Skip to content

beobeodev/fscan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Go 1.21+ Flutter SARIF 2.1.0 License npm

fscan

A blazing-fast dead code scanner for Flutter & Dart projects

Find unused files, classes, functions, widgets, and assets in your Flutter project.
Zero configuration. No Dart SDK required. CI-ready.


Why fscan?

Flutter projects accumulate dead code over time β€” orphaned screens, unused utility classes, forgotten assets eating up your bundle size. Manual cleanup is tedious and error-prone.

fscan statically analyzes your entire Flutter project in seconds and reports exactly what's unused, with zero false positives on private symbols and smart heuristics for public APIs.

fscan Manual Review dart analyze
Unused files Yes Painful No
Unused assets Yes Very painful No
Unused private symbols Yes Impossible at scale Partial
Unused public APIs Yes (warnings) Impossible at scale No
Unused widgets Yes Manual No
Unused routes (auto_route/go_router/Navigator) Yes Manual No
flutter_gen support Yes N/A N/A
Speed (500+ files) ~2 seconds Hours Minutes
Requires Dart SDK No N/A Yes

Quick Start

# Homebrew (macOS/Linux)
brew install beobeodev/tap/fscan

# npm (any platform with Node.js)
npm install -g @beobeodev/fscan

# Go
go install github.com/beobeodev/fscan@latest

# Scan your Flutter project
fscan scan ./my_flutter_app

# That's it. No config files, no setup.

Sample Output

fscan results for: ./my_flutter_app
────────────────────────────────────────────────────────────

UNUSED FILE (4)
  lib/unused_public_function.dart
  lib/unused_widget.dart
  lib/unused_file.dart
  lib/unused_public_class.dart

UNUSED PRIVATE CLASS (1)
  lib/unused_file.dart:9  Private class "_UnusedPrivateHelper" is never referenced

UNUSED ASSET (1)
  assets/images/unused_icon.png

MAYBE UNUSED PUBLIC API (4)
  lib/unused_public_class.dart:4  Public class "UnusedPublicClass" has no references
  lib/unused_public_function.dart:4  Public function "formatCurrency" has no references

MAYBE UNUSED WIDGET (1)
  lib/unused_widget.dart:6  Widget "UnusedWidget" has no direct instantiation

────────────────────────────────────────────────────────────
Total: 11 issues (6 errors, 5 warnings)

What It Detects

Errors (High Confidence)

Rule Description
unused-file Dart files in lib/ not reachable from any entry point
unused-asset Assets declared in pubspec.yaml but never referenced in code
unused-private-class Private classes (_Foo) with zero references anywhere
unused-private-function Private functions (_foo) with zero references anywhere

Warnings (May Be Intentional)

Rule Description
maybe-unused-public-api Public classes and functions with no references in the project
maybe-unused-widget Widget subclasses never instantiated or route-registered
maybe-unused-method Public methods with no cross-file or same-file callers (owner-class-aware)
unused-route Routes declared in auto_route / go_router / Navigator but never navigated to

Warnings are for symbols that could be part of a public API or used via dynamic routing. Review them β€” don't blindly delete.


Features

Dual Scan Engine

                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚         fscan CLI              β”‚
                  └──────────┬──────────────────────-β”˜
                             β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β–Ό                             β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚  Go Deep Scanner    β”‚     β”‚  Dart Semantic Worker   β”‚
   β”‚  (always runs)      β”‚     β”‚  (optional, higher      β”‚
   β”‚                     β”‚     β”‚   accuracy)             β”‚
   β”‚  β€’ Regex-based      β”‚     β”‚  β€’ package:analyzer     β”‚
   β”‚  β€’ No dependencies  β”‚     β”‚  β€’ Full AST resolution  β”‚
   β”‚  β€’ ~2s for 500 filesβ”‚     β”‚  β€’ Requires Dart SDK    β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”‚                             β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚  MergeSymbols       β”‚
              β”‚  (Dart overrides Go β”‚
              β”‚   when available)   β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Go deep scanner runs by default with zero external dependencies. It extracts symbol declarations via regex and performs concurrent cross-file reference counting.
  • Dart semantic worker (opt-in) uses package:analyzer for full AST resolution, constructor tracking, and class hierarchy analysis. When available, its results override the Go scanner for higher accuracy.

Smart Detection

  • App mode vs Library mode β€” auto-detected based on main.dart presence
    • App mode: BFS reachability from entry points
    • Library mode: orphan detection (files not imported by anything)
  • Framework-aware β€” skips lifecycle methods (build, createState, dispose, initState, ...), @override annotations, and _FooState classes paired with StatefulWidget
  • Generated file handling β€” detects .g.dart, .gen.dart, .freezed.dart, .gr.dart, .chopper.dart and more. Generated files are excluded from unused-file detection but included as reference sources.
  • flutter_gen support β€” understands typed asset accessors (BookAssets.icons.arrowLeft.svg()) for accurate asset usage detection
  • Inline suppression β€” skip files with // fscan:ignore-file or lines with // fscan:ignore

CI/CD Integration

  • Exit code 1 when issues are found β€” use as a CI quality gate
  • SARIF output for GitHub Code Scanning integration
  • JSON output for custom tooling and dashboards

Usage

fscan scan [project-path] [flags]

Flags

Flag Short Default Description
--entry -e lib/main.dart Entry point files for reachability analysis
--format -f text Output format: text, json, sarif
--output -o stdout Write report to file
--rules -r all Comma-separated list of rules to enable
--verbose -v false Print scan statistics to stderr
--skip-dart false Skip Dart semantic worker
--strict-assets false Require field-level references for generated assets
--dart-worker auto Path to dart_worker/bin/worker.dart

Examples

# Scan with verbose output
fscan scan ./my_app -v

# Output JSON for CI parsing
fscan scan ./my_app -f json -o report.json

# SARIF for GitHub Code Scanning
fscan scan ./my_app -f sarif -o results.sarif

# Only check for unused files and assets
fscan scan ./my_app -r unused-file,unused-asset

# Scan a library package (auto-detects, no main.dart needed)
fscan scan ./my_library_package

# Strict asset checking (detects flutter_gen accessor usage)
fscan scan ./my_app --strict-assets

# Multiple entry points
fscan scan ./my_app -e lib/main.dart -e lib/admin.dart

# With Dart semantic analysis (requires Dart SDK)
fscan scan ./my_app --dart-worker dart_worker/bin/worker.dart

GitHub Actions

name: Dead Code Check

on: [pull_request]

jobs:
  fscan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version: '1.21'

      - name: Install fscan
        run: go install github.com/beobeodev/fscan@latest

      - name: Scan for dead code
        run: fscan scan . -f sarif -o results.sarif

      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: results.sarif

Output Formats

Text (default)

Human-readable, grouped by rule with issue counts and a summary line. Best for local development.

JSON

{
  "project": "./my_flutter_app",
  "scanned_at": "2026-04-16T08:00:00Z",
  "total": 11,
  "issues": [
    {
      "rule": "unused-file",
      "file": "lib/unused_file.dart",
      "line": 0,
      "message": "lib/unused_file.dart is not reachable from any entry point",
      "severity": "error"
    }
  ]
}

SARIF 2.1.0

Full SARIF compliance for integration with GitHub Code Scanning, VS Code SARIF Viewer, and other static analysis tools.


Strict Assets Mode

By default, fscan considers an asset "used" if its generated file (e.g., assets.gen.dart) is imported anywhere in the project. This is fast but permissive.

With --strict-assets, fscan performs field-level reference scanning:

// assets.gen.dart (generated by flutter_gen)
class $AssetsIconsGen {
  SvgGenImage get arrowLeft => const SvgGenImage('assets/icons/arrow_left.svg');
  SvgGenImage get unusedIcon => const SvgGenImage('assets/icons/unused_icon.svg');
}

// user_code.dart
BookAssets.icons.arrowLeft.svg()  // arrowLeft is used
// unusedIcon is never referenced β†’ flagged

fscan parses the flutter_gen class hierarchy to build category.fieldName patterns (e.g., icons.arrowLeft) and searches user code with word-boundary checking to eliminate false positives from common names like .add, .close, .active.


Suppression

Skip entire files or specific lines:

// fscan:ignore-file
// Place in the first 10 lines to skip the entire file

import 'package:legacy/old_api.dart'; // fscan:ignore

Architecture

fscan/
β”œβ”€β”€ cmd/                          # CLI commands (Cobra)
β”‚   β”œβ”€β”€ root.go                   # Root command, rule descriptions
β”‚   └── scan.go                   # Scan pipeline orchestration
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ config/                   # ScanConfig, entry point detection
β”‚   β”œβ”€β”€ graph/                    # Thread-safe directed graph (file β†’ file, file β†’ asset)
β”‚   β”œβ”€β”€ walker/                   # Concurrent file walker, import/export/part parser
β”‚   β”œβ”€β”€ scanner/                  # Symbol extraction, cross-file reference counting
β”‚   β”œβ”€β”€ asset/                    # pubspec.yaml parsing, asset scanning, flutter_gen mapping
β”‚   β”œβ”€β”€ dart/                     # Optional Dart semantic worker (subprocess protocol)
β”‚   β”œβ”€β”€ rules/                    # Rule engine + 8 detection rules
β”‚   └── report/                   # Text, JSON, SARIF reporters
β”œβ”€β”€ dart_worker/                  # Dart subprocess (package:analyzer)
β”œβ”€β”€ testdata/sample_app/          # Integration test fixtures
β”œβ”€β”€ Makefile                      # Build, test, lint, run targets
└── main.go                       # Entry point

Scan Pipeline

  Parse CLI flags
       β”‚
       β–Ό
  Detect entry points (app vs library mode)
       β”‚
       β–Ό
  Build import graph (concurrent file walk)
       β”‚
       β–Ό
  Scan assets (pubspec.yaml + string refs + flutter_gen)
       β”‚
       β–Ό
  Deep scan symbols (Go regex, concurrent)
       β”‚
       β–Ό
  Dart semantic analysis (optional, overrides deep scan)
       β”‚
       β–Ό
  Apply rules β†’ issues
       β”‚
       β–Ό
  Report (text / json / sarif)
       β”‚
       β–Ό
  Exit code 0 (clean) or 1 (issues found)

Building from Source

git clone https://github.com/beobeodev/fscan.git
cd fscan
make build          # β†’ ./build/fscan
make test           # Run all tests
make install        # Copy to $GOPATH/bin

With Dart Semantic Worker

make dart-setup     # Install Dart dependencies
make run-sample-full  # Run with both scanners

Requires Dart SDK 3.0+.


Tested At Scale

fscan has been validated against real-world Flutter projects:

Project Files Issues Found Scan Time
App (774 files) 774 Dart files 164 issues ~3s
Library (409 files) 409 Dart files 69 issues ~2s
Library + strict assets 409 Dart files 139 issues ~3s

Contributing

Contributions are welcome! Please open an issue or submit a PR.

# Run tests
make test

# Run linter
make lint

# Test against sample project
make run-sample

License

MIT


Built with Go. Made for Flutter developers who care about clean codebases.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages