Smell Detection for VS Code
Detects code smells in the Java project open in VS Code, using Designite (implementation and design smells, from source code) or Arcan (architectural smells, from compiled classes). Both tools ship inside the extension. Results appear in a sidebar and in the Problems panel, and every smell links to the exact declaration it was reported on.
Using it
- Open a Java project folder.
- Click the Smell Detection icon in the Activity Bar (
</> with rising lines).
- Pick Designite or Arcan and click Detect Smells.
- Browse the results by category and smell type, or search by package, class, method or detail. Click a smell to open its declaration.
You can also run the commands Smell Detection: Detect Smells with Designite / Arcan from the Command Palette.
Java: the tools need Java 17 or newer. If none is found, the extension offers to download a private Eclipse Temurin 17 runtime (a 35–45 MB download) into VS Code's extension storage. Nothing is installed system-wide. You can also point smellDetection.javaPath at an existing Java.
Arcan needs compiled classes. Build the project first (mvn compile, gradle classes, or an IDE build). The extension finds every module's build output automatically.
| Tool |
Input |
Smells |
| Designite (DesigniteJava, open-source edition) |
Java source |
Implementation: Abstract Function Call From Constructor, Complex Conditional, Complex Method, Empty catch clause, Long Identifier, Long Method, Long Parameter List, Long Statement, Magic Number, Missing default. Design: Broken Hierarchy, Broken Modularization, Cyclic Hierarchy, Cyclic-Dependent Modularization, Deep Hierarchy, Deficient Encapsulation, Hub-like Modularization, Imperative Abstraction, Insufficient Modularization, Missing Hierarchy, Multifaceted Abstraction, Multipath Hierarchy, Rebellious Hierarchy, Unexploited Encapsulation, Unnecessary Abstraction, Unutilized Abstraction, Wide Hierarchy. Also type and method metrics. |
| Arcan 1.2.1 |
Compiled .class files |
Architecture: Cyclic Dependency (between classes and between packages), Hub-Like Dependency, Unstable Dependency. Also class and package metrics (fan-in/out, CBO, LCOM, Martin's instability/abstractness/distance). |
How the extension reads Arcan's reports (taken from Arcan's source):
- Cyclic Dependency: each row of
classCyclicDependencyTable.csv / packageCyclicDependencyTable.csv is one cycle, and the sidebar lists its members. The shape tables and matrices describe the same cycles in other forms, so they are not counted again.
- Unstable Dependency: one smell per package in
UD.csv, listing the less stable packages it depends on. If the package also passes Arcan's stricter 30% filter (UD30.csv), the detail says so.
- Hub-Like Dependency: one smell per row of
HL.csv.
- Arcan builds its dependency graph from method and constructor calls, class literals,
instanceof, inheritance and annotations in the bytecode. Reading or writing another class's fields, or only declaring a variable of its type, does not count as a dependency in Arcan's model.
Accuracy
The extension reports exactly what the tools report. It adds no smells, drops none, and does not reinterpret them. To make the tools themselves correct on real projects, the extension:
- Analyzes production code only by default, with both tools. Test folders (
src/test, test, tests, …) and build output are excluded, so the two tools look at the same code and generated or duplicate copies are not counted. Set smellDetection.includeTests to include tests.
- Gives Designite a proper source root. Designite resolves references between classes through the folder it is given, so pointing it at a repository root silently drops hierarchy, abstraction and dependency-based design smells. The extension stages the sources by package, so resolution works for any layout, including multi-module builds.
- Gives Arcan every module's compiled classes in one folder, without
module-info.class and multi-release (META-INF/versions) entries.
- Treats "no reports" as a failure. Arcan exits successfully even when it crashes, so the extension checks that reports were written and surfaces the tool's error.
The bundled tools are built from source with fixes for bugs that affected accuracy. Details and diffs are in THIRD_PARTY_NOTICES.md:
- DesigniteJava counted every method and field of a nested class twice, once on the nested class and once on its enclosing class. On Commons Lang this added 60 duplicate implementation smells (6%), and on JUnit 4 it added 13 (12%).
- DesigniteJava reports only method names, so a smell on an overloaded method (49% of Commons Lang's method smells) could not be traced to the right overload. The bundled build also writes each smell's file and declaration line, taken from its parser.
- DesigniteJava parsed everything as Java 8 with an old parser. Modern syntax was misread (records counted as methods,
switch expressions ignored in complexity), and every method or class containing a switch was measured as 0 lines, which hid Long Method smells and produced false Rebellious Hierarchy smells. It now uses Eclipse JDT 3.40 with the latest Java grammar.
- DesigniteJava read files in the platform's default charset, so results depended on the user's OS. It now reads UTF-8, and the extension converts non-UTF-8 sources (
smellDetection.sourceEncoding).
- Arcan's bytecode library could not read Java 8+ class files, so Arcan crashed with no output on most modern projects. It was upgraded, and the results on Java 7 code were confirmed identical.
Verification on real systems. npm run verify-accuracy runs the extension inside VS Code on Apache Commons Lang 3.14.0, JUnit 4.13.2 and Google Guava 33.3.1 (core module, 181k lines). An independent checker (scripts/verify_accuracy.py, which shares no code with the extension) then:
- re-reads the raw CSV reports and requires every smell to appear exactly once, at the file and line the tool reported;
- recounts the analyzed sources and classes;
- opens every location and checks that it declares the reported package, type or method;
- runs each tool directly on the project's source root or class folder and requires identical results.
| Project |
Tool |
Smells |
Matches tool output |
Locations verified |
Time |
| Commons Lang 3.14.0 |
Designite |
1,222 |
✓ |
1,222 / 1,222 |
6 s |
| Commons Lang 3.14.0 |
Arcan |
105 |
✓ |
105 / 105 |
2 s |
| JUnit 4.13.2 |
Designite |
294 |
✓ |
294 / 294 |
3 s |
| JUnit 4.13.2 |
Arcan |
128 |
✓ |
128 / 128 |
1 s |
| Guava 33.3.1 (core) |
Designite |
3,453 |
✓ |
3,453 / 3,453 |
25 s |
| Guava 33.3.1 (core) |
Arcan |
984 |
✓ |
984 / 984 |
10 s |
npm test also runs the extension on projects shaped like real ones: Gradle and multi-module Maven builds, the default package, folders that don't match packages, Java 17 syntax, Latin-1 sources, paths with spaces and commas, projects with no Java, duplicate classes, cancellation, and the security and safety rules below.
Known limits
- Both tools analyze Java only.
- DesigniteJava (open-source edition) models classes and interfaces. Enums and records are not analyzed as types of their own; methods of a nested enum or record count toward the enclosing class.
- Designite reports implementation smells per method, not per occurrence. When a method has, say, four magic numbers, the sidebar shows the method once with
×4.
- Arcan smells are located on the first class or package of a cycle, and on the hub class or unstable package otherwise. All members are listed in the detail.
- These are the open-source editions: DesigniteJava (not Designite Enterprise) and Arcan 1.2.1 (not the current commercial Arcan). To use another version, set
smellDetection.<tool>.path and adjust smellDetection.<tool>.args. The extension reads any CSV reports, but only these two formats have dedicated readers.
Security and safety
- Settings that decide what gets executed (
javaPath, javaArgs, useBundledTools, <tool>.path, <tool>.args) are honored only in your user settings. A project's .vscode/settings.json cannot change them.
- In VS Code's Restricted Mode (untrusted folders), the extension still works, but the workspace cannot change which folders are analyzed or where reports go.
- The tools only read source and class files; they never run the project's code.
- The extension only deletes folders it created itself (marked with
.smell-detection-owned), so a mistaken outputDirectory cannot remove your files.
Settings
| Setting |
Default |
Purpose |
smellDetection.defaultTool |
designite |
Tool selected when the sidebar opens |
smellDetection.includeTests |
false |
Also analyze test code |
smellDetection.problems.severity |
Warning |
How smells appear in the Problems panel (Off hides them) |
smellDetection.javaPath |
java |
Java 17+ executable. java means: bundled/downloaded runtime, then JAVA_HOME, then PATH |
smellDetection.javaArgs |
[] |
JVM options, e.g. ["-Xmx4g"] for very large projects |
smellDetection.outputDirectory |
(extension storage) |
Where raw reports are written |
smellDetection.useBundledTools |
true |
Use the bundled tools when no path is set |
smellDetection.<tool>.path |
|
Use a different jar or executable |
smellDetection.<tool>.inputPath |
|
Analyze only this folder (Designite: sources; Arcan: .class files) |
smellDetection.<tool>.args |
|
Command-line arguments (${input}, ${output}, ${workspaceFolder}, ${projectName}) |
The raw reports of the last run are linked from the sidebar ("reports"), and the full tool output is in Output → Smell Detection.
Development
npm install
npm run build-tools # builds the bundled Designite and Arcan into tools/ (needs git; downloads a JDK and Maven into tools/ if needed)
npm run compile
npm test # end-to-end tests in VS Code (24 tests)
npm run verify-accuracy # real-system accuracy check (needs tools/benchmarks)
npm run package # build the .vsix
Press F5 to start an Extension Development Host on demo-project/. tools/ is not in git: npm run build-tools recreates the bundled tools from their pinned upstream sources plus patches/. PUBLISHING.md explains how to release the extension.
| |