14 - Sonar Static Analysis (Flutter)
Run Sonar-style static analysis on the Flutter app, export it as SARIF, and generate a browsable HTML report. Everything runs locally — no SonarQube server required.
Dart has no official "SonarDart" plugin, so we use very_good_analysis (a Sonar-style strict rule set layered on top of flutter_lints) executed by the regular flutter analyze tool. The text output is then converted to a SARIF v2.1 file so the same sarif-tools HTML pipeline as the backend works here too.
How it is wired
pubspec.yaml— addsvery_good_analysisas a dev dependency.analysis_options.yaml— includespackage:very_good_analysis/analysis_options.yaml, excludes build / generated files, and tones down two overly noisy rules (public_member_api_docs,lines_longer_than_80_chars).scripts/to_sarif.js— Node script that parsesflutter analyzestdout (severity, message, file:line:col, rule name) and writes a SARIF v2.1 file.scripts/aggregate_sonar.js— rule-grouped summary + noisy-file ranking from the--write=output.scripts/fix_*.js— targeted auto-fixers forunawaited_futures,inference_failure_*, andwithOpacitydeprecation.
flutter_app/pubspec.yamlYAML
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.1
# Sonar-style strict lint ruleset for Dart/Flutter
very_good_analysis: ^6.0.0
flutter_app/analysis_options.yamlYAML
include: package:very_good_analysis/analysis_options.yaml
analyzer:
exclude:
- build/**
- "**/*.g.dart"
- "**/*.freezed.dart"
- "**/*.mocks.dart"
errors:
public_member_api_docs: ignore
lines_longer_than_80_chars: ignore
linter:
rules:
avoid_print: true
prefer_single_quotes: true
Prerequisites (one-time)
- Flutter SDK 3.2+ — same as building the app
- Node.js 18+ — runs the
scripts/helpers - Python 3.8+ with
sarif-tools— produces the HTML report
BashInstall sarif-tools (once per machine)
pip install sarif-tools
sarif --version
Step 1 — Run the analyzer
Run flutter analyze twice and capture both outputs. The --write= form gives a stable text file; the default stdout form includes rule names which we need for the SARIF conversion.
BashRefresh the raw analyzer output
cd flutter_app
# Make sure packages are resolved
flutter pub get
# Stdout form (contains rule names) — feeds the SARIF converter
flutter analyze > sonar-report/dart-analyze-stdout.txt
# --write form — feeds aggregate_sonar.js
flutter analyze --write=sonar-report/dart-analyze.txt
Step 2 — Convert to SARIF + aggregate
BashProduce SARIF and text summaries
cd flutter_app
# stdout → SARIF v2.1
node scripts/to_sarif.js
# --write output → rule-grouped summary, noisy files, issues.json
node scripts/aggregate_sonar.js
Step 3 — Generate the HTML report
BashGenerate and open
cd flutter_app
sarif html sonar-report/flutter-analyze.sarif -o sonar-report/flutter-sonar.html
start sonar-report/flutter-sonar.html # Windows
All reports are under flutter_app/sonar-report/:
flutter-sonar.html— browsable HTML dashboardflutter-analyze.sarif— SARIF v2.1 file (input to sarif-tools)dart-analyze-stdout.txt,dart-analyze.txt— raw Flutter outputssummary.txt,issues.json— text + JSON reports
Full run in one copy-paste
BashEnd-to-end (from flutter_app/)
cd flutter_app
flutter pub get
flutter analyze > sonar-report/dart-analyze-stdout.txt
flutter analyze --write=sonar-report/dart-analyze.txt
node scripts/to_sarif.js
node scripts/aggregate_sonar.js
sarif html sonar-report/flutter-analyze.sarif -o sonar-report/flutter-sonar.html
start sonar-report/flutter-sonar.html
Severity mapping
Dart/Flutter lints come with three severities: error, warning, info. We map them to Sonar-style categories as follows for our fix policy:
- Blocker — anything at
errorseverity, plususe_build_context_synchronously(causes crashes when a widget unmounts across an async gap). - Critical —
unawaited_futures(fire-and-forget swallowing errors),inference_failure_on_instance_creation/_on_function_invocation(lost type safety onFuture.delayed,showDialog,showModalBottomSheet). - High —
deprecated_member_use(e.g.withOpacity,ColorScheme.background),avoid_void_async,unnecessary_null_checks,unused_field. - Medium / Low — style rules:
require_trailing_commas,always_use_package_imports,prefer_const_constructors,sort_constructors_first,directives_ordering, etc. Skipped by default; fix opportunistically withdart format+dart fix --apply.
Ready-made fixers
Each script is self-documenting at the top. Dart also ships dart fix which auto-applies many rules — we use it for the bulk of the Medium/Low cleanup.
flutter_app/scripts/Available fixers
to_sarif.js # flutter analyze stdout → SARIF v2.1
aggregate_sonar.js # Rule-grouped summary from --write output
fix_unawaited.js # Wrap fire-and-forget Futures with unawaited(...)
fix_inference.js # Add <void> to Future.delayed / showDialog / showModalBottomSheet
fix_with_opacity.js # .withOpacity(x) → .withValues(alpha: x)
BashBuilt-in dart fix shortcuts
cd flutter_app
# Preview all auto-fixable rules
dart fix --dry-run
# Apply a specific rule only (used during the April 2026 cleanup)
dart fix --apply --code=avoid_void_async
dart fix --apply --code=unnecessary_null_checks
# Apply everything — big diff, review before committing
dart fix --apply
The fix_unawaited.js script uses column offsets from the analyzer report plus bracket-matching. Running it twice without regenerating the report first can silently corrupt files (we hit this once — an unawaited( was inserted inside a comment). Always re-run flutter analyze --write=... before re-running any fixer.
Editor integration
Android Studio / VS Code / IntelliJ pick up analysis_options.yaml automatically and show the same squiggles live while you type. The SARIF conversion and HTML report only matter for CI or for sharing a snapshot with a reviewer.
Typical report after a clean pass
After the April 2026 Blocker + Critical + High cleanup:
- 0 errors
- 0 warnings
- ~600
info-level style hits remaining (mostlyrequire_trailing_commas,always_use_package_imports,prefer_const_constructors) — intentionally left for a future style sweep.
See also
- Backend Sonar Analysis — same workflow for the .NET backend
- Dart linter rules catalog
- very_good_analysis on pub.dev
- sarif-tools on GitHub