Skip to content

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
my_app — 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.

lib/greeting.dart
/// 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
$ 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.

What --remove refuses to touch →

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

    @override members, operators, entry points, generated files and toJson() 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.

$ ciach
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)
$ ciach -f json
{
  "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": []
}
$ ciach -f github
::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.