v0.7.0Dart 3.10+Apache-2.0
Dead code detector for Dart and Flutter.
Finds declarations nothing references and removes them for you. One command, no setup, backed by the Dart analysis server.
“Ciach!” /tɕax/ — Polish for the sound of a clean chop.
dart install ciach
$ ciach
lib/greeting.dart
15:6 function danglingFunction (public)
24:7 variable unusedConstant (public)
lib/orphans.dart
8:7 class UnusedClass (public)
22:7 class FullyDeadClass (public)
31:3 constructor ReferencedAsTypeOnly.new (public)
Found 5 unused declarations in 2 files (scanned 13 files, 44 declarations, 0.5s)
--remove
Report it. Or ciach it.
One flag deletes what was found, doc comments included, after showing the list and asking first.
/// Referenced from bin/app.dart.
void registerHandlers() {
_internalHelper();
}
void _internalHelper() {}
/// Nothing calls this any more.
void danglingFunction() {}
const usedConstant = 'hello';
/// Left behind after a refactor.
const unusedConstant = 'bye';
class UnusedClass {
void orphanMethod() {}
}
$ ciach --remove
lib/greeting.dart
9:6 function danglingFunction (public)
14:7 variable unusedConstant (public)
16:7 class UnusedClass (public)
17:8 method UnusedClass.orphanMethod (public)
Found 4 unused declarations in 1 file (scanned 1 file, 8 declarations, 0.4s)
Remove 4 unused declarations? [y/N] y
Removed 4 unused declarations from 1 file.
Features
Sharp, and careful about it.
-
Every declaration kind
Classes, enums and their values, functions, methods, constructors, fields, getters, variables and more.
-
Backed by the real analyzer
Reference queries go to the Dart analysis server: the same resolution your IDE uses, not a regex.
-
Built for CI
Annotations inline on the pull request diff and a non-zero exit when anything turns up.
-
Safe defaults
@overridemembers, operators, entry points, generated files andtoJson()are skipped unless you opt in. -
Text, JSON or GitHub output
Human-readable by default, machine-readable on request.
-
A config file, optionally
Every flag can live in
ciach.yaml. The command line always wins.
Output
Speaks human, machine and GitHub.
Pick the format with -f. Exit codes are the same in every one.
lib/orphans.dart
8:7 class UnusedClass (public)
10:8 method UnusedClass.orphanMethod (public)
22:7 class FullyDeadClass (public)
31:3 constructor ReferencedAsTypeOnly.new (public)
Found 4 unused declarations in 1 file (scanned 1 file, 6 declarations, 0.7s)
{
"summary": {
"filesScanned": 1,
"declarationsChecked": 6,
"unusedCount": 4,
"docOnlyCount": 0,
"elapsedMs": 729
},
"unused": [
{
"name": "UnusedClass",
"qualifiedName": "UnusedClass",
"kind": "class",
"file": "lib/orphans.dart",
"line": 8,
"column": 7,
"isPrivate": false
}
],
"docOnly": [],
"warnings": [],
"problems": []
}
::warning file=lib/orphans.dart,line=8,col=7,title=Unused declaration::Unused class 'UnusedClass'
::warning file=lib/orphans.dart,line=10,col=8,title=Unused declaration::Unused method 'UnusedClass.orphanMethod'
::warning file=lib/orphans.dart,line=22,col=7,title=Unused declaration::Unused class 'FullyDeadClass'
::notice file=lib/greeting.dart,line=41,col=6,title=Referenced only from a doc comment::function '_docOnlyMentioned' has no code references, only a dartdoc link
Upstream
It finds bugs in the analyzer, too.
Asking for the references of every declaration turns up what an editor rarely hits. We reported these to the Dart SDK, and fixed some ourselves.
- #63903Missed references from object patterns in other filesFixed by us
- #63944Dot shorthands hidden by a local of the same nameFixed by us
-
#64422References to an
Objectmember override threwFixed by the Dart team