dcq_dead_code 0.3.0
dcq_dead_code: ^0.3.0 copied to clipboard
Dead code analysis for Dart packages and mono-repos.
dcq_dead_code #
Dead code analysis for Dart leaf packages and monorepos. Finds unused declarations, nearly-unused symbols, and dependency usage across one or more packages.
Features #
- Dead code detection -- finds public and private declarations with no external references.
- Entry-point reachability -- DFS walk from
main()and@pragma('vm:entry-point')preserves transitively referenced code. - Monorepo support -- analyze multiple packages together so cross-package references are tracked correctly.
- Nearly-unused symbols -- surfaces symbols with very few external references (configurable threshold).
- Dependency usage -- aggregates how many symbols are used from each dependency.
- Smart filtering -- excludes generated files (
.g.dart,.freezed.dart, etc.), test/example directories, and override methods.
Usage #
This package is the analysis library behind the dead-code subcommand in the
dcq CLI. For installation and
CLI usage, see the
dcq_standalone README.
You can also use it directly as a library if you really want:
import 'package:dcq_dead_code/dcq_dead_code.dart';
// Discover packages (returns a record with nullable list + error)
final (packageDirs, error) = discoverPackageDirs(['.']);
if (packageDirs == null) throw Exception(error);
// Find unused declarations
final deadCode = await analyzeDeadCode(packageDirs: packageDirs);
for (final decl in deadCode) {
print('${decl.filePath}:${decl.line} - unused ${decl.kind.name} "${decl.name}"');
}
// Full analysis (dead code + nearly-unused + dependency usage)
final result = await analyzeAll(packageDirs: packageDirs);
formatDeadCodeText(result.deadDeclarations).forEach(print);
formatNearlyUnusedText(result.nearlyUnusedSymbols).forEach(print);
formatDependencyUsageText(result.dependencyUsage).forEach(print);
Leaf packages and accurate results #
The tool determines whether code is "dead" by checking if it is referenced
from outside its defining library within the analyzed set. This means it works
best on leaf packages -- packages with no downstream dependents, such as
applications or CLIs that define main().
If you analyze a library package on its own, its entire public API will appear dead because no consumer is present in the analysis. To get accurate results for library packages, include their known consumers in the same analysis:
dcq dead-code packages/my_lib packages/my_app
# Or also just:
dcq dead-code packages
In a monorepo, pass the repo root or all package directories so that cross-package references are tracked together:
dcq dead-code .
[Dead Code Diagram]
How it works #
- Package discovery -- expands input paths into concrete package
directories by scanning for
pubspec.yamlfiles. - Declaration collection -- walks each resolved
CompilationUnitand records all top-level and member declarations with stable element IDs (<library_uri>:<name>@<offset>). - Reference collection -- tracks which libraries reference each element, including synthetic getters/setters and inferred types.
- Entry-point reachability -- starting from entry points, performs a DFS through the same-library reference graph to mark transitively reachable code as alive.
- Filtering -- removes overrides, generated files, and test/example directories. Public symbols with only internal references are flagged as candidates for privatization rather than removal.