Flutter Engine
The Flutter Engine
|
Preliminary notes on writing lints.
Borrowing heavily from the criteria for adding new checks to errorprone, lints should have the following properties.
Dart lints:
Every lint has a:
Name. A short name using Dart package naming conventions. Naming is hard but strive to be concise and consistent. Prefer to use the problem as the name, as in the existing lints control_flow_in_finally
and empty_catches
. Do not start a lint's name with "always", "avoid", or "prefer". Where possible, use existing rules for inspiration and observe the rules of parallel construction.
Description. A short description of the lint, suitable for printing in console output. For example:
Kind. The first word in the description should identify the kind of lint where kinds are derived from the style guide. In summary:
Detailed Description. In addition to the short description, a lint rule should have more detailed rationale with code examples, ideally good and bad. The style guide is a great source for inspiration. Many style recommendations have been directly translated to lints as enumerated here.
Group. A grouping. For example, Style Guide aggregates style guide derived lints.
Maturity. Rules can be further distinguished by maturity. Unqualified rules are considered stable, while others may be marked EXPERIMENTAL or PROPOSED to indicate that they are under review.
Lints live in the lib/src/rules directory. Corresponding unit tests live in [test/rules].
Rule stubs can be generated with the rule.dart helper script:
$ dart tool/rule.dart -n my_new_lint
generates lint and test stubs in lib/src/rules
and test/rules
.
The linter has a close relationship with the analyzer
package and at times reaches into non-public APIs. For the most part, we have isolated these references in an analyzer.dart utility library. Wherever possible please use this library to access analyzer internals.
analyzer.dart
is missing something please consider opening an issue where we can discuss how best to add it.Thanks!
When writing lints, it can be useful to have the Dart Language Specification handy. If you're working to support bleeding edge language features, you'll want the latest draft.
Important: when writing tests that use standard dart:
libraries, it's important to keep in mind that linter tests use a mocked SDK that has only a small subset of the real one. We do this for performance reasons as it's FAR faster to load a mock SDK into memory than read the real one from disk. If you are writing tests that depend on something in the Dart SDK (for example, an interface such as Iterable
), you may need to update SDK mock content located in the package:analyzer
test utilities mock_sdk.dart
.
The test suite run during the linter's CI, can be run locally like so:
$ dart test/all.dart
You'll notice when authoring a new rule that failures cause the AST of the test case to be displayed to stdout
. If you simply want to dump the AST of a given compilation unit, you can use the spelunk
helper directly. For example:
$ dart tool/spelunk.dart lib/src/rules.dart
would dump the AST of rules.dart
.
For performance reasons rules should prefer implementing NodeLintRule
and registering interest in specific AST node types using registry.addXYZ(this, visitor)
. Avoid overriding visitCompilationUnit()
and performing your own full CompilationUnit
visits.
Details are under active development. Feedback is most welcome!