blob: b312e59daa47277ef4c05236bcf29c1929d1399d [file] [log] [blame]
# Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# There is a fixed set of categories:
#
# * binarySize - rules that help to minimize binary size.
# * brevity - rules that encourage brevity in the source code.
# * documentationCommentMaintenance - rules that help to maintain documentation
# comments.
# * effectiveDart - rules that align with the Effective Dart style guide.
# * errorProne - rules that protect against error-prone code.
# * flutter - rules that help to write Flutter code.
# * languageFeatureUsage - rules that promote language feature usage.
# * memoryLeaks - rules that protect against possibly memory-leaking code.
# * nonPerformant - rules that protect against non-performant code.
# * pub - pub-related rules.
# * publicInterface - rules that promote a healthy public interface.
# * style - matters of style, largely derived from Effective Dart.
# * unintentional - rules that protect against code that probably doesn't do
# what you think it does, or that shouldn't be used as it is.
# * unusedCode - rules that protect against unused code.
# * web - rules that help to write code deployed to the web.
LintCode:
always_declare_return_types_of_functions:
sharedName: always_declare_return_types
problemMessage: "The function '{0}' should have a return type but doesn't."
correctionMessage: "Try adding a return type to the function."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a method or function doesn't
have an explicit return type.
#### Example
The following code produces this diagnostic because the function `f`
doesn't have a return type:
```dart
[!f!]() {}
```
#### Common fixes
Add an explicit return type:
```dart
void f() {}
```
deprecatedDetails: |-
**DO** declare method return types.
When declaring a method or function *always* specify a return type.
Declaring return types for functions helps improve your codebase by allowing the
analyzer to more adequately check your code for errors that could occur during
runtime.
**BAD:**
```dart
main() { }
_bar() => _Foo();
class _Foo {
_foo() => 42;
}
```
**GOOD:**
```dart
void main() { }
_Foo _bar() => _Foo();
class _Foo {
int _foo() => 42;
}
typedef predicate = bool Function(Object o);
```
always_declare_return_types_of_methods:
sharedName: always_declare_return_types
problemMessage: "The method '{0}' should have a return type but doesn't."
correctionMessage: "Try adding a return type to the method."
hasPublishedDocs: true
always_put_control_body_on_new_line:
problemMessage: "Statement should be on a separate line."
correctionMessage: "Try moving the statement to a new line."
addedIn: "2.0"
categories: [errorProne, style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the code being controlled by a
control flow statement (`if`, `for`, `while`, or `do`) is on the same line
as the control flow statement.
#### Example
The following code produces this diagnostic because the `return` statement
is on the same line as the `if` that controls whether the `return` will be
executed:
```dart
void f(bool b) {
if (b) [!return!];
}
```
#### Common fixes
Put the controlled statement onto a separate, indented, line:
```dart
void f(bool b) {
if (b)
return;
}
```
deprecatedDetails: |-
From the [style guide for the flutter repo](https://flutter.dev/style-guide/):
**DO** separate the control structure expression from its statement.
Don't put the statement part of an `if`, `for`, `while`, `do` on the same line
as the expression, even if it is short. Doing so makes it unclear that there
is relevant code there. This is especially important for early returns.
**BAD:**
```dart
if (notReady) return;
if (notReady)
return;
else print('ok')
while (condition) i += 1;
```
**GOOD:**
```dart
if (notReady)
return;
if (notReady)
return;
else
print('ok')
while (condition)
i += 1;
```
Note that this rule can conflict with the
[Dart formatter](https://dart.dev/tools/dart-format), and should not be enabled
when the Dart formatter is used.
always_put_required_named_parameters_first:
problemMessage: "Required named parameters should be before optional named parameters."
correctionMessage: "Try moving the required named parameter to be before any optional named parameters."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when required named parameters occur
after optional named parameters.
#### Example
The following code produces this diagnostic because the required parameter
`x` is after the optional parameter `y`:
```dart
void f({int? y, required int [!x!]}) {}
```
#### Common fixes
Reorder the parameters so that all required named parameters are before
any optional named parameters:
```dart
void f({required int x, int? y}) {}
```
deprecatedDetails: |-
**DO** specify `required` on named parameter before other named parameters.
**BAD:**
```dart
m({b, c, required a}) ;
```
**GOOD:**
```dart
m({required a, b, c}) ;
```
**BAD:**
```dart
m({b, c, @required a}) ;
```
**GOOD:**
```dart
m({@required a, b, c}) ;
```
always_require_non_null_named_parameters:
addedIn: "2.0"
removedIn: "3.3"
deprecatedDetails: |-
NOTE: This rule is removed in Dart 3.3.0; it is no longer functional.
**DO** specify `@required` on named parameters without a default value on which
an `assert(param != null)` is done.
**BAD:**
```dart
m1({a}) {
assert(a != null);
}
```
**GOOD:**
```dart
m1({@required a}) {
assert(a != null);
}
m2({a: 1}) {
assert(a != null);
}
```
NOTE: Only asserts at the start of the bodies will be taken into account.
always_specify_types_add_type:
sharedName: always_specify_types
problemMessage: "Missing type annotation."
correctionMessage: "Try adding a type annotation."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
From the [style guide for the flutter repo](https://flutter.dev/style-guide/):
**DO** specify type annotations.
Avoid `var` when specifying that a type is unknown and short-hands that elide
type annotations. Use `dynamic` if you are being explicit that the type is
unknown. Use `Object` if you are being explicit that you want an object that
implements `==` and `hashCode`.
**BAD:**
```dart
var foo = 10;
final bar = Bar();
const quux = 20;
```
**GOOD:**
```dart
int foo = 10;
final Bar bar = Bar();
String baz = 'hello';
const int quux = 20;
```
NOTE: Using the the `@optionalTypeArgs` annotation in the `meta` package, API
authors can special-case type parameters whose type needs to be dynamic but whose
declaration should be treated as optional. For example, suppose you have a
`Key` object whose type parameter you'd like to treat as optional. Using the
`@optionalTypeArgs` would look like this:
```dart
import 'package:meta/meta.dart';
@optionalTypeArgs
class Key<T> {
...
}
void main() {
Key s = Key(); // OK!
}
```
always_specify_types_replace_keyword:
sharedName: always_specify_types
problemMessage: "Missing type annotation."
correctionMessage: "Try replacing '{0}' with '{1}'."
hasPublishedDocs: false
always_specify_types_specify_type:
sharedName: always_specify_types
problemMessage: "Missing type annotation."
correctionMessage: "Try specifying the type '{0}'."
hasPublishedDocs: false
always_specify_types_split_to_types:
sharedName: always_specify_types
problemMessage: "Missing type annotation."
correctionMessage: "Try splitting the declaration and specify the different type annotations."
hasPublishedDocs: false
always_use_package_imports:
problemMessage: "Use 'package:' imports for files in the 'lib' directory."
correctionMessage: "Try converting the URI to a 'package:' URI."
addedIn: "2.10"
categories: [errorProne]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when an `import` in a library inside
the `lib` directory uses a relative path to import another library inside
the `lib` directory of the same package.
#### Example
Given that a file named `a.dart` and the code below are both inside the
`lib` directory of the same package, the following code produces this
diagnostic because a relative URI is used to import `a.dart`:
```dart
import [!'a.dart'!];
```
#### Common fixes
Use a package import:
```dart
import 'package:p/a.dart';
```
deprecatedDetails: |-
**DO** avoid relative imports for files in `lib/`.
When mixing relative and absolute imports it's possible to create confusion
where the same member gets imported in two different ways. One way to avoid
that is to ensure you consistently use absolute imports for files within the
`lib/` directory.
This is the opposite of 'prefer_relative_imports'.
You can also use 'avoid_relative_lib_imports' to disallow relative imports of
files within `lib/` directory outside of it (for example `test/`).
**BAD:**
```dart
import 'baz.dart';
import 'src/bag.dart'
import '../lib/baz.dart';
...
```
**GOOD:**
```dart
import 'package:foo/bar.dart';
import 'package:foo/baz.dart';
import 'package:foo/src/baz.dart';
...
```
annotate_overrides:
problemMessage: "The member '{0}' overrides an inherited member but isn't annotated with '@override'."
correctionMessage: "Try adding the '@override' annotation."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a member overrides an inherited
member, but isn't annotated with `@override`.
#### Example
The following code produces this diagnostic because the method `m` in the
class `B` overrides the method with the same name in class `A`, but isn't
marked as an intentional override:
```dart
class A {
void m() {}
}
class B extends A {
void [!m!]() {}
}
```
#### Common fixes
If the member in the subclass is intended to override the member in the
superclass, then add an `@override` annotation:
```dart
class A {
void m() {}
}
class B extends A {
@override
void m() {}
}
```
If the member in the subclass is not intended to override the member in
the superclass, then rename one of the members:
```dart
class A {
void m() {}
}
class B extends A {
void m2() {}
}
```
deprecatedDetails: |-
**DO** annotate overridden methods and fields.
This practice improves code readability and helps protect against
unintentionally overriding superclass members.
**BAD:**
```dart
class Cat {
int get lives => 9;
}
class Lucky extends Cat {
final int lives = 14;
}
```
**GOOD:**
```dart
abstract class Dog {
String get breed;
void bark() {}
}
class Husky extends Dog {
@override
final String breed = 'Husky';
@override
void bark() {}
}
```
annotate_redeclares:
problemMessage: "The member '{0}' is redeclaring but isn't annotated with '@redeclare'."
correctionMessage: "Try adding the '@redeclare' annotation."
addedIn: "3.2"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** annotate redeclared members.
This practice improves code readability and helps protect against
unintentionally redeclaring members or being surprised when a member ceases to
redeclare (due for example to a rename refactoring).
**BAD:**
```dart
class C {
void f() { }
}
extension type E(C c) implements C {
void f() {
...
}
}
```
**GOOD:**
```dart
import 'package:meta/meta.dart';
class C {
void f() { }
}
extension type E(C c) implements C {
@redeclare
void f() {
...
}
}
```
avoid_annotating_with_dynamic:
problemMessage: "Unnecessary 'dynamic' type annotation."
correctionMessage: "Try removing the type 'dynamic'."
addedIn: "2.0"
categories: [brevity, style]
hasPublishedDocs: false
deprecatedDetails: |-
**AVOID** annotating with `dynamic` when not required.
As `dynamic` is the assumed return value of a function or method, it is usually
not necessary to annotate it.
**BAD:**
```dart
dynamic lookUpOrDefault(String name, Map map, dynamic defaultValue) {
var value = map[name];
if (value != null) return value;
return defaultValue;
}
```
**GOOD:**
```dart
lookUpOrDefault(String name, Map map, defaultValue) {
var value = map[name];
if (value != null) return value;
return defaultValue;
}
```
avoid_as:
addedIn: "2.0"
removedIn: "3.0"
deprecatedDetails: |-
NOTE: This rule was removed from the SDK in Dart 3; it is no longer functional.
Its advice is compiler-specific and mostly obsolete with null safety.
**AVOID** using `as`.
If you know the type is correct, use an assertion or assign to a more
narrowly-typed variable (this avoids the type check in release mode; `as` is not
compiled out in release mode). If you don't know whether the type is
correct, check using `is` (this avoids the exception that `as` raises).
**BAD:**
```dart
(pm as Person).firstName = 'Seth';
```
**GOOD:**
```dart
if (pm is Person)
pm.firstName = 'Seth';
```
but certainly not
**BAD:**
```dart
try {
(pm as Person).firstName = 'Seth';
} on CastError { }
```
Note that an exception is made in the case of `dynamic` since the cast has no
performance impact.
**OK:**
```dart
HasScrollDirection scrollable = renderObject as dynamic;
```
avoid_bool_literals_in_conditional_expressions:
problemMessage: "Conditional expressions with a 'bool' literal can be simplified."
correctionMessage: "Try rewriting the expression to use either '&&' or '||'."
addedIn: "2.0"
categories: [brevity]
hasPublishedDocs: false
deprecatedDetails: |-
**AVOID** `bool` literals in conditional expressions.
**BAD:**
```dart
condition ? true : boolExpression
condition ? false : boolExpression
condition ? boolExpression : true
condition ? boolExpression : false
```
**GOOD:**
```dart
condition || boolExpression
!condition && boolExpression
!condition || boolExpression
condition && boolExpression
```
avoid_catches_without_on_clauses:
problemMessage: "Catch clause should use 'on' to specify the type of exception being caught."
correctionMessage: "Try adding an 'on' clause before the 'catch'."
addedIn: "2.0"
categories: [effectiveDart, style]
hasPublishedDocs: false
deprecatedDetails: |-
From [Effective Dart](https://dart.dev/effective-dart/usage#avoid-catches-without-on-clauses):
**AVOID** catches without on clauses.
Using catch clauses without on clauses make your code prone to encountering
unexpected errors that won't be thrown (and thus will go unnoticed).
**BAD:**
```dart
try {
somethingRisky()
} catch(e) {
doSomething(e);
}
```
**GOOD:**
```dart
try {
somethingRisky()
} on Exception catch(e) {
doSomething(e);
}
```
A few exceptional cases are allowed:
* If the body of the catch rethrows the exception.
* If the caught exception is "directly used" in an argument to `Future.error`,
`Completer.completeError`, or `FlutterError.reportError`, or any function with
a return type of `Never`.
* If the caught exception is "directly used" in a new throw-expression.
In these cases, "directly used" means that the exception is referenced within
the relevant code (like within an argument). If the exception variable is
referenced _before_ the relevant code, for example to instantiate a wrapper
exception, the variable is not "directly used."
avoid_catching_errors_class:
sharedName: avoid_catching_errors
problemMessage: "The type 'Error' should not be caught."
correctionMessage: "Try removing the catch or catching an 'Exception' instead."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DON'T** explicitly catch `Error` or types that implement it.
Errors differ from Exceptions in that Errors can be analyzed and prevented prior
to runtime. It should almost never be necessary to catch an error at runtime.
**BAD:**
```dart
try {
somethingRisky();
} on Error catch(e) {
doSomething(e);
}
```
**GOOD:**
```dart
try {
somethingRisky();
} on Exception catch(e) {
doSomething(e);
}
```
avoid_catching_errors_subclass:
sharedName: avoid_catching_errors
problemMessage: "The type '{0}' should not be caught because it is a subclass of 'Error'."
correctionMessage: "Try removing the catch or catching an 'Exception' instead."
hasPublishedDocs: false
avoid_classes_with_only_static_members:
problemMessage: "Classes should define instance members."
correctionMessage: "Try adding instance behavior or moving the members out of the class."
addedIn: "2.0"
categories: [effectiveDart, languageFeatureUsage, style]
hasPublishedDocs: false
deprecatedDetails: |-
From [Effective Dart](https://dart.dev/effective-dart/design#avoid-defining-a-class-that-contains-only-static-members):
**AVOID** defining a class that contains only static members.
Creating classes with the sole purpose of providing utility or otherwise static
methods is discouraged. Dart allows functions to exist outside of classes for
this very reason.
**BAD:**
```dart
class DateUtils {
static DateTime mostRecent(List<DateTime> dates) {
return dates.reduce((a, b) => a.isAfter(b) ? a : b);
}
}
class _Favorites {
static const mammal = 'weasel';
}
```
**GOOD:**
```dart
DateTime mostRecent(List<DateTime> dates) {
return dates.reduce((a, b) => a.isAfter(b) ? a : b);
}
const _favoriteMammal = 'weasel';
```
avoid_double_and_int_checks:
problemMessage: "Explicit check for double or int."
correctionMessage: "Try removing the check."
addedIn: "2.0"
categories: [errorProne, web]
hasPublishedDocs: false
deprecatedDetails: |-
**AVOID** to check if type is `double` or `int`.
When compiled to JS, integer values are represented as floats. That can lead to
some unexpected behavior when using either `is` or `is!` where the type is
either `int` or `double`.
**BAD:**
```dart
f(num x) {
if (x is double) {
...
} else if (x is int) {
...
}
}
```
**GOOD:**
```dart
f(dynamic x) {
if (x is num) {
...
} else {
...
}
}
```
avoid_dynamic_calls:
problemMessage: "Method invocation or property access on a 'dynamic' target."
correctionMessage: "Try giving the target a type."
addedIn: "2.12"
categories: [binarySize, errorProne]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** avoid method calls or accessing properties on an object that is either
explicitly or implicitly statically typed `dynamic`. Dynamic calls are treated
slightly different in every runtime environment and compiler, but most
production modes (and even some development modes) have both compile size and
runtime performance penalties associated with dynamic calls.
Additionally, targets typed `dynamic` disables most static analysis, meaning it
is easier to lead to a runtime `NoSuchMethodError` or `TypeError` than properly
statically typed Dart code.
There is an exception to methods and properties that exist on `Object?`:
- `a.hashCode`
- `a.runtimeType`
- `a.noSuchMethod(someInvocation)`
- `a.toString()`
... these members are dynamically dispatched in the web-based runtimes, but not
in the VM-based ones. Additionally, they are so common that it would be very
punishing to disallow `any.toString()` or `any == true`, for example.
Note that despite `Function` being a type, the semantics are close to identical
to `dynamic`, and calls to an object that is typed `Function` will also trigger
this lint.
Dynamic calls are allowed on cast expressions (`as dynamic` or `as Function`).
**BAD:**
```dart
void explicitDynamicType(dynamic object) {
print(object.foo());
}
void implicitDynamicType(object) {
print(object.foo());
}
abstract class SomeWrapper {
T doSomething<T>();
}
void inferredDynamicType(SomeWrapper wrapper) {
var object = wrapper.doSomething();
print(object.foo());
}
void callDynamic(dynamic function) {
function();
}
void functionType(Function function) {
function();
}
```
**GOOD:**
```dart
void explicitType(Fooable object) {
object.foo();
}
void castedType(dynamic object) {
(object as Fooable).foo();
}
abstract class SomeWrapper {
T doSomething<T>();
}
void inferredType(SomeWrapper wrapper) {
var object = wrapper.doSomething<Fooable>();
object.foo();
}
void functionTypeWithParameters(Function() function) {
function();
}
```
avoid_empty_else:
problemMessage: "Empty statements are not allowed in an 'else' clause."
correctionMessage: "Try removing the empty statement or removing the else clause."
addedIn: "2.0"
categories: [brevity, errorProne]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the statement after an `else`
is an empty statement (a semicolon).
For more information, see the documentation for
[`avoid_empty_else`](https://dart.dev/diagnostics/avoid_empty_else).
#### Example
The following code produces this diagnostic because the statement
following the `else` is an empty statement:
```dart
void f(int x, int y) {
if (x > y)
print("1");
else [!;!]
print("2");
}
```
#### Common fixes
If the statement after the empty statement is intended to be executed only
when the condition is `false`, then remove the empty statement:
```dart
void f(int x, int y) {
if (x > y)
print("1");
else
print("2");
}
```
If there is no code that is intended to be executed only when the
condition is `false`, then remove the whole `else` clause:
```dart
void f(int x, int y) {
if (x > y)
print("1");
print("2");
}
```
deprecatedDetails: |-
**AVOID** empty statements in the `else` clause of `if` statements.
**BAD:**
```dart
if (x > y)
print('1');
else ;
print('2');
```
If you want a statement that follows the empty clause to _conditionally_ run,
remove the dangling semicolon to include it in the `else` clause.
Optionally, also enclose the else's statement in a block.
**GOOD:**
```dart
if (x > y)
print('1');
else
print('2');
```
**GOOD:**
```dart
if (x > y) {
print('1');
} else {
print('2');
}
```
If you want a statement that follows the empty clause to _unconditionally_ run,
remove the `else` clause.
**GOOD:**
```dart
if (x > y) print('1');
print('2');
```
avoid_equals_and_hash_code_on_mutable_classes:
problemMessage: "The method '{0}' should not be overridden in classes not annotated with '@immutable'."
correctionMessage: "Try removing the override or annotating the class with '@immutable'."
addedIn: "2.6"
categories: [effectiveDart, style]
hasPublishedDocs: false
deprecatedDetails: |-
From [Effective Dart](https://dart.dev/effective-dart/design#avoid-defining-custom-equality-for-mutable-classes):
**AVOID** overloading operator == and hashCode on classes not marked `@immutable`.
If a class is not immutable, overloading `operator ==` and `hashCode` can
lead to unpredictable and undesirable behavior when used in collections.
**BAD:**
```dart
class B {
String key;
const B(this.key);
@override
operator ==(other) => other is B && other.key == key;
@override
int get hashCode => key.hashCode;
}
```
**GOOD:**
```dart
@immutable
class A {
final String key;
const A(this.key);
@override
operator ==(other) => other is A && other.key == key;
@override
int get hashCode => key.hashCode;
}
```
NOTE: The lint checks the use of the `@immutable` annotation, and will trigger
even if the class is otherwise not mutable. Thus:
**BAD:**
```dart
class C {
final String key;
const C(this.key);
@override
operator ==(other) => other is C && other.key == key;
@override
int get hashCode => key.hashCode;
}
```
avoid_escaping_inner_quotes:
problemMessage: "Unnecessary escape of '{0}'."
correctionMessage: "Try changing the outer quotes to '{1}'."
addedIn: "2.8"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
Avoid escaping inner quotes by converting surrounding quotes.
**BAD:**
```dart
var s = 'It\'s not fun';
```
**GOOD:**
```dart
var s = "It's not fun";
```
avoid_field_initializers_in_const_classes:
problemMessage: "Fields in 'const' classes should not have initializers."
correctionMessage: "Try converting the field to a getter or initialize the field in the constructors."
addedIn: "2.0"
# TODO(srawlins): This rule has nothing to do with style. It is to reduce
# runtime memory usage. But we don't have a Category for that yet.
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**AVOID** field initializers in const classes.
Instead of `final x = const expr;`, you should write `get x => const expr;` and
not allocate a useless field. As of April 2018 this is true for the VM, but not
for code that will be compiled to JS.
**BAD:**
```dart
class A {
final a = const [];
const A();
}
```
**GOOD:**
```dart
class A {
get a => const [];
const A();
}
```
avoid_final_parameters:
problemMessage: "Parameters should not be marked as 'final'."
correctionMessage: "Try removing the keyword 'final'."
addedIn: "2.16"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**AVOID** declaring parameters as `final`.
Declaring parameters as `final` can lead to unnecessarily verbose code,
especially when using the "parameter_assignments" rule.
**BAD:**
```dart
void goodParameter(final String label) { // LINT
print(label);
}
```
**GOOD:**
```dart
void badParameter(String label) { // OK
print(label);
}
```
**BAD:**
```dart
void goodExpression(final int value) => print(value); // LINT
```
**GOOD:**
```dart
void badExpression(int value) => print(value); // OK
```
**BAD:**
```dart
[1, 4, 6, 8].forEach((final value) => print(value + 2)); // LINT
```
**GOOD:**
```dart
[1, 4, 6, 8].forEach((value) => print(value + 2)); // OK
```
avoid_function_literals_in_foreach_calls:
problemMessage: "Function literals shouldn't be passed to 'forEach'."
correctionMessage: "Try using a 'for' loop."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the argument to
`Iterable.forEach` is a closure.
#### Example
The following code produces this diagnostic because the argument to the
invocation of `forEach` is a closure:
```dart
void f(Iterable<String> s) {
s.[!forEach!]((e) => print(e));
}
```
#### Common fixes
If the closure can be replaced by a tear-off, then replace the closure:
```dart
void f(Iterable<String> s) {
s.forEach(print);
}
```
If the closure can't be replaced by a tear-off, then use a `for` loop to
iterate over the elements:
```dart
void f(Iterable<String> s) {
for (var e in s) {
print(e);
}
}
```
deprecatedDetails: |-
**AVOID** using `forEach` with a function literal.
The `for` loop enables a developer to be clear and explicit as to their intent.
A return in the body of the `for` loop returns from the body of the function,
where as a return in the body of the `forEach` closure only returns a value
for that iteration of the `forEach`. The body of a `for` loop can contain
`await`s, while the closure body of a `forEach` cannot.
**BAD:**
```dart
people.forEach((person) {
...
});
```
**GOOD:**
```dart
for (var person in people) {
...
}
```
avoid_futureor_void:
problemMessage: "Don't use the type 'FutureOr<void>'."
correctionMessage: "Try using 'Future<void>?' or 'void'."
addedIn: "3.6-wip"
categories: [errorProne, unintentional]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the type `FutureOr<void>`
is used as the type of a result (to be precise: it is used in a
position that isn't contravariant). The type `FutureOr<void>` is
problematic because it may appear to encode that a result is either a
`Future<void>`, or the result should be discarded (when it is
`void`). However, there is no safe way to detect whether we have one
or the other case because an expression of type `void` can evaluate
to any object whatsoever, including a future of any type.
It is also conceptually unsound to have a type whose meaning is
something like "ignore this object; also, take a look because it
might be a future".
An exception is made for contravariant occurrences of the type
`FutureOr<void>` (e.g., for the type of a formal parameter), and no
warning is emitted for these occurrences. The reason for this
exception is that the type does not describe a result, it describes a
constraint on a value provided by others. Similarly, an exception is
made for type alias declarations, because they may well be used in a
contravariant position (e.g., as the type of a formal
parameter). Hence, in type alias declarations, only the type
parameter bounds are checked.
#### Example
```dart
import 'dart:async';
[!FutureOr<void>!] m() => null;
```
#### Common fixes
A replacement for the type `FutureOr<void>` which is often useful is
`Future<void>?`. This type encodes that a result is either a
`Future<void>` or it is null, and there is no ambiguity at run time
since no object can have both types.
It may not always be possible to use the type `Future<void>?` as a
replacement for the type `FutureOr<void>`, because the latter is a
supertype of all types, and the former is not. In this case it may be a
useful remedy to replace `FutureOr<void>` by the type `void`.
deprecatedDetails: |-
**AVOID** using `FutureOr<void>` as the type of a result. This type is
problematic because it may appear to encode that a result is either a
`Future<void>`, or the result should be discarded (when it is `void`).
However, there is no safe way to detect whether we have one or the other
case (because an expression of type `void` can evaluate to any object
whatsoever, including a future of any type).
It is also conceptually unsound to have a type whose meaning is something
like "ignore this object; also, take a look because it might be a future".
An exception is made for contravariant occurrences of the type
`FutureOr<void>` (e.g., for the type of a formal parameter), and no
warning is emitted for these occurrences. The reason for this exception
is that the type does not describe a result, it describes a constraint
on a value provided by others. Similarly, an exception is made for type
alias declarations, because they may well be used in a contravariant
position (e.g., as the type of a formal parameter). Hence, in type alias
declarations, only the type parameter bounds are checked.
A replacement for the type `FutureOr<void>` which is often useful is
`Future<void>?`. This type encodes that the result is either a
`Future<void>` or it is null, and there is no ambiguity at run time
since no object can have both types.
It may not always be possible to use the type `Future<void>?` as a
replacement for the type `FutureOr<void>`, because the latter is a
supertype of all types, and the former is not. In this case it may be a
useful remedy to replace `FutureOr<void>` by the type `void`.
**BAD:**
```dart
FutureOr<void> m() {...}
```
**GOOD:**
```dart
Future<void>? m() {...}
```
**This rule is experimental.** It is being evaluated, and it may be changed
or removed. Feedback on its behavior is welcome! The main issue is here:
https://github.com/dart-lang/linter/issues/4622
avoid_implementing_value_types:
problemMessage: "Classes that override '==' should not be implemented."
correctionMessage: "Try removing the class from the 'implements' clause."
addedIn: "2.1"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DON'T** implement classes that override `==`.
The `==` operator is contractually required to be an equivalence relation;
that is, symmetrically for all objects `o1` and `o2`, `o1 == o2` and `o2 == o1`
must either both be true, or both be false.
> _NOTE_: Dart does not have true _value types_, so instead we consider a class
> that implements `==` as a _proxy_ for identifying value types.
When using `implements`, you do not inherit the method body of `==`, making it
nearly impossible to follow the contract of `==`. Classes that override `==`
typically are usable directly in tests _without_ creating mocks or fakes as
well. For example, for a given class `Size`:
```dart
class Size {
final int inBytes;
const Size(this.inBytes);
@override
bool operator ==(Object other) => other is Size && other.inBytes == inBytes;
@override
int get hashCode => inBytes.hashCode;
}
```
**BAD:**
```dart
class CustomSize implements Size {
final int inBytes;
const CustomSize(this.inBytes);
int get inKilobytes => inBytes ~/ 1000;
}
```
**BAD:**
```dart
import 'package:test/test.dart';
import 'size.dart';
class FakeSize implements Size {
int inBytes = 0;
}
void main() {
test('should not throw on a size >1Kb', () {
expect(() => someFunction(FakeSize()..inBytes = 1001), returnsNormally);
});
}
```
**GOOD:**
```dart
class ExtendedSize extends Size {
ExtendedSize(int inBytes) : super(inBytes);
int get inKilobytes => inBytes ~/ 1000;
}
```
**GOOD:**
```dart
import 'package:test/test.dart';
import 'size.dart';
void main() {
test('should not throw on a size >1Kb', () {
expect(() => someFunction(Size(1001)), returnsNormally);
});
}
```
avoid_init_to_null:
problemMessage: "Redundant initialization to 'null'."
correctionMessage: "Try removing the initializer."
addedIn: "2.0"
categories: [brevity, effectiveDart, style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a nullable variable is
explicitly initialized to `null`. The variable can be a local variable,
field, or top-level variable.
A variable or field that isn't explicitly initialized automatically gets
initialized to `null`. There's no concept of "uninitialized memory" in
Dart.
#### Example
The following code produces this diagnostic because the variable `f` is
explicitly initialized to `null`:
```dart
class C {
int? [!f = null!];
void m() {
if (f != null) {
print(f);
}
}
}
```
#### Common fixes
Remove the unnecessary initialization:
```dart
class C {
int? f;
void m() {
if (f != null) {
print(f);
}
}
}
```
deprecatedDetails: |-
From [Effective Dart](https://dart.dev/effective-dart/usage#dont-explicitly-initialize-variables-to-null):
**DON'T** explicitly initialize variables to `null`.
If a variable has a non-nullable type or is `final`,
Dart reports a compile error if you try to use it
before it has been definitely initialized.
If the variable is nullable and not `const` or `final`,
then it is implicitly initialized to `null` for you.
There's no concept of "uninitialized memory" in Dart
and no need to explicitly initialize a variable to `null` to be "safe".
Adding `= null` is redundant and unneeded.
**BAD:**
```dart
Item? bestDeal(List<Item> cart) {
Item? bestItem = null;
for (final item in cart) {
if (bestItem == null || item.price < bestItem.price) {
bestItem = item;
}
}
return bestItem;
}
```
**GOOD:**
```dart
Item? bestDeal(List<Item> cart) {
Item? bestItem;
for (final item in cart) {
if (bestItem == null || item.price < bestItem.price) {
bestItem = item;
}
}
return bestItem;
}
```
avoid_js_rounded_ints:
problemMessage: "Integer literal can't be represented exactly when compiled to JavaScript."
correctionMessage: "Try using a 'BigInt' to represent the value."
addedIn: "2.0"
categories: [errorProne, web]
hasPublishedDocs: false
deprecatedDetails: |-
**AVOID** integer literals that cannot be represented exactly when compiled to
JavaScript.
When a program is compiled to JavaScript `int` and `double` become JavaScript
Numbers. Too large integers (`value < Number.MIN_SAFE_INTEGER` or
`value > Number.MAX_SAFE_INTEGER`) may be rounded to the closest Number value.
For instance `1000000000000000001` cannot be represented exactly as a JavaScript
Number, so `1000000000000000000` will be used instead.
**BAD:**
```dart
int value = 9007199254740995;
```
**GOOD:**
```dart
BigInt value = BigInt.parse('9007199254740995');
```
avoid_multiple_declarations_per_line:
problemMessage: "Multiple variables declared on a single line."
correctionMessage: "Try splitting the variable declarations into multiple lines."
addedIn: "2.13"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DON'T** declare multiple variables on a single line.
**BAD:**
```dart
String? foo, bar, baz;
```
**GOOD:**
```dart
String? foo;
String? bar;
String? baz;
```
avoid_null_checks_in_equality_operators:
problemMessage: "Unnecessary null comparison in implementation of '=='."
correctionMessage: "Try removing the comparison."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DON'T** check for `null` in custom `==` operators.
As `null` is a special value, no instance of any class (other than `Null`) can
be equivalent to it. Thus, it is redundant to check whether the other instance
is `null`.
**BAD:**
```dart
class Person {
final String? name;
@override
operator ==(Object? other) =>
other != null && other is Person && name == other.name;
}
```
**GOOD:**
```dart
class Person {
final String? name;
@override
operator ==(Object? other) => other is Person && name == other.name;
}
```
avoid_positional_boolean_parameters:
problemMessage: "'bool' parameters should be named parameters."
correctionMessage: "Try converting the parameter to a named parameter."
addedIn: "2.0"
categories: [effectiveDart, style]
hasPublishedDocs: false
deprecatedDetails: |-
From [Effective Dart](https://dart.dev/effective-dart/design#avoid-positional-boolean-parameters):
**AVOID** positional boolean parameters.
Positional boolean parameters are a bad practice because they are very
ambiguous. Using named boolean parameters is much more readable because it
inherently describes what the boolean value represents.
**BAD:**
```dart
Task(true);
Task(false);
ListBox(false, true, true);
Button(false);
```
**GOOD:**
```dart
Task.oneShot();
Task.repeating();
ListBox(scroll: true, showScrollbars: true);
Button(ButtonState.enabled);
```
avoid_print:
problemMessage: "Don't invoke 'print' in production code."
correctionMessage: "Try using a logging framework."
addedIn: "2.5"
categories: [unintentional]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the function `print` is invoked
in production code.
#### Example
The following code produces this diagnostic because the function `print`
can't be invoked in production:
```dart
void f(int x) {
[!print!]('x = $x');
}
```
#### Common fixes
If you're writing code that uses Flutter, then use the function
[`debugPrint`][debugPrint], guarded by a test
using [`kDebugMode`][kDebugMode]:
```dart
import 'package:flutter/foundation.dart';
void f(int x) {
if (kDebugMode) {
debugPrint('x = $x');
}
}
```
If you're writing code that doesn't use Flutter, then use a logging
service, such as [`package:logging`][package-logging], to write the
information.
deprecatedDetails: |-
**DO** avoid `print` calls in production code.
For production code, consider using a logging framework.
If you are using Flutter, you can use `debugPrint`
or surround `print` calls with a check for `kDebugMode`
**BAD:**
```dart
void f(int x) {
print('debug: $x');
...
}
```
**GOOD:**
```dart
void f(int x) {
debugPrint('debug: $x');
...
}
```
**GOOD:**
```dart
void f(int x) {
log('log: $x');
...
}
```
**GOOD:**
```dart
void f(int x) {
if (kDebugMode) {
print('debug: $x');
}
...
}
```
avoid_private_typedef_functions:
problemMessage: "The typedef is unnecessary because it is only used in one place."
correctionMessage: "Try inlining the type or using it in other places."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**AVOID** private typedef functions used only once. Prefer inline function
syntax.
**BAD:**
```dart
typedef void _F();
m(_F f);
```
**GOOD:**
```dart
m(void Function() f);
```
avoid_redundant_argument_values:
problemMessage: "The value of the argument is redundant because it matches the default value."
correctionMessage: "Try removing the argument."
addedIn: "2.8"
categories: [brevity, style]
hasPublishedDocs: false
deprecatedDetails: |-
**DON'T** pass an argument that matches the corresponding parameter's default
value.
Note that a method override can change the default value of a parameter, so that
an argument may be equal to one default value, and not the other. Take, for
example, two classes, `A` and `B` where `B` is a subclass of `A`, and `B`
overrides a method declared on `A`, and that method has a parameter with one
default value in `A`'s declaration, and a different default value in `B`'s
declaration. If the static type of the target of the invoked method is `B`, and
`B`'s default value matches the argument, then the argument can be omitted (and
if the argument value is different, then a lint is not reported). If, however,
the static type of the target of the invoked method is `A`, then a lint may be
reported, but we cannot know statically which method is invoked, so the reported
lint may be a false positive. Such cases can be ignored inline with a comment
like `// ignore: avoid_redundant_argument_values`.
**BAD:**
```dart
void f({bool valWithDefault = true, bool? val}) {
...
}
void main() {
f(valWithDefault: true);
}
```
**GOOD:**
```dart
void f({bool valWithDefault = true, bool? val}) {
...
}
void main() {
f(valWithDefault: false);
f();
}
```
avoid_relative_lib_imports:
problemMessage: "Can't use a relative path to import a library in 'lib'."
correctionMessage: "Try fixing the relative path or changing the import to a 'package:' import."
addedIn: "2.0"
categories: [errorProne]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the URI in an `import`
directive has `lib` in the path.
#### Example
Assuming that there is a file named `a.dart` in the `lib` directory:
```dart
%uri="lib/a.dart"
class A {}
```
The following code produces this diagnostic because the import contains a
path that includes `lib`:
```dart
import [!'../lib/a.dart'!];
```
#### Common fixes
Rewrite the import to not include `lib` in the URI:
```dart
import 'a.dart';
```
deprecatedDetails: |-
**DO** avoid relative imports for files in `lib/`.
When mixing relative and absolute imports it's possible to create confusion
where the same member gets imported in two different ways. An easy way to avoid
that is to ensure you have no relative imports that include `lib/` in their
paths.
You can also use 'always_use_package_imports' to disallow relative imports
between files within `lib/`.
**BAD:**
```dart
import 'package:foo/bar.dart';
import '../lib/baz.dart';
...
```
**GOOD:**
```dart
import 'package:foo/bar.dart';
import 'baz.dart';
...
```
avoid_renaming_method_parameters:
problemMessage: "The parameter name '{0}' doesn't match the name '{1}' in the overridden method."
correctionMessage: "Try changing the name to '{1}'."
addedIn: "2.0"
categories: [documentationCommentMaintenance]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a method that overrides a
method from a superclass changes the names of the parameters.
#### Example
The following code produces this diagnostic because the parameter of the
method `m` in `B` is named `b`, which is different from the name of the
overridden method's parameter in `A`:
```dart
class A {
void m(int a) {}
}
class B extends A {
@override
void m(int [!b!]) {}
}
```
#### Common fixes
Rename one of the parameters so that they are the same:
```dart
class A {
void m(int a) {}
}
class B extends A {
@override
void m(int a) {}
}
```
deprecatedDetails: |-
**DON'T** rename parameters of overridden methods.
Methods that override another method, but do not have their own documentation
comment, will inherit the overridden method's comment when `dart doc` produces
documentation. If the inherited method contains the name of the parameter (in
square brackets), then `dart doc` cannot link it correctly.
**BAD:**
```dart
abstract class A {
m(a);
}
abstract class B extends A {
m(b);
}
```
**GOOD:**
```dart
abstract class A {
m(a);
}
abstract class B extends A {
m(a);
}
```
avoid_return_types_on_setters:
problemMessage: "Unnecessary return type on a setter."
correctionMessage: "Try removing the return type."
addedIn: "2.0"
categories: [brevity, style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a setter has an explicit return
type.
Setters never return a value, so declaring the return type of one is
redundant.
#### Example
The following code produces this diagnostic because the setter `s` has an
explicit return type (`void`):
```dart
[!void!] set s(int p) {}
```
#### Common fixes
Remove the return type:
```dart
set s(int p) {}
```
deprecatedDetails: |-
**AVOID** return types on setters.
As setters do not return a value, declaring the return type of one is redundant.
**BAD:**
```dart
void set speed(int ms);
```
**GOOD:**
```dart
set speed(int ms);
```
avoid_returning_null:
addedIn: "2.0"
removedIn: "3.3"
deprecatedDetails: |-
NOTE: This rule is removed in Dart 3.3.0; it is no longer functional.
**AVOID** returning null from members whose return type is bool, double, int,
or num.
Functions that return primitive types such as bool, double, int, and num are
generally expected to return non-nullable values. Thus, returning null where a
primitive type was expected can lead to runtime exceptions.
**BAD:**
```dart
bool getBool() => null;
num getNum() => null;
int getInt() => null;
double getDouble() => null;
```
**GOOD:**
```dart
bool getBool() => false;
num getNum() => -1;
int getInt() => -1;
double getDouble() => -1.0;
```
avoid_returning_null_for_future:
addedIn: "2.1"
removedIn: "3.3"
deprecatedDetails: |-
NOTE: This rule is removed in Dart 3.3.0; it is no longer functional.
**AVOID** returning null for Future.
It is almost always wrong to return `null` for a `Future`. Most of the time the
developer simply forgot to put an `async` keyword on the function.
avoid_returning_null_for_void_from_function:
sharedName: avoid_returning_null_for_void
problemMessage: "Don't return 'null' from a function with a return type of 'void'."
correctionMessage: "Try removing the 'null'."
addedIn: "2.1"
categories: [style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a function that has a return
type of `void` explicitly returns `null`.
#### Example
The following code produces this diagnostic because there is an explicit
return of `null` in a `void` function:
```dart
void f() {
[!return null;!]
}
```
#### Common fixes
Remove the unnecessary explicit `null`:
```dart
void f() {
return;
}
```
deprecatedDetails: |-
**AVOID** returning `null` for `void`.
In a large variety of languages `void` as return type is used to indicate that
a function doesn't return anything. Dart allows returning `null` in functions
with `void` return type but it also allow using `return;` without specifying any
value. To have a consistent way you should not return `null` and only use an
empty return.
**BAD:**
```dart
void f1() {
return null;
}
Future<void> f2() async {
return null;
}
```
**GOOD:**
```dart
void f1() {
return;
}
Future<void> f2() async {
return;
}
```
avoid_returning_null_for_void_from_method:
sharedName: avoid_returning_null_for_void
problemMessage: "Don't return 'null' from a method with a return type of 'void'."
correctionMessage: "Try removing the 'null'."
hasPublishedDocs: true
avoid_returning_this:
problemMessage: "Don't return 'this' from a method."
correctionMessage: "Try changing the return type to 'void' and removing the return."
addedIn: "2.0"
categories: [effectiveDart, style]
hasPublishedDocs: false
deprecatedDetails: |-
From [Effective Dart](https://dart.dev/effective-dart/design#avoid-returning-this-from-methods-just-to-enable-a-fluent-interface):
**AVOID** returning this from methods just to enable a fluent interface.
Returning `this` from a method is redundant; Dart has a cascade operator which
allows method chaining universally.
Returning `this` is allowed for:
- operators
- methods with a return type different of the current class
- methods defined in parent classes / mixins or interfaces
- methods defined in extensions
**BAD:**
```dart
var buffer = StringBuffer()
.write('one')
.write('two')
.write('three');
```
**GOOD:**
```dart
var buffer = StringBuffer()
..write('one')
..write('two')
..write('three');
```
avoid_setters_without_getters:
problemMessage: "Setter has no corresponding getter."
correctionMessage: "Try adding a corresponding getter or removing the setter."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DON'T** define a setter without a corresponding getter.
Defining a setter without defining a corresponding getter can lead to logical
inconsistencies. Doing this could allow you to set a property to some value,
but then upon observing the property's value, it could easily be different.
**BAD:**
```dart
class Bad {
int l, r;
set length(int newLength) {
r = l + newLength;
}
}
```
**GOOD:**
```dart
class Good {
int l, r;
int get length => r - l;
set length(int newLength) {
r = l + newLength;
}
}
```
avoid_shadowing_type_parameters:
problemMessage: "The type parameter '{0}' shadows a type parameter from the enclosing {1}."
correctionMessage: "Try renaming one of the type parameters."
addedIn: "2.1"
categories: [errorProne]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a type parameter shadows a type
parameter from an enclosing declaration.
Shadowing a type parameter with a different type parameter can lead to
subtle bugs that are difficult to debug.
#### Example
The following code produces this diagnostic because the type parameter `T`
defined by the method `m` shadows the type parameter `T` defined by the
class `C`:
```dart
class C<T> {
void m<[!T!]>() {}
}
```
#### Common fixes
Rename one of the type parameters:
```dart
class C<T> {
void m<S>() {}
}
```
deprecatedDetails: |-
**AVOID** shadowing type parameters.
**BAD:**
```dart
class A<T> {
void fn<T>() {}
}
```
**GOOD:**
```dart
class A<T> {
void fn<U>() {}
}
```
avoid_single_cascade_in_expression_statements:
problemMessage: "Unnecessary cascade expression."
correctionMessage: "Try using the operator '{0}'."
addedIn: "2.0"
categories: [brevity, style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a single cascade operator is
used and the value of the expression isn't being used for anything (such
as being assigned to a variable or being passed as an argument).
#### Example
The following code produces this diagnostic because the value of the
cascade expression `s..length` isn't being used:
```dart
void f(String s) {
[!s..length!];
}
```
#### Common fixes
Replace the cascade operator with a simple access operator:
```dart
void f(String s) {
s.length;
}
```
deprecatedDetails: |-
**AVOID** single cascade in expression statements.
**BAD:**
```dart
o..m();
```
**GOOD:**
```dart
o.m();
```
avoid_slow_async_io:
problemMessage: "Use of an async 'dart:io' method."
correctionMessage: "Try using the synchronous version of the method."
addedIn: "2.0"
categories: [nonPerformant]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when an asynchronous file I/O method
with a synchronous equivalent is used.
The following are the specific flagged asynchronous methods:
- `Directory.exists`
- `Directory.stat`
- `File.lastModified`
- `File.exists`
- `File.stat`
- `FileSystemEntity.isDirectory`
- `FileSystemEntity.isFile`
- `FileSystemEntity.isLink`
- `FileSystemEntity.type`
#### Example
The following code produces this diagnostic because the async method
`exists` is invoked:
```dart
import 'dart:io';
Future<void> g(File f) async {
await [!f.exists()!];
}
```
#### Common fixes
Use the synchronous version of the method:
```dart
import 'dart:io';
void g(File f) {
f.existsSync();
}
```
deprecatedDetails: |-
**AVOID** using the following asynchronous file I/O methods because they are
much slower than their synchronous counterparts.
* `Directory.exists`
* `Directory.stat`
* `File.lastModified`
* `File.exists`
* `File.stat`
* `FileSystemEntity.isDirectory`
* `FileSystemEntity.isFile`
* `FileSystemEntity.isLink`
* `FileSystemEntity.type`
**BAD:**
```dart
import 'dart:io';
Future<Null> someFunction() async {
var file = File('/path/to/my/file');
var now = DateTime.now();
if ((await file.lastModified()).isBefore(now)) print('before'); // LINT
}
```
**GOOD:**
```dart
import 'dart:io';
Future<Null> someFunction() async {
var file = File('/path/to/my/file');
var now = DateTime.now();
if (file.lastModifiedSync().isBefore(now)) print('before'); // OK
}
```
avoid_type_to_string:
problemMessage: "Using 'toString' on a 'Type' is not safe in production code."
correctionMessage: "Try a normal type check or compare the 'runtimeType' directly."
addedIn: "2.12"
categories: [unintentional]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the method `toString` is
invoked on a value whose static type is `Type`.
#### Example
The following code produces this diagnostic because the method `toString`
is invoked on the `Type` returned by `runtimeType`:
```dart
bool isC(Object o) => o.runtimeType.[!toString!]() == 'C';
class C {}
```
#### Common fixes
If it's essential that the type is exactly the same, then use an explicit
comparison:
```dart
bool isC(Object o) => o.runtimeType == C;
class C {}
```
If it's alright for instances of subtypes of the type to return `true`,
then use a type check:
```dart
bool isC(Object o) => o is C;
class C {}
```
deprecatedDetails: |-
**DO** avoid calls to <Type>.toString() in production code, since it does not
contractually return the user-defined name of the Type (or underlying class).
Development-mode compilers where code size is not a concern use the full name,
but release-mode compilers often choose to minify these symbols.
**BAD:**
```dart
void bar(Object other) {
if (other.runtimeType.toString() == 'Bar') {
doThing();
}
}
Object baz(Thing myThing) {
return getThingFromDatabase(key: myThing.runtimeType.toString());
}
```
**GOOD:**
```dart
void bar(Object other) {
if (other is Bar) {
doThing();
}
}
class Thing {
String get thingTypeKey => ...
}
Object baz(Thing myThing) {
return getThingFromDatabase(key: myThing.thingTypeKey);
}
```
avoid_types_as_parameter_names:
problemMessage: "The parameter name '{0}' matches a visible type name."
correctionMessage: "Try adding a name for the parameter or changing the parameter name to not match an existing type."
addedIn: "2.0"
categories: [unintentional]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the name of a parameter in a
parameter list is the same as a visible type (a type whose name is in
scope).
This often indicates that the intended name of the parameter is missing,
causing the name of the type to be used as the name of the parameter
rather than the type of the parameter. Even when that's not the case (the
name of the parameter is intentional), the name of the parameter will
shadow the existing type, which can lead to bugs that are difficult to
diagnose.
#### Example
The following code produces this diagnostic because the function `f` has a
parameter named `int`, which shadows the type `int` from `dart:core`:
```dart
void f([!int!]) {}
```
#### Common fixes
If the parameter name is missing, then add a name for the parameter:
```dart
void f(int x) {}
```
If the parameter is intended to have an implicit type of `dynamic`, then
rename the parameter so that it doesn't shadow the name of any visible type:
```dart
void f(int_) {}
```
deprecatedDetails: |-
**AVOID** using a parameter name that is the same as an existing type.
**BAD:**
```dart
m(f(int));
```
**GOOD:**
```dart
m(f(int v));
```
avoid_types_on_closure_parameters:
problemMessage: "Unnecessary type annotation on a function expression parameter."
correctionMessage: "Try removing the type annotation."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**AVOID** annotating types for function expression parameters.
Annotating types for function expression parameters is usually unnecessary
because the parameter types can almost always be inferred from the context,
thus making the practice redundant.
**BAD:**
```dart
var names = people.map((Person person) => person.name);
```
**GOOD:**
```dart
var names = people.map((person) => person.name);
```
avoid_unnecessary_containers:
problemMessage: "Unnecessary instance of 'Container'."
correctionMessage: "Try removing the 'Container' (but not its children) from the widget tree."
addedIn: "2.7"
categories: [flutter, style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a widget tree contains an
instance of `Container` and the only argument to the constructor is
`child:`.
#### Example
The following code produces this diagnostic because the invocation of the
`Container` constructor only has a `child:` argument:
```dart
import 'package:flutter/material.dart';
Widget buildRow() {
return [!Container!](
child: Row(
children: [
Text('a'),
Text('b'),
],
)
);
}
```
#### Common fixes
If you intended to provide other arguments to the constructor, then add
them:
```dart
import 'package:flutter/material.dart';
Widget buildRow() {
return Container(
color: Colors.red.shade100,
child: Row(
children: [
Text('a'),
Text('b'),
],
)
);
}
```
If no other arguments are needed, then unwrap the child widget:
```dart
import 'package:flutter/material.dart';
Widget buildRow() {
return Row(
children: [
Text('a'),
Text('b'),
],
);
}
```
deprecatedDetails: |-
**AVOID** wrapping widgets in unnecessary containers.
Wrapping a widget in `Container` with no other parameters set has no effect
and makes code needlessly more complex.
**BAD:**
```dart
Widget buildRow() {
return Container(
child: Row(
children: <Widget>[
const MyLogo(),
const Expanded(
child: Text('...'),
),
],
)
);
}
```
**GOOD:**
```dart
Widget buildRow() {
return Row(
children: <Widget>[
const MyLogo(),
const Expanded(
child: Text('...'),
),
],
);
}
```
avoid_unstable_final_fields:
addedIn: "3.3"
removedIn: "3.3"
deprecatedDetails: |-
This rule has been removed.
avoid_unused_constructor_parameters:
problemMessage: "The parameter '{0}' is not used in the constructor."
correctionMessage: "Try using the parameter or removing it."
addedIn: "2.0"
# TODO(srawlins): This isn't even just about unintentional syntax; unused
# parameters can represent code bloat.
categories: [unintentional]
hasPublishedDocs: false
deprecatedDetails: |-
**AVOID** defining unused parameters in constructors.
**BAD:**
```dart
class BadOne {
BadOne(int unusedParameter, [String unusedPositional]);
}
class BadTwo {
int c;
BadTwo(int a, int b, int x) {
c = a + b;
}
}
```
avoid_void_async:
problemMessage: "An 'async' function should have a 'Future' return type when it doesn't return a value."
correctionMessage: "Try changing the return type."
addedIn: "2.1"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** mark `async` functions as returning `Future<void>`.
When declaring an `async` method or function which does not return a value,
declare that it returns `Future<void>` and not just `void`.
**BAD:**
```dart
void f() async {}
void f2() async => null;
```
**GOOD:**
```dart
Future<void> f() async {}
Future<void> f2() async => null;
```
**EXCEPTION:**
An exception is made for top-level `main` functions, where the `Future`
annotation *can* (and generally should) be dropped in favor of `void`.
**GOOD:**
```dart
Future<void> f() async {}
void main() async {
await f();
}
```
avoid_web_libraries_in_flutter:
problemMessage: "Don't use web-only libraries outside Flutter web plugins."
correctionMessage: "Try finding a different library for your needs."
addedIn: "2.6"
categories: [errorProne, flutter, web]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a library in a package that
isn't a web plugin contains an import of a web-only library:
- `dart:html`
- `dart:js`
- `dart:js_util`
- `dart:js_interop`
- `dart:js_interop_unsafe`
- `package:js`
- `package:web`
#### Example
When found in a package that isn't a web plugin, the following code
produces this diagnostic because it imports `dart:html`:
```dart
import [!'dart:html'!];
import 'package:flutter/material.dart';
class C {}
```
#### Common fixes
If the package isn't intended to be a web plugin, then remove the import:
```dart
import 'package:flutter/material.dart';
class C {}
```
If the package is intended to be a web plugin, then add the following
lines to the `pubspec.yaml` file of the package:
```yaml
flutter:
plugin:
platforms:
web:
pluginClass: HelloPlugin
fileName: hello_web.dart
```
See [Developing packages & plugins](https://flutter.dev/to/develop-packages)
for more information.
deprecatedDetails: |-
**AVOID** using web libraries, `dart:html`, `dart:js` and
`dart:js_util` in Flutter packages that are not web plugins. These libraries are
not supported outside of a web context; functionality that depends on them will
fail at runtime in Flutter mobile, and their use is generally discouraged in
Flutter web.
Web library access *is* allowed in:
* plugin packages that declare `web` as a supported context
otherwise, imports of `dart:html`, `dart:js` and `dart:js_util` are disallowed.
await_only_futures:
problemMessage: "Uses 'await' on an instance of '{0}', which is not a subtype of 'Future'."
correctionMessage: "Try removing the 'await' or changing the expression."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the expression after `await`
has any type other than `Future<T>`, `FutureOr<T>`, `Future<T>?`,
`FutureOr<T>?` or `dynamic`.
An exception is made for the expression `await null` because it is a
common way to introduce a microtask delay.
Unless the expression can produce a `Future`, the `await` is unnecessary
and can cause a reader to assume a level of asynchrony that doesn't exist.
#### Example
The following code produces this diagnostic because the expression after
`await` has the type `int`:
```dart
void f() async {
[!await!] 23;
}
```
#### Common fixes
Remove the `await`:
```dart
void f() async {
23;
}
```
deprecatedDetails: |-
**AVOID** using await on anything which is not a future.
Await is allowed on the types: `Future<X>`, `FutureOr<X>`, `Future<X>?`,
`FutureOr<X>?` and `dynamic`.
Further, using `await null` is specifically allowed as a way to introduce a
microtask delay.
**BAD:**
```dart
main() async {
print(await 23);
}
```
**GOOD:**
```dart
main() async {
await null; // If a delay is really intended.
print(23);
}
```
camel_case_extensions:
problemMessage: "The extension name '{0}' isn't an UpperCamelCase identifier."
correctionMessage: "Try changing the name to follow the UpperCamelCase style."
addedIn: "2.6"
categories: [effectiveDart, style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the name of an extension
doesn't use the 'UpperCamelCase' naming convention.
#### Example
The following code produces this diagnostic because the name of the
extension doesn't start with an uppercase letter:
```dart
extension [!stringExtension!] on String {}
```
#### Common fixes
If the extension needs to have a name (needs to be visible outside this
library), then rename the extension so that it has a valid name:
```dart
extension StringExtension on String {}
```
If the extension doesn't need to have a name, then remove the name of the
extension:
```dart
extension on String {}
```
deprecatedDetails: |-
From [Effective Dart](https://dart.dev/effective-dart/style#do-name-extensions-using-uppercamelcase):
**DO** name extensions using `UpperCamelCase`.
Extensions should capitalize the first letter of each word (including
the first word), and use no separators.
**GOOD:**
```dart
extension MyFancyList<T> on List<T> {
// ...
}
extension SmartIterable<T> on Iterable<T> {
// ...
}
```
camel_case_types:
problemMessage: "The type name '{0}' isn't an UpperCamelCase identifier."
correctionMessage: "Try changing the name to follow the UpperCamelCase style."
addedIn: "2.0"
categories: [effectiveDart, style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the name of a type (a class,
mixin, enum, or typedef) doesn't use the 'UpperCamelCase' naming
convention.
#### Example
The following code produces this diagnostic because the name of the class
doesn't start with an uppercase letter:
```dart
class [!c!] {}
```
#### Common fixes
Rename the type so that it has a valid name:
```dart
class C {}
```
deprecatedDetails: |-
From [Effective Dart](https://dart.dev/effective-dart/style#do-name-types-using-uppercamelcase):
**DO** name types using UpperCamelCase.
Classes and typedefs should capitalize the first letter of each word (including
the first word), and use no separators.
**GOOD:**
```dart
class SliderMenu {
// ...
}
class HttpRequest {
// ...
}
typedef num Adder(num x, num y);
```
cancel_subscriptions:
problemMessage: "Uncancelled instance of 'StreamSubscription'."
correctionMessage: "Try invoking 'cancel' in the function in which the 'StreamSubscription' was created."
addedIn: "2.0"
categories: [errorProne, memoryLeaks]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when an instance of
`StreamSubscription` is created but the method `cancel` isn't invoked.
#### Example
The following code produces this diagnostic because the `subscription`
isn't canceled:
```dart
import 'dart:async';
void f(Stream stream) {
// ignore: unused_local_variable
var [!subscription = stream.listen((_) {})!];
}
```
#### Common fixes
Cancel the subscription:
```dart
import 'dart:async';
void f(Stream stream) {
var subscription = stream.listen((_) {});
subscription.cancel();
}
```
deprecatedDetails: |-
**DO** invoke `cancel` on instances of `dart:async` `StreamSubscription`.
Cancelling instances of StreamSubscription prevents memory leaks and unexpected
behavior.
**BAD:**
```dart
class A {
StreamSubscription _subscriptionA; // LINT
void init(Stream stream) {
_subscriptionA = stream.listen((_) {});
}
}
```
**BAD:**
```dart
void someFunction() {
StreamSubscription _subscriptionF; // LINT
}
```
**GOOD:**
```dart
class B {
StreamSubscription _subscriptionB; // OK
void init(Stream stream) {
_subscriptionB = stream.listen((_) {});
}
void dispose(filename) {
_subscriptionB.cancel();
}
}
```
**GOOD:**
```dart
void someFunctionOK() {
StreamSubscription _subscriptionB; // OK
_subscriptionB.cancel();
}
```
**Known limitations**
This rule does not track all patterns of StreamSubscription instantiations and
cancellations. See [linter#317](https://github.com/dart-lang/linter/issues/317)
for more information.
cascade_invocations:
problemMessage: "Unnecessary duplication of receiver."
correctionMessage: "Try using a cascade to avoid the duplication."
addedIn: "2.0"
categories: [brevity, languageFeatureUsage, style]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** Use the cascading style when successively invoking methods on the same
reference.
**BAD:**
```dart
SomeClass someReference = SomeClass();
someReference.firstMethod();
someReference.secondMethod();
```
**BAD:**
```dart
SomeClass someReference = SomeClass();
...
someReference.firstMethod();
someReference.aProperty = value;
someReference.secondMethod();
```
**GOOD:**
```dart
SomeClass someReference = SomeClass()
..firstMethod()
..aProperty = value
..secondMethod();
```
**GOOD:**
```dart
SomeClass someReference = SomeClass();
...
someReference
..firstMethod()
..aProperty = value
..secondMethod();
```
cast_nullable_to_non_nullable:
problemMessage: "Don't cast a nullable value to a non-nullable type."
correctionMessage: "Try adding a not-null assertion ('!') to make the type non-nullable."
addedIn: "2.12"
categories: [errorProne]
hasPublishedDocs: false
deprecatedDetails: |-
**DON'T** cast a nullable value to a non nullable type. This hides a null check
and most of the time it is not what is expected.
**BAD:**
```dart
class A {}
class B extends A {}
A? a;
var v = a as B;
var v = a as A;
```
**GOOD:**
```dart
class A {}
class B extends A {}
A? a;
var v = a! as B;
var v = a!;
```
close_sinks:
problemMessage: "Unclosed instance of 'Sink'."
correctionMessage: "Try invoking 'close' in the function in which the 'Sink' was created."
addedIn: "2.0"
categories: [errorProne, memoryLeaks]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when an instance of `Sink` is
created but the method `close` isn't invoked.
#### Example
The following code produces this diagnostic because the `sink` isn't
closed:
```dart
import 'dart:io';
void g(File f) {
var [!sink = f.openWrite()!];
sink.write('x');
}
```
#### Common fixes
Close the sink:
```dart
import 'dart:io';
void g(File f) {
var sink = f.openWrite();
sink.write('x');
sink.close();
}
```
deprecatedDetails: |-
**DO** invoke `close` on instances of `dart:core` `Sink`.
Closing instances of Sink prevents memory leaks and unexpected behavior.
**BAD:**
```dart
class A {
IOSink _sinkA;
void init(filename) {
_sinkA = File(filename).openWrite(); // LINT
}
}
```
**BAD:**
```dart
void someFunction() {
IOSink _sinkF; // LINT
}
```
**GOOD:**
```dart
class B {
IOSink _sinkB;
void init(filename) {
_sinkB = File(filename).openWrite(); // OK
}
void dispose(filename) {
_sinkB.close();
}
}
```
**GOOD:**
```dart
void someFunctionOK() {
IOSink _sinkFOK; // OK
_sinkFOK.close();
}
```
**Known limitations**
This rule does not track all patterns of Sink instantiations and
closures. See [linter#1381](https://github.com/dart-lang/linter/issues/1381)
for more information.
collection_methods_unrelated_type:
problemMessage: "The argument type '{0}' isn't related to '{1}'."
correctionMessage: "Try changing the argument or element type to match."
addedIn: "2.19"
categories: [unintentional]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when any one of several methods in
the core libraries are invoked with arguments of an inappropriate type.
These methods are ones that don't provide a specific enough type for the
parameter to allow the normal type checking to catch the error.
The arguments that are checked are:
- an argument to `Iterable<E>.contains` should be related to `E`
- an argument to `List<E>.remove` should be related to `E`
- an argument to `Map<K, V>.containsKey` should be related to `K`
- an argument to `Map<K, V>.containsValue` should be related to `V`
- an argument to `Map<K, V>.remove` should be related to `K`
- an argument to `Map<K, V>.[]` should be related to `K`
- an argument to `Queue<E>.remove` should be related to `E`
- an argument to `Set<E>.lookup` should be related to `E`
- an argument to `Set<E>.remove` should be related to `E`
#### Example
The following code produces this diagnostic because the argument to
`contains` is a `String`, which isn't assignable to `int`, the element
type of the list `l`:
```dart
bool f(List<int> l) => l.contains([!'1'!]);
```
#### Common fixes
If the element type is correct, then change the argument to have the same
type:
```dart
bool f(List<int> l) => l.contains(1);
```
If the argument type is correct, then change the element type:
```dart
bool f(List<String> l) => l.contains('1');
```
deprecatedDetails: |-
**DON'T** invoke certain collection method with an argument with an unrelated
type.
Doing this will invoke `==` on the collection's elements and most likely will
return `false`.
An argument passed to a collection method should relate to the collection type
as follows:
* an argument to `Iterable<E>.contains` should be related to `E`
* an argument to `List<E>.remove` should be related to `E`
* an argument to `Map<K, V>.containsKey` should be related to `K`
* an argument to `Map<K, V>.containsValue` should be related to `V`
* an argument to `Map<K, V>.remove` should be related to `K`
* an argument to `Map<K, V>.[]` should be related to `K`
* an argument to `Queue<E>.remove` should be related to `E`
* an argument to `Set<E>.lookup` should be related to `E`
* an argument to `Set<E>.remove` should be related to `E`
**BAD:**
```dart
void someFunction() {
var list = <int>[];
if (list.contains('1')) print('someFunction'); // LINT
}
```
**BAD:**
```dart
void someFunction() {
var set = <int>{};
set.remove('1'); // LINT
}
```
**GOOD:**
```dart
void someFunction() {
var list = <int>[];
if (list.contains(1)) print('someFunction'); // OK
}
```
**GOOD:**
```dart
void someFunction() {
var set = <int>{};
set.remove(1); // OK
}
```
combinators_ordering:
problemMessage: "Sort combinator names alphabetically."
correctionMessage: "Try sorting the combinator names alphabetically."
addedIn: "2.19"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** sort combinator names alphabetically.
**BAD:**
```dart
import 'a.dart' show B, A hide D, C;
export 'a.dart' show B, A hide D, C;
```
**GOOD:**
```dart
import 'a.dart' show A, B hide C, D;
export 'a.dart' show A, B hide C, D;
```
comment_references:
problemMessage: "The referenced name isn't visible in scope."
correctionMessage: "Try adding an import for the referenced name."
addedIn: "2.0"
categories: [documentationCommentMaintenance]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** reference only in-scope identifiers in doc comments.
If you surround identifiers like variable, method, or type names in square
brackets, then tools like your IDE and
[`dart doc`](https://dart.dev/tools/dart-doc) can link to them. For this to
work, ensure that all identifiers in docs wrapped in brackets are in scope.
For example, assuming `outOfScopeId` is out of scope:
**BAD:**
```dart
/// Returns whether [value] is larger than [outOfScopeId].
bool isOutOfRange(int value) { ... }
```
**GOOD:**
```dart
/// Returns the larger of [a] or [b].
int max_int(int a, int b) { ... }
```
Note that the square bracket comment format is designed to allow comments to
refer to declarations using a fairly natural format but does not allow
*arbitrary expressions*. In particular, code references within square brackets
can consist of any of the following:
- A bare identifier which is in-scope for the comment (see the spec for what is
"in-scope" in doc comments). Examples include `[print]` and `[Future]`.
- Two identifiers separated by a period (a "prefixed identifier"), such that the
first identifier acts as a namespacing identifier, such as a class property
name or method name prefixed by the containing class's name, or a top-level
identifier prefixed by an import prefix. Examples include `[Future.new]` (an
unnamed constructor), `[Future.value]` (a constructor), `[Future.wait]` (a
static method), `[Future.then]` (an instance method), `[math.max]` (given that
'dart:async' is imported with a `max` prefix).
- A prefixed identifier followed by a pair of parentheses, used to disambiguate
named constructors from instance members (whose names are allowed to collide).
Examples include `[Future.value()]`.
- Three identifiers separated by two periods, such that the first identifier is
an import prefix name, the second identifier is a top-level element like a
class or an extension, and the third identifier is a member of that top-level
element. Examples include `[async.Future.then]` (given that 'dart:async' is
imported with an `async` prefix).
**Known limitations**
The `comment_references` lint rule aligns with the Dart analyzer's notion of
comment references, which is occasionally distinct from Dartdoc's notion of
comment references. The lint rule may report comment references which Dartdoc
can resolve, even though the analyzer cannot. See
[linter#1142](https://github.com/dart-lang/linter/issues/1142) for more
information.
conditional_uri_does_not_exist:
problemMessage: "The target of the conditional URI '{0}' doesn't exist."
correctionMessage: "Try creating the file referenced by the URI, or try using a URI for a file that does exist."
addedIn: "2.16"
categories: [errorProne]
hasPublishedDocs: false
deprecatedDetails: |-
**DON'T** reference files that do not exist in conditional imports.
Code may fail at runtime if the condition evaluates such that the missing file
needs to be imported.
**BAD:**
```dart
import 'file_that_does_exist.dart'
if (condition) 'file_that_does_not_exist.dart';
```
**GOOD:**
```dart
import 'file_that_does_exist.dart'
if (condition) 'file_that_also_does_exist.dart';
```
constant_identifier_names:
problemMessage: "The constant name '{0}' isn't a lowerCamelCase identifier."
correctionMessage: "Try changing the name to follow the lowerCamelCase style."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the name of a constant doesn't
follow the lowerCamelCase naming convention.
#### Example
The following code produces this diagnostic because the name of the
top-level variable isn't a lowerCamelCase identifier:
```dart
const [!EMPTY_STRING!] = '';
```
#### Common fixes
Rewrite the name to follow the lowerCamelCase naming convention:
```dart
const emptyString = '';
```
deprecatedDetails: |-
**PREFER** using lowerCamelCase for constant names.
In new code, use `lowerCamelCase` for constant variables, including enum values.
In existing code that uses `ALL_CAPS_WITH_UNDERSCORES` for constants, you may
continue to use all caps to stay consistent.
**BAD:**
```dart
const PI = 3.14;
const kDefaultTimeout = 1000;
final URL_SCHEME = RegExp('^([a-z]+):');
class Dice {
static final NUMBER_GENERATOR = Random();
}
```
**GOOD:**
```dart
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
class Dice {
static final numberGenerator = Random();
}
```
control_flow_in_finally:
problemMessage: "Use of '{0}' in a 'finally' clause."
correctionMessage: "Try restructuring the code."
addedIn: "2.0"
categories: [errorProne]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a `finally` clause contains a
`return`, `break`, or `continue` statement.
#### Example
The following code produces this diagnostic because there is a `return`
statement inside a `finally` block:
```dart
int f() {
try {
return 1;
} catch (e) {
print(e);
} finally {
[!return 0;!]
}
}
```
#### Common fixes
If the statement isn't needed, then remove the statement, and remove the
`finally` clause if the block is empty:
```dart
int f() {
try {
return 1;
} catch (e) {
print(e);
}
}
```
If the statement is needed, then move the statement outside the `finally`
block:
```dart
int f() {
try {
return 1;
} catch (e) {
print(e);
}
return 0;
}
```
deprecatedDetails: |-
**AVOID** control flow leaving `finally` blocks.
Using control flow in `finally` blocks will inevitably cause unexpected behavior
that is hard to debug.
**BAD:**
```dart
class BadReturn {
double nonCompliantMethod() {
try {
return 1 / 0;
} catch (e) {
print(e);
} finally {
return 1.0; // LINT
}
}
}
```
**BAD:**
```dart
class BadContinue {
double nonCompliantMethod() {
for (var o in [1, 2]) {
try {
print(o / 0);
} catch (e) {
print(e);
} finally {
continue; // LINT
}
}
return 1.0;
}
}
```
**BAD:**
```dart
class BadBreak {
double nonCompliantMethod() {
for (var o in [1, 2]) {
try {
print(o / 0);
} catch (e) {
print(e);
} finally {
break; // LINT
}
}
return 1.0;
}
}
```
**GOOD:**
```dart
class Ok {
double compliantMethod() {
var i = 5;
try {
i = 1 / 0;
} catch (e) {
print(e); // OK
}
return i;
}
}
```
curly_braces_in_flow_control_structures:
problemMessage: "Statements in {0} should be enclosed in a block."
correctionMessage: "Try wrapping the statement in a block."
addedIn: "2.0"
categories: [errorProne]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a control structure (`if`,
`for`, `while`, or `do` statement) has a statement other than a block.
#### Example
The following code produces this diagnostic because the `then` statement
is not enclosed in a block:
```dart
int f(bool b) {
if (b)
[!return 1;!]
return 0;
}
```
#### Common fixes
Add braces around the statement that should be a block:
```dart
int f(bool b) {
if (b) {
return 1;
}
return 0;
}
```
deprecatedDetails: |-
**DO** use curly braces for all flow control structures.
Doing so avoids the [dangling else](https://en.wikipedia.org/wiki/Dangling_else)
problem.
**BAD:**
```dart
if (overflowChars != other.overflowChars)
return overflowChars < other.overflowChars;
```
**GOOD:**
```dart
if (isWeekDay) {
print('Bike to work!');
} else {
print('Go dancing or read a book!');
}
```
There is one exception to this: an `if` statement with no `else` clause where
the entire `if` statement (including the condition and the body) fits in one
line. In that case, you may leave off the braces if you prefer:
**GOOD:**
```dart
if (arg == null) return defaultValue;
```
If the body wraps to the next line, though, use braces:
**GOOD:**
```dart
if (overflowChars != other.overflowChars) {
return overflowChars < other.overflowChars;
}
```
dangling_library_doc_comments:
problemMessage: "Dangling library doc comment."
correctionMessage: "Add a 'library' directive after the library comment."
addedIn: "2.19"
categories: [documentationCommentMaintenance]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a documentation comment that
appears to be library documentation isn't followed by a `library`
directive. More specifically, it is produced when a documentation comment
appears before the first directive in the library, assuming that it isn't
a `library` directive, or before the first top-level declaration and is
separated from the declaration by one or more blank lines.
#### Example
The following code produces this diagnostic because there's a
documentation comment before the first `import` directive:
```dart
[!/// This is a great library.!]
import 'dart:core';
```
The following code produces this diagnostic because there's a
documentation comment before the first class declaration, but there's a
blank line between the comment and the declaration.
```dart
[!/// This is a great library.!]
class C {}
```
#### Common fixes
If the comment is library documentation, then add a `library` directive
without a name:
```dart
/// This is a great library.
library;
import 'dart:core';
```
If the comment is documentation for the following declaration, then remove
the blank line:
```dart
/// This is a great library.
class C {}
```
deprecatedDetails: |-
Attach library doc comments (with `///`) to library directives, rather than
leaving them dangling near the top of a library.
**BAD:**
```dart
/// This is a great library.
import 'package:math';
```
```dart
/// This is a great library.
class C {}
```
**GOOD:**
```dart
/// This is a great library.
library;
import 'package:math';
class C {}
```
**NOTE:** An unnamed library, like `library;` above, is only supported in Dart
2.19 and later. Code which might run in earlier versions of Dart will need to
provide a name in the `library` directive.
depend_on_referenced_packages:
problemMessage: "The imported package '{0}' isn't a dependency of the importing package."
correctionMessage: "Try adding a dependency for '{0}' in the 'pubspec.yaml' file."
addedIn: "2.14"
categories: [pub]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a package import refers to a
package that is not specified in the `pubspec.yaml` file.
Depending explicitly on packages that you reference ensures they will
always exist and allows you to put a dependency constraint on them to
guard against breaking changes.
#### Example
Given a `pubspec.yaml` file containing the following:
```yaml
dependencies:
meta: ^3.0.0
```
The following code produces this diagnostic because there is no dependency
on the package `a`:
```dart
import 'package:a/a.dart';
```
#### Common fixes
Whether the dependency should be a regular dependency or dev dependency
depends on whether the package is referenced from a public library (one
under either `lib` or `bin`), or only private libraries, (such as one
under `test`).
If the package is referenced from at least one public library, then add a
regular dependency on the package to the `pubspec.yaml` file under the
`dependencies` field:
```yaml
dependencies:
a: ^1.0.0
meta: ^3.0.0
```
If the package is referenced only from private libraries, then add a
dev dependency on the package to the `pubspec.yaml` file under the
`dev_dependencies` field:
```yaml
dependencies:
meta: ^3.0.0
dev_dependencies:
a: ^1.0.0
```
deprecatedDetails: |-
**DO** depend on referenced packages.
When importing a package, add a dependency on it to your pubspec.
Depending explicitly on packages that you reference ensures they will always
exist and allows you to put a dependency constraint on them to guard you
against breaking changes.
Whether this should be a regular dependency or dev_dependency depends on if it
is referenced from a public file (one under either `lib` or `bin`), or some
other private file.
**BAD:**
```dart
import 'package:a/a.dart';
```
```yaml
dependencies:
```
**GOOD:**
```dart
import 'package:a/a.dart';
```
```yaml
dependencies:
a: ^1.0.0
```
deprecated_consistency_constructor:
sharedName: deprecated_consistency
problemMessage: "Constructors in a deprecated class should be deprecated."
correctionMessage: "Try marking the constructor as deprecated."
addedIn: "2.13"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** apply `@Deprecated()` consistently:
- if a class is deprecated, its constructors should also be deprecated.
- if a field is deprecated, the constructor parameter pointing to it should also
be deprecated.
- if a constructor parameter pointing to a field is deprecated, the field should
also be deprecated.
**BAD:**
```dart
@deprecated
class A {
A();
}
class B {
B({this.field});
@deprecated
Object field;
}
```
**GOOD:**
```dart
@deprecated
class A {
@deprecated
A();
}
class B {
B({@deprecated this.field});
@deprecated
Object field;
}
class C extends B {
C({@deprecated super.field});
}
```
deprecated_consistency_field:
sharedName: deprecated_consistency
problemMessage: "Fields that are initialized by a deprecated parameter should be deprecated."
correctionMessage: "Try marking the field as deprecated."
hasPublishedDocs: false
deprecated_consistency_parameter:
sharedName: deprecated_consistency
problemMessage: "Parameters that initialize a deprecated field should be deprecated."
correctionMessage: "Try marking the parameter as deprecated."
hasPublishedDocs: false
deprecated_member_use_from_same_package_with_message:
sharedName: deprecated_member_use_from_same_package
problemMessage: "'{0}' is deprecated and shouldn't be used. {1}"
correctionMessage: "Try replacing the use of the deprecated member with the replacement, if a replacement is specified."
addedIn: "3.0"
categories: [languageFeatureUsage]
hasPublishedDocs: false
deprecatedDetails: |-
Elements that are annotated with `@Deprecated` should not be referenced from
within the package in which they are declared.
**AVOID** using deprecated elements.
...
**BAD:**
```dart
// Declared in one library:
class Foo {
@Deprecated("Use 'm2' instead")
void m1() {}
void m2({
@Deprecated('This is an old parameter') int? p,
})
}
@Deprecated('Do not use')
int x = 0;
// In the same or another library, but within the same package:
void m(Foo foo) {
foo.m1();
foo.m2(p: 7);
x = 1;
}
```
Deprecated elements can be used from within _other_ deprecated elements, in
order to allow for the deprecation of a collection of APIs together as one unit.
**GOOD:**
```dart
// Declared in one library:
class Foo {
@Deprecated("Use 'm2' instead")
void m1() {}
void m2({
@Deprecated('This is an old parameter') int? p,
})
}
@Deprecated('Do not use')
int x = 0;
// In the same or another library, but within the same package:
@Deprecated('Do not use')
void m(Foo foo) {
foo.m1();
foo.m2(p: 7);
x = 1;
}
```
deprecated_member_use_from_same_package_without_message:
sharedName: deprecated_member_use_from_same_package
problemMessage: "'{0}' is deprecated and shouldn't be used."
correctionMessage: "Try replacing the use of the deprecated member with the replacement, if a replacement is specified."
hasPublishedDocs: false
diagnostic_describe_all_properties:
problemMessage: "The public property isn't described by either 'debugFillProperties' or 'debugDescribeChildren'."
correctionMessage: "Try describing the property."
addedIn: "2.3"
categories: [errorProne, flutter]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** reference all public properties in `debug` method implementations.
Implementers of `Diagnosticable` should reference all public properties in
a `debugFillProperties(...)` or `debugDescribeChildren(...)` method
implementation to improve debuggability at runtime.
Public properties are defined as fields and getters that are
* not package-private (e.g., prefixed with `_`)
* not `static` or overriding
* not themselves `Widget`s or collections of `Widget`s
In addition, the "debug" prefix is treated specially for properties in Flutter.
For the purposes of diagnostics, a property `foo` and a prefixed property
`debugFoo` are treated as effectively describing the same property and it is
sufficient to refer to one or the other.
**BAD:**
```dart
class Absorber extends Widget {
bool get absorbing => _absorbing;
bool _absorbing;
bool get ignoringSemantics => _ignoringSemantics;
bool _ignoringSemantics;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('absorbing', absorbing));
// Missing reference to ignoringSemantics
}
}
```
**GOOD:**
```dart
class Absorber extends Widget {
bool get absorbing => _absorbing;
bool _absorbing;
bool get ignoringSemantics => _ignoringSemantics;
bool _ignoringSemantics;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('absorbing', absorbing));
properties.add(DiagnosticsProperty<bool>('ignoringSemantics', ignoringSemantics));
}
}
```
directives_ordering_alphabetical:
sharedName: directives_ordering
problemMessage: "Sort directive sections alphabetically."
correctionMessage: "Try sorting the directives."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** follow the directive ordering conventions in
[Effective Dart](https://dart.dev/effective-dart/style#ordering):
**DO** place `dart:` imports before other imports.
**BAD:**
```dart
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'dart:async'; // LINT
import 'dart:html'; // LINT
```
**BAD:**
```dart
import 'dart:html'; // OK
import 'package:bar/bar.dart';
import 'dart:async'; // LINT
import 'package:foo/foo.dart';
```
**GOOD:**
```dart
import 'dart:async'; // OK
import 'dart:html'; // OK
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
```
**DO** place `package:` imports before relative imports.
**BAD:**
```dart
import 'a.dart';
import 'b.dart';
import 'package:bar/bar.dart'; // LINT
import 'package:foo/foo.dart'; // LINT
```
**BAD:**
```dart
import 'package:bar/bar.dart'; // OK
import 'a.dart';
import 'package:foo/foo.dart'; // LINT
import 'b.dart';
```
**GOOD:**
```dart
import 'package:bar/bar.dart'; // OK
import 'package:foo/foo.dart'; // OK
import 'a.dart';
import 'b.dart';
```
**DO** specify exports in a separate section after all imports.
**BAD:**
```dart
import 'src/error.dart';
export 'src/error.dart'; // LINT
import 'src/string_source.dart';
```
**GOOD:**
```dart
import 'src/error.dart';
import 'src/string_source.dart';
export 'src/error.dart'; // OK
```
**DO** sort sections alphabetically.
**BAD:**
```dart
import 'package:foo/bar.dart'; // OK
import 'package:bar/bar.dart'; // LINT
import 'a/b.dart'; // OK
import 'a.dart'; // LINT
```
**GOOD:**
```dart
import 'package:bar/bar.dart'; // OK
import 'package:foo/bar.dart'; // OK
import 'a.dart'; // OK
import 'a/b.dart'; // OK
```
directives_ordering_dart:
sharedName: directives_ordering
problemMessage: "Place 'dart:' {0}s before other {0}s."
correctionMessage: "Try sorting the directives."
hasPublishedDocs: false
directives_ordering_exports:
sharedName: directives_ordering
problemMessage: "Specify exports in a separate section after all imports."
correctionMessage: "Try sorting the directives."
hasPublishedDocs: false
directives_ordering_package_before_relative:
sharedName: directives_ordering
problemMessage: "Place 'package:' {0}s before relative {0}s."
correctionMessage: "Try sorting the directives."
hasPublishedDocs: false
discarded_futures:
problemMessage: "Asynchronous function invoked in a non-'async' function."
correctionMessage: "Try converting the enclosing function to be 'async' and then 'await' the future."
addedIn: "2.18"
categories: [errorProne]
hasPublishedDocs: false
deprecatedDetails: |-
Making asynchronous calls in non-`async` functions is usually the sign of a
programming error. In general these functions should be marked `async` and such
futures should likely be awaited (as enforced by `unawaited_futures`).
**DON'T** invoke asynchronous functions in non-`async` blocks.
**BAD:**
```dart
void recreateDir(String path) {
deleteDir(path);
createDir(path);
}
Future<void> deleteDir(String path) async {}
Future<void> createDir(String path) async {}
```
**GOOD:**
```dart
Future<void> recreateDir(String path) async {
await deleteDir(path);
await createDir(path);
}
Future<void> deleteDir(String path) async {}
Future<void> createDir(String path) async {}
```
do_not_use_environment:
problemMessage: "Invalid use of an environment declaration."
correctionMessage: "Try removing the environment declaration usage."
addedIn: "2.9"
categories: [errorProne]
hasPublishedDocs: false
deprecatedDetails: |-
Using values derived from the environment at compile-time, creates
hidden global state and makes applications hard to understand and maintain.
**DON'T** use `fromEnvironment` or `hasEnvironment` factory constructors.
**BAD:**
```dart
const loggingLevel =
bool.hasEnvironment('logging') ? String.fromEnvironment('logging') : null;
```
document_ignores:
problemMessage: "Missing documentation explaining why the diagnostic is ignored."
correctionMessage: "Try adding a comment immediately above the ignore comment."
addedIn: "3.5"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** document all ignored diagnostic reports.
**BAD:**
```dart
// ignore: unused_element
int _x = 1;
```
**GOOD:**
```dart
// This private field will be used later.
// ignore: unused_element
int _x = 1;
```
empty_catches:
problemMessage: "Empty catch block."
correctionMessage: "Try adding statements to the block, adding a comment to the block, or removing the 'catch' clause."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the block in a `catch` clause
is empty.
#### Example
The following code produces this diagnostic because the catch block is
empty:
```dart
void f() {
try {
print('Hello');
} catch (exception) [!{}!]
}
```
#### Common fixes
If the exception shouldn't be ignored, then add code to handle the
exception:
```dart
void f() {
try {
print('We can print.');
} catch (exception) {
print("We can't print.");
}
}
```
If the exception is intended to be ignored, then add a comment explaining
why:
```dart
void f() {
try {
print('We can print.');
} catch (exception) {
// Nothing to do.
}
}
```
If the exception is intended to be ignored and there isn't any good
explanation for why, then rename the exception parameter:
```dart
void f() {
try {
print('We can print.');
} catch (_) {}
}
```
deprecatedDetails: |-
**AVOID** empty catch blocks.
In general, empty catch blocks should be avoided. In cases where they are
intended, a comment should be provided to explain why exceptions are being
caught and suppressed. Alternatively, the exception identifier can be named with
underscores (e.g., `_`) to indicate that we intend to skip it.
**BAD:**
```dart
try {
...
} catch(exception) { }
```
**GOOD:**
```dart
try {
...
} catch(e) {
// ignored, really.
}
// Alternatively:
try {
...
} catch(_) { }
// Better still:
try {
...
} catch(e) {
doSomething(e);
}
```
empty_constructor_bodies:
problemMessage: "Empty constructor bodies should be written using a ';' rather than '{}'."
correctionMessage: "Try replacing the constructor body with ';'."
addedIn: "2.0"
categories: [brevity, effectiveDart, style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when a constructor has an empty
block body.
#### Example
The following code produces this diagnostic because the constructor for
`C` has a block body that is empty:
```dart
class C {
C() [!{}!]
}
```
#### Common fixes
Replace the block with a semicolon:
```dart
class C {
C();
}
```
deprecatedDetails: |-
From [Effective Dart](https://dart.dev/effective-dart/usage#do-use--instead-of--for-empty-constructor-bodies):
**DO** use `;` instead of `{}` for empty constructor bodies.
In Dart, a constructor with an empty body can be terminated with just a
semicolon. This is required for const constructors. For consistency and
brevity, other constructors should also do this.
**BAD:**
```dart
class Point {
int x, y;
Point(this.x, this.y) {}
}
```
**GOOD:**
```dart
class Point {
int x, y;
Point(this.x, this.y);
}
```
empty_statements:
problemMessage: "Unnecessary empty statement."
correctionMessage: "Try removing the empty statement or restructuring the code."
addedIn: "2.0"
categories: [errorProne]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when an empty statement is found.
#### Example
The following code produces this diagnostic because the statement
controlled by the `while` loop is an empty statement:
```dart
void f(bool condition) {
while (condition)[!;!]
g();
}
void g() {}
```
#### Common fixes
If there are no statements that need to be controlled, then remove both
the empty statement and the control structure it's part of (being careful
that any other code being removed doesn't have a side-effect that needs to
be preserved):
```dart
void f(bool condition) {
g();
}
void g() {}
```
If there are no statements that need to be controlled but the control
structure is still required for other reasons, then replace the empty
statement with a block to make the structure of the code more obvious:
```dart
void f(bool condition) {
while (condition) {}
g();
}
void g() {}
```
If there are statements that need to be controlled, remove the empty
statement and adjust the code so that the appropriate statements are being
controlled, possibly adding a block:
```dart
void f(bool condition) {
while (condition) {
g();
}
}
void g() {}
```
deprecatedDetails: |-
**AVOID** empty statements.
Empty statements almost always indicate a bug.
For example,
**BAD:**
```dart
if (complicated.expression.foo());
bar();
```
Formatted with `dart format` the bug becomes obvious:
```dart
if (complicated.expression.foo()) ;
bar();
```
Better to avoid the empty statement altogether.
**GOOD:**
```dart
if (complicated.expression.foo())
bar();
```
enable_null_safety:
addedIn: "2.19"
removedIn: "3.0"
deprecatedDetails: |-
NOTE: This rule is removed in Dart 3.0.0; it is no longer functional.
**DO** use sound null safety, by not specifying a dart version lower than `2.12`.
**BAD:**
```dart
// @dart=2.8
a() {
}
```
**GOOD:**
```dart
b() {
}
```
eol_at_end_of_file:
problemMessage: "Missing a newline at the end of the file."
correctionMessage: "Try adding a newline at the end of the file."
addedIn: "2.14"
categories: [style]
hasPublishedDocs: false
deprecatedDetails: |-
**DO** put a single newline at the end of non-empty files.
**BAD:**
```dart
a {
}
```
**GOOD:**
```dart
b {
}
<-- newline
```
erase_dart_type_extension_types:
problemMessage: "Unsafe use of 'DartType' in an 'is' check."
correctionMessage: "Ensure DartType extension types are erased by using a helper method."
addedIn: "3.3"
categories: [errorProne]
hasPublishedDocs: false
todo: |-
TODO(nshahan): Update.
deprecatedDetails: |-
Experimental WIP lint to help ensure `DartType` accesses are safe in the dev_compiler.
**For internal use only.**
exhaustive_cases:
problemMessage: "Missing case clauses for some constants in '{0}'."
correctionMessage: "Try adding case clauses for the missing constants."
addedIn: "2.9"
categories: [errorProne]
hasPublishedDocs: false
deprecatedDetails: |-
Switching on instances of enum-like classes should be exhaustive.
Enum-like classes are defined as concrete (non-abstract) classes that have:
* only private non-factory constructors
* two or more static const fields whose type is the enclosing class and
* no subclasses of the class in the defining library
**DO** define case clauses for all constants in enum-like classes.
**BAD:**
```dart
class EnumLike {
final int i;
const EnumLike._(this.i);
static const e = EnumLike._(1);
static const f = EnumLike._(2);
static const g = EnumLike._(3);
}
void bad(EnumLike e) {
// Missing case.
switch(e) { // LINT
case EnumLike.e :
print('e');
break;
case EnumLike.f :
print('f');
break;
}
}
```
**GOOD:**
```dart
class EnumLike {
final int i;
const EnumLike._(this.i);
static const e = EnumLike._(1);
static const f = EnumLike._(2);
static const g = EnumLike._(3);
}
void ok(EnumLike e) {
// All cases covered.
switch(e) { // OK
case EnumLike.e :
print('e');
break;
case EnumLike.f :
print('f');
break;
case EnumLike.g :
print('g');
break;
}
}
```
file_names:
problemMessage: "The file name '{0}' isn't a lower_case_with_underscores identifier."
correctionMessage: "Try changing the name to follow the lower_case_with_underscores style."
addedIn: "2.0"
categories: [style]
hasPublishedDocs: true
documentation: |-
#### Description
The analyzer produces this diagnostic when the name of a `.dart` file
doesn't use lower_case_with_underscores.
#### Example
A file named `SliderMenu.dart` produces this diagnostic because the file
name uses the UpperCamelCase convention.
#### Common fixes
Rename the file to use the lower_case_with_underscores convention, such as
`slider_menu.dart`.
deprecatedDetails: |-
**DO** name source files using `lowercase_with_underscores`.
Some file systems are not case-sensitive, so many projects require filenames to
be all lowercas