Skip to main content

Shared Inspection Engine

Overview​

All JetBrains IDEs share a common inspection engine built on the IntelliJ Platform. This unified architecture ensures consistent code analysis across different IDEs and languages.

Core Architecture​

IntelliJ Platform Foundation​

The inspection engine is part of the IntelliJ Platform, which provides:

┌─────────────────────────────────────────┐
│ IntelliJ Platform Core │
├─────────────────────────────────────────┤
│ PSI (Program Structure Interface) │
│ - Language-agnostic AST representation │
│ - Unified code model │
├─────────────────────────────────────────┤
│ Inspection Infrastructure │
│ - LocalInspectionTool base class │
│ - GlobalInspectionTool base class │
│ - InspectionProfileManager │
├─────────────────────────────────────────┤
│ Language-Specific Plugins │
│ - Java, TypeScript, Python, etc. │
│ - Custom inspections per language │
└─────────────────────────────────────────┘

Inspection Types​

Local Inspections​

  • Analyze single files independently
  • Fast, run in real-time as you type
  • Examples: unused variables, syntax errors

Global Inspections​

  • Analyze entire project context
  • Slower, typically run on-demand
  • Examples: duplicate code, cyclic dependencies

Execution Pipeline​

Based on our implementation in InspectionExecutor.ts:

1. Project Loading​

// From ProjectAnalyzer.ts
async analyzeProject(projectPath: string): Promise<ProjectInfo> {
const ideaDir = path.join(projectPath, '.idea');
// Load project configuration
// Detect project type and structure
}

2. Profile Resolution​

// From InspectionProfileManager.ts
async resolveProfile(options: ProfileOptions): Promise<string> {
// Check for forced profile path
if (options.forcedPath) return options.forcedPath;

// Look for project-specific profiles
const projectProfile = await this.findProjectProfile();
if (projectProfile) return projectProfile;

// Fall back to unified profile
return this.getUnifiedProfile();
}

3. Inspection Execution​

// From InspectionStrategy.ts
buildCommand(params: InspectionParams): string[] {
return [
inspectPath,
projectRoot,
profilePath,
outputPath,
'-format', 'json',
'-d', targetPath
];
}

4. Result Processing​

// From InspectionResultProcessor.ts
async process(rawOutput: string): Promise<InspectionResult> {
const parsed = await this.parser.parse(rawOutput);
const normalized = this.normalizer.normalize(parsed);
const filtered = this.filter.apply(normalized);
return this.formatter.format(filtered);
}

Language Support​

How Multi-Language Support Works​

Each JetBrains IDE includes:

  1. Core Platform: Shared inspection engine
  2. Language Plugins: Language-specific analyzers
  3. Unified Interface: Common inspect.sh command

Language Detection​

From our IDEDetector.ts:

// IDE capabilities are determined by installed plugins
const ideCapabilities = {
'IntelliJ IDEA': ['java', 'kotlin', 'scala', 'groovy'],
WebStorm: ['javascript', 'typescript', 'html', 'css'],
PyCharm: ['python', 'django', 'flask'],
PhpStorm: ['php', 'html', 'javascript'],
GoLand: ['go'],
RubyMine: ['ruby', 'rails'],
CLion: ['c', 'cpp', 'cmake'],
Rider: ['csharp', 'fsharp', 'vb'],
};

Inspection Registration​

How Inspections Are Registered​

Each inspection is registered via plugin.xml:

<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<localInspection
language="TypeScript"
displayName="Unused local symbols"
groupName="TypeScript"
enabledByDefault="true"
level="WARNING"
implementationClass="com.intellij.lang.javascript.inspections.JSUnusedLocalSymbolsInspection"/>
</extensions>
</idea-plugin>

Inspection Metadata​

Each inspection contains:

  • ID: Unique identifier (e.g., JSUnusedLocalSymbols)
  • Display Name: Human-readable name
  • Group: Category for organization
  • Default Severity: ERROR, WARNING, WEAK WARNING, INFO
  • Language: Target language(s)

Result Format​

Unified JSON Output​

All IDEs produce the same JSON format:

{
"problems": [
{
"file": "src/example.ts",
"line": 10,
"column": 5,
"severity": "WARNING",
"description": "Variable 'unused' is never used",
"inspectionId": "JSUnusedLocalSymbols",
"category": "Declaration redundancy"
}
]
}

Severity Mapping​

From SeverityMapper.ts:

export class SeverityMapper {
private readonly severityMap = {
ERROR: DiagnosticSeverity.Error,
WARNING: DiagnosticSeverity.Warning,
'WEAK WARNING': DiagnosticSeverity.Information,
INFO: DiagnosticSeverity.Hint,
INFORMATION: DiagnosticSeverity.Hint,
'SERVER PROBLEM': DiagnosticSeverity.Error,
TYPO: DiagnosticSeverity.Information,
};
}

Performance Optimizations​

Caching Mechanisms​

  1. Index Caching: PSI trees are cached for performance
  2. Inspection Results: Can be cached between runs
  3. Profile Caching: Profiles loaded once per session

Parallel Processing​

The inspection engine can:

  • Run multiple inspections in parallel
  • Process multiple files simultaneously
  • Use worker threads for CPU-intensive analysis

Command-Line Interface​

The inspect.sh Script​

All IDEs provide the same CLI interface:

#!/bin/sh
# Simplified representation of inspect.sh

IDE_HOME="$(dirname "$0")/.."
IDEA_PROPERTIES="${IDE_HOME}/bin/idea.properties"

# Set isolated configuration to avoid conflicts
IDEA_CONFIG_PATH="${TMPDIR}/idea-config-$$"
IDEA_SYSTEM_PATH="${TMPDIR}/idea-system-$$"

exec java \
-Didea.config.path="${IDEA_CONFIG_PATH}" \
-Didea.system.path="${IDEA_SYSTEM_PATH}" \
-classpath "${IDE_HOME}/lib/*" \
com.intellij.codeInspection.InspectionMain \
"$@"

Why Results Are Consistent​

  1. Same Core Engine: All IDEs use IntelliJ Platform
  2. Shared Inspections: Common inspections across IDEs
  3. Unified Profiles: Profile format is standardized
  4. Common Output: JSON format is identical

Integration Points​

How Our MCP Server Integrates​

  1. IDE Detection: Find available IDEs
  2. Project Analysis: Read .idea configuration
  3. Profile Management: Handle inspection profiles
  4. Execution: Run inspect.sh subprocess
  5. Result Processing: Parse and normalize output

Key Integration Classes​

  • IDEDetector: Finds installed IDEs
  • IDESelector: Chooses best IDE for the task
  • InspectionExecutor: Manages inspection process
  • ResultParser: Processes inspection output
  • DiagnosticNormalizer: Standardizes results

Best Practices​

For Consistent Results​

  1. Use Unified Profiles: Ensure profiles work across IDEs
  2. Specify Timeouts: Set appropriate timeouts for large projects
  3. Filter Appropriately: Use include/exclude filters
  4. Handle Errors Gracefully: Implement proper error handling

For Performance​

  1. Scope Inspections: Inspect only necessary files
  2. Use Local Inspections: When project context isn't needed
  3. Cache Results: When analyzing same code repeatedly
  4. Parallelize: Run independent inspections concurrently

Troubleshooting​

Common Issues​

  1. Different Results Between IDEs

    • Check language plugin versions
    • Verify profile compatibility
    • Ensure same project configuration
  2. Performance Problems

    • Increase timeout values
    • Reduce inspection scope
    • Use faster local inspections
  3. Missing Inspections

    • Verify IDE has required plugins
    • Check inspection is enabled in profile
    • Ensure language support is installed

References​