dart_code_linter
Dart Code Linter は、開発者がソフトウェアの品質を分析および改善するのを支援するソフトウェア分析ツールです。Dart Code Linter は、Dart Code Metrics のフォークに基づいています。
Dart Code Linter は、開発者がソフトウェアの品質を分析および改善するのを支援するソフトウェア分析ツールです。Dart Code Linter は Dart Code Metrics のフォークに基づいています。他の開発者の貢献を歓迎します。この GitHub リポジトリにプルリクエストやバグレポートを送信してください。
^0.3.0>=10.0.0 <15.0.0>=0.14.0 <0.16.0^2.0.1^2.0.0^1.16.0^3.0.0>=6.0.0 <8.0.0^2.0.1^0.15.0^1.1.0^1.7.0^1.8.0^3.1.0>=0.3.0 <0.6.0^1.9.0^4.1.0>=6.6.0 <8.0.0^3.1.0^1.0.2>=0.17.0 <0.21.0>=2.0.0 <7.0.0>=0.3.0 <2.0.0>=1.21.0 <1.32.0{"path":"./test/resources/test_lints"}以下は英語原文のスナップショットです。最新版は GitHub をご覧ください。
Dart Code Linter (DCL) is a powerful toolkit designed to enhance your development process by identifying and resolving issues within your Dart and Flutter code. Whether you're dealing with potential runtime bugs, violations of best practices, or styling concerns, DCL has got you covered. With a comprehensive collection of over 70 pre-built rules, you can effortlessly validate your code against a variety of expectations. Furthermore, DCL offers the flexibility to customize these rules to cater to your specific requirements, ensuring an optimized coding experience.
dart pub add --dev dart_code_linter
Add configuration to analysis_options.yaml and reload IDE to allow the analyzer to discover the plugin config.
analyzer:
plugins:
- dart_code_linter
dart_code_linter:
rules:
- avoid-dynamic
- avoid-passing-async-when-sync-expected
- avoid-redundant-async
- avoid-unnecessary-type-assertions
- avoid-unnecessary-type-casts
- avoid-unrelated-type-assertions
- avoid-unused-parameters
- avoid-nested-conditional-expressions
- newline-before-return
- no-boolean-literal-compare
- no-empty-block
- prefer-trailing-comma
- prefer-conditional-expressions
- no-equal-then-else
- prefer-moving-to-variable
- prefer-match-file-name
analyzer:
plugins:
- dart_code_linter
dart_code_linter:
metrics:
cyclomatic-complexity: 20
number-of-parameters: 4
maximum-nesting-level: 5
metrics-exclude:
- test/**
rules:
- avoid-dynamic
- avoid-passing-async-when-sync-expected
- avoid-redundant-async
- avoid-unnecessary-type-assertions
- avoid-unnecessary-type-casts
- avoid-unrelated-type-assertions
- avoid-unused-parameters
- avoid-nested-conditional-expressions
- newline-before-return
- no-boolean-literal-compare
- no-empty-block
- prefer-trailing-comma
- prefer-conditional-expressions
- no-equal-then-else
- prefer-moving-to-variable
- prefer-match-file-name
DCL can be used as a plugin for the Dart analyzer package providing additional rules. All issues produced by rules or anti-patterns will be highlighted in the IDE.
Depending on your Dart SDK version, you can configure the plugin in two ways:
Dart 3.9 is not supported by this release's plugin integrations. Use Dart >= 3.10 for the Analysis Server Plugin and Dart < 3.9 for the Legacy Analyzer Plugin.
DCL supports the new Dart Analysis Server plugin protocol (analysis_server_plugin). To use it, add plugin configuration under the top-level plugins key in analysis_options.yaml:
plugins:
dart_code_linter:
diagnostics:
avoid-dynamic: true
no-magic-number: warning
dart_code_linter:
rules:
- avoid-dynamic
- no-magic-number:
severity: warning
allowed: [42]
Top-level plugins.dart_code_linter.diagnostics controls IDE enablement and severity. The top-level dart_code_linter.rules section supplies full DCL rule configuration, including arbitrary parameters used by both IDE integration and CLI.
Dart 3.13 accepts only scalar diagnostic values in plugins.dart_code_linter.diagnostics:
true: enable the rule with its analyzer default severity.false: disable the rule in the IDE.info, warning, or error: enable the rule with that IDE severity.Do not put a map below plugins.dart_code_linter.diagnostics.<rule> on Flutter 3.47 / Dart 3.13. The analyzer rejects that shape with invalid_section_format before the plugin runs. Put rule maps under dart_code_linter.rules instead.
Rules with mandatory configuration, such as avoid-banned-imports and ban-name, work with the modern plugin when their configuration lives under dart_code_linter.rules.
Configure the plugin under analyzer in your analysis_options.yaml:
analyzer:
plugins:
- dart_code_linter
dart_code_linter:
rules:
- avoid-dynamic
- prefer-trailing-comma
Rules that are marked with 🛠 have auto-fixes available through the IDE context menu. VS Code example:
VS Code example
As DCL depends on the Dart analyzer package. The following table shows the compatible versions:
| DCL Version | Analyzer Version | Dart SDK |
|---|---|---|
| 4.4.0 | >=10.0.0 <15.0.0 | >=3.5.0 <4.0.0 |
| 4.3.0 | >=10.0.0 <15.0.0 | >=3.5.0 <4.0.0 |
| 4.2.2 | >=10.0.0 <15.0.0 | >=3.5.0 <4.0.0 |
| 4.2.1 | >=10.0.0 <15.0.0 | >=3.5.0 <4.0.0 |
| 4.2.0 | >=10.0.0 <15.0.0 | >=3.5.0 <4.0.0 |
| 4.1.9 | >=10.0.0 <15.0.0 | >=3.5.0 <4.0.0 |
| 4.1.8 | >=10.0.0 <15.0.0 | >=3.5.0 <4.0.0 |
| 4.1.7 | >=10.0.0 <14.0.0 | >=3.5.0 <4.0.0 |
| 4.1.6 | >=10.0.0 <14.0.0 | >=3.5.0 <4.0.0 |
| 4.1.5 | >=10.0.0 <14.0.0 | >=3.5.0 <4.0.0 |
| 4.1.4 | >=10.0.0 <14.0.0 | >=3.5.0 <4.0.0 |
| 4.1.3 | >=10.0.0 <14.0.0 | >=3.5.0 <4.0.0 |
| 4.1.2 | >=10.0.0 <14.0.0 | >=3.5.0 <4.0.0 |
| 4.1.1 | >=10.0.0 <14.0.0 | >=3.5.0 <4.0.0 |
| 4.1.0 | >=10.0.0 <14.0.0 | >=3.5.0 <4.0.0 |
| 4.0.5 | >=10.0.0 <13.0.0 | >=3.5.0 <4.0.0 |
| 4.0.4 | >=10.0.0 <13.0.0 | >=3.5.0 <4.0.0 |
| 4.0.3 | >=10.0.0 <13.0.0 | >=3.5.0 <4.0.0 |
| 4.0.2 | >=10.0.0 <13.0.0 | >=3.5.0 <4.0.0 |
| 4.0.1 | >=10.0.0 <13.0.0 | >=3.5.0 <4.0.0 |
| 4.0.0 | >=11.0.0 <12.0.0 | >=3.5.0 <4.0.0 |
| >=3.2.0 <4.0.0 | ^8.0.0 | >=3.4.0 <4.0.0 |
| >=3.0.0 <3.2.0 | ^7.4.1 | >=3.4.0 <4.0.0 |
| >=2.0.0 <3.0.0 | ^6.0.0 | >=3.0.0 <4.0.0 |
The package can be used as CLI and supports multiple commands:
| Command | Example of use | Short description |
|---|---|---|
| analyze | dart run dart_code_linter:metrics analyze lib | Reports code metrics, rules and anti-patterns violations. |
| check-unnecessary-nullable | dart run dart_code_linter:metrics check-unnecessary-nullable lib | Checks unnecessary nullable parameters in functions, methods, constructors. |
| check-unused-files | dart run dart_code_linter:metrics check-unused-files lib | Checks unused *.dart files. |
| check-unused-l10n | dart run dart_code_linter:metrics check-unused-l10n lib | Check unused localization in *.dart files. |
| check-unused-code | dart run dart_code_linter:metrics check-unused-code lib | Checks unused code in *.dart files. |
For additional help on any of the commands, enter dart run dart_code_linter:metrics help <command>
Note: if you're setting up DCL for multi-package repository (a.k.a. monorepo), it'll pick up analysis_options.yaml files correctly.
You can define one analysis_options.yaml at the root file.
Reports code metrics, rules and anti-patterns violations. To execute the command, run
dart run dart_code_linter:metrics analyze lib
It will produce a result in one of the format:
Checks unnecessary nullable parameters in functions, methods, constructors. To execute the command, run
dart run dart_code_linter:metrics check-unnecessary-nullable lib
It will produce a result in one of the format:
Checks unused *.dart files. To execute the command, run
dart run dart_code_linter:metrics check-unused-files lib
It will produce a result in one of the format:
Checks unused Dart class members, that encapsulates the app’s localized values.
An example of such class:
class ClassWithLocalization {
String get title {
return Intl.message(
'Hello World',
name: 'title',
desc: 'Title for the Demo application',
locale: localeName,
);
}
}
To execute the command, run
dart run dart_code_linter:metrics check-unused-l10n lib
It will produce a result in one of the format:
Checks unused code in *.dart files. To execute the command, run
dart run dart_code_linter:metrics check-unused-code lib
It will produce a result in one of the format:
By default only top level declarations (classes, functions, variables, and so on) are checked. Unused private members of type declarations (methods, fields, getters, setters and named constructors) are reported too when the check is opted in:
dart run dart_code_linter:metrics check-unused-code lib --analyze-private-members
The same can be enabled through analysis_options.yaml, so it applies to every
run:
dart_code_linter:
unused-code:
analyze-private-members: true
The CLI flag wins over the analysis_options.yaml value when both are set. Two
limitations are worth knowing about:
part files,
for example) are invisible, so members used exclusively from there are
reported.Public members are covered by a separate opt in, because they need more guesswork than private ones and are therefore less reliable:
dart run dart_code_linter:metrics check-unused-code lib --analyze-public-members
dart_code_linter:
unused-code:
analyze-public-members: true
The two options are independent, so a large project can keep the cheap private members check on while leaving this one off. Members that cannot be seen to be used through a reference are skipped rather than reported:
toString, hashCode
and noSuchMethod on every class, and overrides that carry no @override
annotation.@override, @mustBeOverridden, @visibleForOverriding,
@redeclare, @protected, @visibleForTesting, @JS, or
@pragma('vm:entry-point').@JSExport, which JavaScript calls
through createJSInteropWrapper. This one also counts when the annotation
sits on the enclosing class, though only for that class's instance members,
since statics are never wrapped. Note that a @pragma('vm:entry-point') on
the enclosing class does not work the same way: it only permits allocation
from native code, so members still need their own pragma and are otherwise
reported.dynamic) type. Operators count too: a host + 1, host[0] = 1 or
host(1) on a dynamic target keeps every operator +, operator []= and
call member, since any of them could be the one reached.toJson, which json.encode calls by convention rather than by reference.values is referenced anywhere, since
iteration, byName and name based deserialization reach the constants without
naming any of them.Even so, expect more false positives than from the private members check.
Members reached only through code generation, reflection or a package that
depends on yours cannot be seen at all. Note also that members used only by
your tests are reported when the analysis covers lib alone; pass the test
folder too (check-unused-code lib test) if you want those usages counted.
A third opt in reports the opposite situation: public declarations that are used, but only ever from inside the library that declares them, and so could carry a private name instead.
dart run dart_code_linter:metrics check-unused-code lib --suggest-private-members
dart_code_linter:
unused-code:
suggest-private-members: true
It covers both type members and top level declarations, and is independent of
the other two options. Because it reports code that is used rather than dead
code, it has its own exit gate, --[no-]fatal-could-be-private, so a project
can keep the suggestions visible without failing the build on them.
A declaration nothing references at all is never reported here: that is dead code, which is what the two options above are for. When both checks are on, an unused declaration is reported once, as unused. One shape slips through that rule: a dead declaration sharing its name with a used declaration of the same library is matched by the deliberately loose name comparison that works around dart-lang/sdk#49182, so it reads as used and can be reported as a suggestion rather than as dead code. Members of a type that is itself reported dead are dropped, so what is left of this is a dead member of a live type.
Every exemption of the public members check applies here too, since an analysis that cannot see how a declaration is reached cannot tell that everything reaching it sits in one library either. On top of those, these are never suggested:
name and toString, so
renaming one can silently change serialized output; and the call method
that makes its type callable, since obj(...) binds a member spelled
exactly call, so the rename fails to compile even inside the declaring
library. Only a method is exempt: a field, a getter or a static named call
is reached by an ordinary reference and is still suggested.this.x or super.x formal. Dart forbids a named
parameter starting with an underscore, so the rename does not compile even
for a constructor nothing outside the library calls.noSuchMethod. The rename compiles
there, but a mock that stubs by name stops matching the call.lib/ outside lib/src, since
Dart lets a consumer import that directly whether or not anything exports
it. The cut covers the members of its types as well as its top level
declarations: a consumer that can name the type reaches the public members
of that type just as directly, so the rename breaks it either way. Only the
suggestions are dropped, and the unused check still reports these files
exactly as it always has. --monorepo lifts the exemption, as it does for
the unused check, since it says there are no unseen consumers to protect. An
application is in that same position, since nothing outside it can import
its lib/ at all, so pass --monorepo there too. A published package that
keeps nothing under lib/src will otherwise see no suggestions at all,
which is the intended answer rather than a gap: every declaration it has is
reachable by a consumer this analysis cannot see.The same blind spot as above applies: a subtype or a reference living in a
package that depends on yours, or in a folder outside the analysis, cannot be
seen, so run the check over every folder that uses the code
(check-unused-code lib test).
Please read the following guide if the plugin is not working as you'd expect it to work.
If you are interested in contributing, please check out the contribution guidelines. Feedback and contributions are welcome!
Dart Code Linter is licensed under the MIT