A high-performance Rust-based Dart/Flutter analyzer focused on code quality, conventions, and runtime safety. Built with speed, parallel processing, and memory efficiency in mind for large codebases.
Focus on code conventions, naming, and file organization:
- camel_case_class_names: Ensures class names use CamelCase
- snake_case_file_names: Ensures file names use snake_case
- private_field_underscore: Checks private fields start with underscore
- line_length: Enforces maximum line length (default: 120 characters)
Focus on avoiding runtime errors and unsafe code patterns:
- avoid_dynamic: Detects usage of
dynamictype that bypasses type safety - avoid_empty_catch: Catches empty catch blocks that swallow exceptions
- unused_import: Identifies unused imports
- avoid_print: Warns about print statements in production code
- avoid_null_check_on_nullable: Detects unsafe null assertion operators
- Parallel processing using Rayon for efficient multi-core utilization
- Fast file scanning with optimized Dart file discovery
- Low memory footprint compared to traditional analyzers
- Configurable parallel/sequential execution modes
Built-in Model Context Protocol (MCP) server for programmatic access to analyzer results:
- Query all errors or filter by category, severity, or file
- Get statistics about code issues
- JSON-RPC interface for easy integration
Use dart-re-analyzer as a transparent proxy for the Dart Analysis Server:
- Inject dart-re-analyzer diagnostics directly into your IDE
- Works with VS Code, IntelliJ, Neovim, Emacs, and more
- No IDE configuration changes needed
- Combines dart-re-analyzer rules with Dart Analysis Server's semantic analysis
git clone https://github.com/evaisse/dart-re-analyzer.git
cd dart-re-analyzer
cargo build --releaseThe binary will be available at target/release/dart-re-analyzer
Analyze a Dart/Flutter project:
dart-re-analyzer analyze /path/to/projectAnalyze current directory:
dart-re-analyzer analyze .Run only style rules:
dart-re-analyzer analyze . --style-onlyRun only runtime rules:
dart-re-analyzer analyze . --runtime-onlyGet results as JSON:
dart-re-analyzer analyze . --format jsonHuman-readable output (default):
dart-re-analyzer analyze . --format textGenerate a default configuration file:
dart-re-analyzer init-configThis creates analyzer_config.json with default settings:
{
"enabled": true,
"exclude_patterns": [
".dart_tool/**",
"build/**",
".pub/**",
"packages/**"
],
"style_rules": {
"enabled": true,
"disabled_rules": []
},
"runtime_rules": {
"enabled": true,
"disabled_rules": []
},
"max_line_length": 120,
"parallel": true
}Use a custom configuration:
dart-re-analyzer analyze . --config my_config.jsonStart the MCP server for programmatic access:
dart-re-analyzer serve --port 9000 /path/to/projectUse as a Dart Analysis Server proxy in your IDE:
dart-re-analyzer language-server /path/to/projectThis allows you to get dart-re-analyzer diagnostics directly in your IDE alongside the Dart Analysis Server's diagnostics. See LSP Proxy Guide for IDE-specific setup instructions.
Get all errors:
{"method": "get_all_errors", "params": {}}Get filtered errors:
{
"method": "get_errors",
"params": {
"category": "runtime",
"severity": "error",
"file": "main.dart"
}
}Get statistics:
{"method": "get_stats", "params": {}}Response format:
{
"success": true,
"data": {
"total": 10,
"errors": 1,
"warnings": 7,
"info": 2,
"style_issues": 3,
"runtime_issues": 7,
"files_with_issues": 2
}
}The analyzer now includes full Tree-sitter integration for precise syntax tree analysis:
use dart_re_analyzer::treesitter::{parse_dart, extract_classes, extract_tokens};
// Parse Dart code into a full syntax tree
let tree = parse_dart(source)?;
// Extract all classes with precise locations
let classes = extract_classes(&tree, source);
for class in classes {
println!("Class: {} at bytes [{}..{}]",
class.name, class.start_byte, class.end_byte);
}
// Extract all tokens for detailed analysis
let tokens = extract_tokens(&tree, source);
println!("Total tokens: {}", tokens.len());Features:
- Complete tokenization with line/column positions
- Error-tolerant parsing (works with incomplete code)
- Zero-copy parsing for performance
- Typed wrappers for classes, methods, imports
- Full concrete syntax tree access
See the Tree-sitter Guide for comprehensive documentation.
Run the demo:
cargo run --example treesitter_demoUse declarative pattern matching for complex analysis:
use dart_re_analyzer::treesitter::{parse_dart, query_tree, queries};
let tree = parse_dart(source)?;
// Find all classes
let matches = query_tree(&tree, source, queries::CLASSES)?;
// Find dynamic type usage
let dynamics = query_tree(&tree, source, queries::DYNAMIC_TYPES)?;
// Custom query: find all string literals
let query = r#"(string_literal) @string"#;
let strings = query_tree(&tree, source, query)?;Pre-defined queries:
CLASSES,METHODS,FIELDS,IMPORTSDYNAMIC_TYPES,PRINT_CALLS,EMPTY_CATCHNULL_ASSERTIONS,TYPED_VARIABLES,TYPE_PARAMETERS
Efficiently re-parse code after edits:
use dart_re_analyzer::treesitter::{IncrementalParser, Edit};
let mut parser = IncrementalParser::new()?;
parser.parse("class MyClass {}")?;
// Insert text without full re-parse
let edit = Edit::insert(13, 15, 0, 13);
parser.reparse(edit, "class MyClass extends Object {}")?;Benefits:
- 10-100x faster than full re-parse for small changes
- Perfect for watch mode and IDE integration
- Maintains parse tree state across edits
Foundation for IDE-quality analysis:
use dart_re_analyzer::lsp::{MockSemanticAnalyzer, SemanticAnalyzer};
let analyzer = MockSemanticAnalyzer::new();
// Resolve types
let type_info = analyzer.resolve_type(&file, line, col)?;
// Get diagnostics
let diagnostics = analyzer.get_diagnostics(&file)?;
// Find definitions and references
let definition = analyzer.find_definition(&file, line, col)?;
let references = analyzer.find_references(&file, line, col)?;Capabilities:
- Type resolution and inference
- Null-safety flow analysis
- Cross-file symbol resolution
- IDE-quality diagnostics
See the LSP Integration Guide for details.
Extract rich structural information:
use dart_re_analyzer::treesitter::{
extract_fields, extract_variables, extract_type_annotations,
extract_type_parameters, extract_expressions
};
// Get all fields with modifiers
let fields = extract_fields(&tree, source);
for field in fields {
println!("{}: static={}, final={}, const={}",
field.name, field.is_static, field.is_final, field.is_const);
}
// Get type information
let types = extract_type_annotations(&tree, source);
for ty in types {
println!("Type: {}{}", ty.type_name, if ty.is_nullable { "?" } else { "" });
}Issues found:
/path/to/project/lib/my_file.dart:
β [4:7] style (camel_case_class_names): Class name 'myClass' should use CamelCase (start with uppercase)
π‘ Rename to 'MyClass'
β [15:7] runtime (avoid_empty_catch): Empty catch block swallows exceptions silently
π‘ Handle the exception or at least log it
β [6:3] runtime (avoid_dynamic): Avoid using 'dynamic' type as it bypasses type safety
π‘ Use a specific type or Object? instead
Summary:
1 errors, 2 warnings, 0 info messages
List of glob patterns to exclude from analysis:
"exclude_patterns": [
".dart_tool/**",
"build/**",
"test/**/*.g.dart"
]"style_rules": {
"enabled": true,
"disabled_rules": ["line_length"]
},
"runtime_rules": {
"enabled": true,
"disabled_rules": ["avoid_print"]
}"max_line_length": 100"parallel": truecargo buildcargo testTest dart-re-analyzer on a real Dart project:
./test_analyzer.shThis script runs the analyzer on test_project/ which contains Dart code samples designed to test all analyzer rules and features.
RUST_LOG=debug cargo run -- analyze .This project is configured to work with GitHub Copilot and includes MCP (Model Context Protocol) server configurations for enhanced AI assistance.
Configured Language Servers:
- rust-analyzer: Provides Rust language intelligence
- dart-analyzer: Provides Dart language support for understanding patterns
Setup:
- Open this project in VS Code
- Install recommended extensions (GitHub Copilot, rust-analyzer, etc.)
- The MCP servers will automatically enhance Copilot's understanding of the codebase
See .github/copilot/README.md for detailed configuration information.
The analyzer is structured into several modules:
- parser: Dart file discovery and loading
- analyzer: Rule trait and analysis coordination
- rules: Style and runtime rule implementations
- config: Configuration management
- mcp: Model Context Protocol server
- treesitter: Tree-sitter parsing and queries
- lsp: Language Server Protocol integration
- error: Error types and diagnostic structures
The analyzer includes multiple complementary analysis approaches:
- Full concrete syntax tree with complete tokenization
- Error-tolerant parsing that works with incomplete code
- Declarative queries for pattern matching
- Incremental parsing for efficient re-analysis
- Typed wrappers for classes, methods, fields, variables, types, expressions
- See Tree-sitter Guide for detailed usage
- Type resolution and inference interface
- Symbol information structures
- Semantic diagnostics with fixes
- Cross-file navigation support
- See LSP Integration Guide for detailed usage
- Fast and lightweight for simple pattern detection
- Easy to add new rules without complex parsing
- Good for straightforward checks like naming conventions
- Lower memory overhead compared to full parsing
Hybrid Strategy: Use the right tool for each job - Tree-sitter for structure, LSP for semantics, regex for simple patterns.
β Tree-sitter Queries - Declarative pattern language for maintainable rules β Incremental Parsing - Fast re-parse on edits for watch mode β Extended Typed Wrappers - Fields, variables, expressions, type annotations, generics β LSP Foundation - Architecture for semantic analysis integration
Potential improvements for future versions:
- β
Integrate AST parsing using tree-sitterDONE! - β
Incremental parsing APIDONE! - β
Tree-sitter queriesDONE! - β
More typed wrappersDONE! - π§ Full Dart Analysis Server LSP integration (process management, JSON-RPC)
- π Watch mode for continuous analysis using incremental parsing
- π Rule implementations using tree-sitter queries
The analyzer is designed for large codebases:
- Uses parallel processing via Rayon
- Efficient regex-based pattern matching
- Minimal memory allocations
- Fast file system traversal
For a typical Flutter project with 1000+ files, expect:
- Analysis time: < 2 seconds
- Memory usage: < 100MB
- Scales linearly with project size
Contributions are welcome! Areas for improvement:
- Additional style rules
- More runtime safety checks
- AST-based analysis (replacing regex patterns)
- IDE integrations
- Watch mode for continuous analysis
MIT
Emmanuel Vaisse