| # 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. |
| |
| # After editing this file to add a new lint rule or code, |
| # make sure to regenerate supporting classes by running: |
| # |
| # dart run pkg/linter/tool/generate_lints.dart |
| |
| # 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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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: |
| state: |
| stable: "2.0" |
| removed: "3.3" |
| hasPublishedDocs: false |
| 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." |
| state: |
| stable: "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 `@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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| experimental: "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'." |
| state: |
| stable: "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: |
| state: |
| stable: "2.0" |
| removed: "3.0" |
| hasPublishedDocs: false |
| 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 '||'." |
| state: |
| stable: "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'." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| experimental: "2.12" |
| stable: "2.14" |
| categories: [binarySize, errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a member of a class is accessed |
| on an expression whose type is `dynamic`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the getter `length` is |
| being invoked on `s`, which has the type `dynamic`: |
| |
| ```dart |
| void f(dynamic s) { |
| [!s!].length; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Provide enough type information that the expression has a type other than |
| `dynamic`: |
| |
| ```dart |
| void f(String s) { |
| s.length; |
| } |
| ``` |
| 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." |
| state: |
| stable: "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'." |
| state: |
| stable: "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}'." |
| state: |
| stable: "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." |
| state: |
| stable: "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'." |
| state: |
| stable: "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." |
| state: |
| stable: "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'." |
| state: |
| experimental: "3.6" |
| 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/sdk/issues/59232. |
| avoid_implementing_value_types: |
| problemMessage: "Classes that override '==' should not be implemented." |
| correctionMessage: "Try removing the class from the 'implements' clause." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **NOTE:** This lint has been replaced by the |
| `non_nullable_equals_parameter` warning and is deprecated. |
| Remove all inclusions of this lint from your analysis options. |
| |
| **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." |
| state: |
| experimental: "2.0" |
| stable: "2.2" |
| 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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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}'." |
| state: |
| stable: "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." |
| state: |
| stable: "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: |
| state: |
| stable: "2.0" |
| removed: "3.3" |
| hasPublishedDocs: false |
| 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: |
| state: |
| stable: "2.1" |
| removed: "3.3" |
| hasPublishedDocs: false |
| 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'." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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}'." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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_formal_parameter: |
| sharedName: 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." |
| hasPublishedDocs: true |
| avoid_types_as_parameter_names_type_parameter: |
| sharedName: avoid_types_as_parameter_names |
| problemMessage: "The type parameter name '{0}' matches a visible type name." |
| state: |
| stable: "2.0" |
| correctionMessage: "Try changing the type parameter name to not match an existing type." |
| 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. |
| |
| The analyzer also produces this diagnostic when the name of a type |
| parameter in a type parameter list is the same as a type whose name is |
| in scope. It is again recommended that the type parameter is renamed |
| such that the error-prone shadowing is avoided. |
| |
| #### 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." |
| state: |
| stable: "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." |
| state: |
| stable: "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: |
| state: |
| experimental: "3.3" |
| removed: "3.3" |
| hasPublishedDocs: false |
| 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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| experimental: "2.6" |
| stable: "2.14" |
| 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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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/sdk/issues/57387) |
| for more information. |
| cascade_invocations: |
| problemMessage: "Unnecessary duplication of receiver." |
| correctionMessage: "Try using a cascade to avoid the duplication." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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 [sdk#57882](https://github.com/dart-lang/sdk/issues/57882) |
| 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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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 |
| [sdk#57783](https://github.com/dart-lang/sdk/issues/57783) 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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "2.3" |
| categories: [errorProne, flutter] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a class that implements |
| `Diagnosticable` has a public property that isn't added as a property in |
| either a `debugFillProperties` or `debugDescribeChildren` method. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the property `p2` |
| isn't added in the `debugFillProperties` method: |
| |
| ```dart |
| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/material.dart'; |
| |
| class C extends Widget { |
| bool get p1 => true; |
| |
| bool get [!p2!] => false; |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<bool>('p1', p1)); |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If there isn't on override of either the `debugFillProperties` or |
| `debugDescribeChildren` method, then add one. |
| |
| Add a description of the property in the `debugFillProperties` or |
| `debugDescribeChildren` method: |
| |
| ```dart |
| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/material.dart'; |
| |
| class C extends Widget { |
| bool get p1 => true; |
| |
| bool get p2 => false; |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<bool>('p1', p1)); |
| properties.add(DiagnosticsProperty<bool>('p2', p2)); |
| } |
| } |
| ``` |
| 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." |
| state: |
| stable: "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: "'Future'-returning calls in a non-'async' function." |
| correctionMessage: "Try converting the enclosing function to be 'async' and then 'await' the future, or wrap the expression in 'unawaited'." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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 ';'." |
| state: |
| stable: "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." |
| state: |
| stable: "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: |
| state: |
| stable: "2.19" |
| removed: "3.0" |
| hasPublishedDocs: false |
| 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." |
| state: |
| stable: "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." |
| state: |
| internal: "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." |
| state: |
| stable: "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." |
| state: |
| stable: "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 lowercase. Using a separating character allows names to still be readable |
| in that form. Using underscores as the separator ensures that the name is still |
| a valid Dart identifier, which may be helpful if the language later supports |
| symbolic imports. |
| |
| **BAD:** |
| |
| * `SliderMenu.dart` |
| * `filesystem.dart` |
| * `file-system.dart` |
| |
| **GOOD:** |
| |
| * `slider_menu.dart` |
| * `file_system.dart` |
| |
| Files without a strict `.dart` extension are ignored. For example: |
| |
| **OK:** |
| |
| * `file-system.g.dart` |
| * `SliderMenu.css.dart` |
| |
| The lint `library_names` can be used to enforce the same kind of naming on the |
| library. |
| flutter_style_todos: |
| problemMessage: "To-do comment doesn't follow the Flutter style." |
| correctionMessage: "Try following the Flutter style for to-do comments." |
| state: |
| stable: "2.1" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DO** use Flutter TODO format. |
| |
| From the [Flutter |
| docs](https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#comments): |
| |
| > TODOs should include the string TODO in all caps, followed by the GitHub |
| username of the person with the best context about the problem referenced by the |
| TODO in parenthesis. A TODO is not a commitment that the person referenced will |
| fix the problem, it is intended to be the person with enough context to explain |
| the problem. Thus, when you create a TODO, it is almost always your username |
| that is given. |
| |
| **GOOD:** |
| ```dart |
| // TODO(username): message. |
| // TODO(username): message, https://URL-to-issue. |
| ``` |
| hash_and_equals: |
| problemMessage: "Missing a corresponding override of '{0}'." |
| correctionMessage: "Try overriding '{0}' or removing '{1}'." |
| state: |
| stable: "2.0" |
| categories: [errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a class or mixin either |
| overrides the definition of `==` but doesn't override the definition of |
| `hashCode`, or conversely overrides the definition of `hashCode` but |
| doesn't override the definition of `==`. |
| |
| Both the `==` operator and the `hashCode` property of objects must be |
| consistent for a common hash map implementation to function properly. As a |
| result, when overriding either method, both should be overridden. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the class `C` |
| overrides the `==` operator but doesn't override the getter `hashCode`: |
| |
| ```dart |
| class C { |
| final int value; |
| |
| C(this.value); |
| |
| @override |
| bool operator [!==!](Object other) => |
| other is C && |
| other.runtimeType == runtimeType && |
| other.value == value; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If you need to override one of the members, then add an override of the |
| other: |
| |
| ```dart |
| class C { |
| final int value; |
| |
| C(this.value); |
| |
| @override |
| bool operator ==(Object other) => |
| other is C && |
| other.runtimeType == runtimeType && |
| other.value == value; |
| |
| @override |
| int get hashCode => value.hashCode; |
| } |
| ``` |
| |
| If you don't need to override either of the members, then remove the |
| unnecessary override: |
| |
| ```dart |
| class C { |
| final int value; |
| |
| C(this.value); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** override `hashCode` if overriding `==` and prefer overriding `==` if |
| overriding `hashCode`. |
| |
| Every object in Dart has a `hashCode`. Both the `==` operator and the |
| `hashCode` property of objects must be consistent in order for a common hash |
| map implementation to function properly. Thus, when overriding `==`, the |
| `hashCode` should also be overridden to maintain consistency. Similarly, if |
| `hashCode` is overridden, `==` should be also. |
| |
| **BAD:** |
| ```dart |
| class Bad { |
| final int value; |
| Bad(this.value); |
| |
| @override |
| bool operator ==(Object other) => other is Bad && other.value == value; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Better { |
| final int value; |
| Better(this.value); |
| |
| @override |
| bool operator ==(Object other) => |
| other is Better && |
| other.runtimeType == runtimeType && |
| other.value == value; |
| |
| @override |
| int get hashCode => value.hashCode; |
| } |
| ``` |
| implementation_imports: |
| problemMessage: "Import of a library in the 'lib/src' directory of another package." |
| correctionMessage: "Try importing a public library that exports this library, or removing the import." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an import references a library |
| that's inside the `lib/src` directory of a different package, which |
| violates [the convention for pub |
| packages](https://dart.dev/tools/pub/package-layout#implementation-files). |
| |
| #### Example |
| |
| The following code, assuming that it isn't part of the `ffi` package, |
| produces this diagnostic because the library being imported is inside the |
| top-level `src` directory: |
| |
| ```dart |
| import [!'package:ffi/src/allocation.dart'!]; |
| ``` |
| |
| #### Common fixes |
| |
| If the library being imported contains code that's part of the public API, |
| then import the public library that exports the public API: |
| |
| ```dart |
| import 'package:ffi/ffi.dart'; |
| ``` |
| |
| If the library being imported isn't part of the public API of the package, |
| then either find a different way to accomplish your goal, assuming that |
| it's possible, or open an issue asking the package authors to make it part |
| of the public API. |
| deprecatedDetails: |- |
| From the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files): |
| |
| **DON'T** import implementation files from another package. |
| |
| The libraries inside `lib` are publicly visible: other packages are free to |
| import them. But much of a package's code is internal implementation libraries |
| that should only be imported and used by the package itself. Those go inside a |
| subdirectory of `lib` called `src`. You can create subdirectories in there if |
| it helps you organize things. |
| |
| You are free to import libraries that live in `lib/src` from within other Dart |
| code in the same package (like other libraries in `lib`, scripts in `bin`, |
| and tests) but you should never import from another package's `lib/src` |
| directory. Those files are not part of the package's public API, and they |
| might change in ways that could break your code. |
| |
| **BAD:** |
| ```dart |
| // In 'road_runner' |
| import 'package:acme/src/internals.dart'; |
| ``` |
| implicit_call_tearoffs: |
| problemMessage: "Implicit tear-off of the 'call' method." |
| correctionMessage: "Try explicitly tearing off the 'call' method." |
| state: |
| stable: "2.19" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an object with a `call` method |
| is assigned to a function-typed variable, implicitly tearing off the |
| `call` method. |
| |
| #### Example |
| |
| The following code produces this diagnostic because an instance of |
| `Callable` is passed to a function expecting a `Function`: |
| |
| ```dart |
| class Callable { |
| void call() {} |
| } |
| |
| void callIt(void Function() f) { |
| f(); |
| } |
| |
| void f() { |
| callIt([!Callable()!]); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Explicitly tear off the `call` method: |
| |
| ```dart |
| class Callable { |
| void call() {} |
| } |
| |
| void callIt(void Function() f) { |
| f(); |
| } |
| |
| void f() { |
| callIt(Callable().call); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** |
| Explicitly tear off `.call` methods from objects when assigning to a Function |
| type. There is less magic with an explicit tear off. Future language versions |
| may remove the implicit call tear off. |
| |
| **BAD:** |
| ```dart |
| class Callable { |
| void call() {} |
| } |
| void callIt(void Function() f) { |
| f(); |
| } |
| |
| callIt(Callable()); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Callable { |
| void call() {} |
| } |
| void callIt(void Function() f) { |
| f(); |
| } |
| |
| callIt(Callable().call); |
| ``` |
| implicit_reopen: |
| problemMessage: "The {0} '{1}' reopens '{2}' because it is not marked '{3}'." |
| correctionMessage: "Try marking '{1}' '{3}' or annotating it with '@reopen'." |
| state: |
| experimental: "3.0" |
| categories: [errorProne] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Using an `interface`, `base`, `final`, or `sealed` modifier on a class, |
| or a `base` modifier on a mixin, |
| authors can control whether classes and mixins allow being implemented, |
| extended, and/or mixed in from outside of the library where they're defined. |
| In some cases, it's possible for an author to inadvertently relax these controls |
| and implicitly "reopen" a class. (A similar reopening cannot occur with a mixin.) |
| |
| This lint guards against unintentionally reopening a class by requiring such |
| cases to be made explicit with the |
| [`@reopen`](https://pub.dev/documentation/meta/latest/meta/reopen-constant.html) |
| annotation in `package:meta`. |
| |
| **BAD:** |
| ```dart |
| interface class I {} |
| |
| class C extends I {} // LINT |
| ``` |
| |
| **GOOD:** |
| ```dart |
| interface class I {} |
| |
| final class C extends I {} |
| ``` |
| |
| ```dart |
| import 'package:meta/meta.dart'; |
| |
| interface class I {} |
| |
| @reopen |
| class C extends I {} |
| ``` |
| invalid_case_patterns: |
| problemMessage: "This expression is not valid in a 'case' clause in Dart 3.0." |
| correctionMessage: "Try refactoring the expression to be valid in 3.0." |
| state: |
| experimental: "3.0" |
| categories: [languageFeatureUsage] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Some case expressions that are valid in Dart 2.19 and below will become an error |
| or have changed semantics when a library is upgraded to 3.0. This lint flags |
| those expressions in order to ease migration to Dart 3.0. |
| |
| Some valid switch cases in 2.19 will become compile errors in Dart 3.0: |
| |
| * Set literals |
| * Parenthesized expressions |
| * Calls to `identical()`. |
| * Unary operator expressions `!`, `-`, or `~` (except for `-` before an integer |
| literal, which is a valid pattern and is fine) |
| * Binary operator expressions `!=`, `==`, `&`, `|`, `^`, `~/`, `>>`, `>>>`, |
| `<<`, `+`, `-`, `*`, `/`, `%`, `<`, `<=`, `>`, `>=`, `??`. |
| * Conditional operator `?:` |
| * `.length` calls on strings |
| * `is` and `is!` expressions |
| |
| Examples of all of them: |
| |
| ```dart |
| switch (obj) { |
| case {1}: // Set literal. |
| case (1): // Parenthesized expression. |
| case identical(1, 2): // `identical()` call. |
| case -pi: // Unary operator. |
| case 1 + 2: // Binary operator. |
| case true ? 1 : 2: // Conditional operator. |
| case 'hi'.length: // .length call. |
| case i is int: // is expression. |
| } |
| ``` |
| |
| Some valid switch cases in 2.19 are also syntactically valid patterns, but the |
| pattern matching behavior may be different from the current constant equality |
| behavior. They are: |
| |
| **List and map literals.** A list or map literal can appear as a constant in a |
| case: |
| |
| ```dart |
| switch (obj) { |
| case [1, 2]: ... |
| case {'k': 'v'}: ... |
| } |
| ``` |
| |
| Currently, the case will only match if the incoming value has the same identity |
| as the constant. So: |
| |
| ```dart |
| test(List<int> list) { |
| switch (list) { |
| case [1, 2]: print('Matched'); break; |
| default: print('Did not match'); break; |
| } |
| } |
| |
| main() { |
| test(const [1, 2]); // Prints "Matched". |
| test([1, 2]); // Prints "Did not match". |
| } |
| ``` |
| |
| With patterns, a list or map literal becomes a list or map pattern. The pattern |
| destructures the incoming object and matches if the subpatterns all match. In |
| other words, list and map pattern match using something more like deep equality. |
| |
| With Dart 3.0, the above program prints "Matched" twice. |
| |
| **Constant constructor calls.** Similar to collections, you can construct a |
| constant instance of a class in a case: |
| |
| ```dart |
| class Point { |
| final int x; |
| final int y; |
| const Point({this.x, this.y}); |
| } |
| |
| test(Point p) { |
| switch (p) { |
| case Point(x: 1, y: 2): print('Matched'); break; |
| default: print('Did not match'); break; |
| } |
| } |
| |
| main() { |
| test(const Point(1, 2)); // Prints "Matched". |
| test(Point(1, 2)); // Prints "Did not match". |
| } |
| ``` |
| |
| Again, like collections, the case currently only matches if the incoming value |
| has the same identity. With patterns, the `Point(...)` syntax becomes an object |
| pattern that destructures the incoming point, calls the `x` and `y` getters on |
| it and then matches the results of those against the corresponding subpatterns. |
| |
| In this example, it will print "Matched" twice. |
| |
| Note that object patterns only support named fields. So any constant constructor |
| in a case today that has positional arguments will become a compile-time error |
| when parsed as a pattern. A constant constructor call with no arguments is a |
| valid object pattern and only does a type test: |
| |
| ```dart |
| class Thing { |
| const Thing(); |
| } |
| |
| test(Thing t) { |
| switch (t) { |
| case Thing(): print('Matched'); break; |
| default: print('Did not match'); break; |
| } |
| } |
| |
| main() { |
| test(const Thing()); // Prints "Matched". |
| test(Thing()); // Prints "Did not match". |
| } |
| ``` |
| |
| When interpreted as a pattern, this prints "Matched" twice. |
| |
| **Wildcards.** Today, you can have a constant named `_`: |
| |
| ```dart |
| test(int n) { |
| const _ = 3; |
| switch (n) { |
| case _: print('Matched'); break; |
| default: print('Did not match'); break; |
| } |
| } |
| |
| main() { |
| test(3); // Prints "Matched". |
| test(5); // Prints "Did not match". |
| } |
| ``` |
| |
| With patterns, the identifier `_` is treated as a pattern that matches all |
| values, so this prints "Matched" twice. |
| |
| **Logic operators.** The logic operators `&&` and `||` are valid constant |
| expressions and also valid patterns. As a constant expression, they simply |
| evaluate the expression to a boolean and match if the incoming value is equal to |
| that boolean value. So: |
| |
| ```dart |
| test(bool b) { |
| switch (b) { |
| case true && false: print('Matched'); break; |
| default: print('Did not match'); break; |
| } |
| } |
| |
| main() { |
| test(false); // Prints "Matched". |
| test(true); // Prints "Did not match". |
| } |
| ``` |
| |
| With Dart 3.0, these become patterns. The above example prints "Did not match" |
| twice because no boolean value can be both true and false. |
| |
| Many of invalid cases can be mechanically changed to something that is valid |
| both in Dart today and valid and means the same in Dart 3.0. |
| |
| **Parenthesized expressions:** Provided the inner expression is one that's not |
| broken in Dart 3.0, just discard the parentheses. |
| |
| **List literals, map literals, set literals, and constant constructor calls:** |
| Put `const` before the literal or call. This turns it into a constant pattern |
| which preserves the current behavior: |
| |
| **BAD:** |
| |
| ```dart |
| case [1, 2]: |
| case {'k': 'v'}: |
| case {1, 2}: |
| case Point(1, 2): |
| ``` |
| |
| **GOOD:** |
| |
| ```dart |
| case const [1, 2]: |
| case const {'k': 'v'}: |
| case const {1, 2}: |
| case const Point(1, 2): |
| ``` |
| |
| * **Wildcards:** Rename the constant from `_` to something else. Since the name |
| is private, this can be done locally in the library without affecting other |
| code. |
| |
| * **Everything else:** For any other invalid expression, you have to hoist the |
| expression out into a new named constant. For example, if you have code like |
| this: |
| |
| |
| **BAD:** |
| |
| ```dart |
| switch (n) { |
| case 1 + 2: ... |
| } |
| ``` |
| |
| It can be fixed by changing it to: |
| |
| **GOOD:** |
| |
| ```dart |
| const three = 1 + 2; |
| |
| switch (n) { |
| case three: ... |
| } |
| ``` |
| invalid_runtime_check_with_js_interop_types_dart_as_js: |
| sharedName: invalid_runtime_check_with_js_interop_types |
| problemMessage: "Cast from '{0}' to '{1}' casts a Dart value to a JS interop type, which might not be platform-consistent." |
| correctionMessage: "Try using conversion methods from 'dart:js_interop' to convert between Dart types and JS interop types." |
| state: |
| stable: "3.5" |
| categories: [errorProne, web] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an `is` test has either: |
| - a JS interop type on the right-hand side, whether directly or as a type |
| argument to another type, or |
| - a JS interop value on the left-hand side. |
| |
| #### Examples |
| |
| The following code produces this diagnostic because the JS interop type |
| `JSBoolean` is on the right-hand side of an `is` test: |
| |
| ```dart |
| import 'dart:js_interop'; |
| |
| bool f(Object b) => [!b is JSBoolean!]; |
| ``` |
| |
| The following code produces this diagnostic because the JS interop type |
| `JSString` is used as a type argument on the right-hand side of an `is` |
| test: |
| |
| ```dart |
| import 'dart:js_interop'; |
| |
| bool f(List<Object> l) => [!l is List<JSString>!]; |
| ``` |
| |
| The following code produces this diagnostic because the JS interop value |
| `a` is on the left-hand side of an `is` test: |
| |
| ```dart |
| import 'dart:js_interop'; |
| |
| bool f(JSAny a) => [!a is String!]; |
| ``` |
| |
| #### Common fixes |
| |
| Use a JS interop helper, such as `isA`, to check the underlying type of |
| JS interop values: |
| |
| ```dart |
| import 'dart:js_interop'; |
| |
| void f(Object b) => b.jsify()?.isA<JSBoolean>(); |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use `is` checks where the type is a JS interop type. |
| |
| **DON'T** use `is` checks where the type is a generic Dart type that has JS |
| interop type arguments. |
| |
| **DON'T** use `is` checks with a JS interop value. |
| |
| `dart:js_interop` types have runtime types that are different based on whether |
| you are compiling to JS or to Wasm. Therefore, runtime type checks may result in |
| different behavior. Runtime checks also do not necessarily check that a JS |
| interop value is a particular JavaScript type. |
| |
| **BAD:** |
| ```dart |
| extension type HTMLElement(JSObject o) {} |
| extension type HTMLDivElement(JSObject o) implements HTMLElement {} |
| |
| void compute(JSAny a, bool b, List<JSObject> lo, List<String> ls, JSObject o, |
| HTMLElement e) { |
| a is String; // LINT, checking that a JS value is a Dart type |
| b is JSBoolean; // LINT, checking that a Dart value is a JS type |
| a is JSString; // LINT, checking that a JS value is a different JS interop |
| // type |
| o is JSNumber; // LINT, checking that a JS value is a different JS interop |
| // type |
| lo is List<String>; // LINT, JS interop type argument and Dart type argument |
| // are incompatible |
| ls is List<JSString>; // LINT, Dart type argument and JS interop type argument |
| // are incompatible |
| lo is List<JSArray>; // LINT, comparing JS interop type argument with |
| // different JS interop type argument |
| lo is List<JSNumber>; // LINT, comparing JS interop type argument with |
| // different JS interop type argument |
| o is HTMLElement; // LINT, true because both are JSObjects but doesn't check |
| // that it's a JS HTMLElement |
| e is HTMLDivElement; // LINT, true because both are JSObjects but doesn't |
| // check that it's a JS HTMLDivElement |
| } |
| ``` |
| |
| Prefer using JS interop helpers like `isA` from `dart:js_interop` to check the |
| underlying type of JS interop values. |
| |
| **GOOD:** |
| ```dart |
| extension type HTMLElement(JSObject o) implements JSObject {} |
| extension type HTMLDivElement(JSObject o) implements HTMLElement {} |
| |
| void compute(JSAny a, List<JSAny> l, JSObject o, HTMLElement e) { |
| a.isA<JSString>; // OK, uses JS interop to check it is a JS string |
| l[0].isA<JSString>; // OK, uses JS interop to check it is a JS string |
| o.isA<HTMLElement>(); // OK, uses JS interop to check `o` is an HTMLElement |
| e.isA<HTMLDivElement>(); // OK, uses JS interop to check `e` is an |
| // HTMLDivElement |
| } |
| ``` |
| |
| **DON'T** use `as` to cast a JS interop value to an unrelated Dart type or an |
| unrelated Dart value to a JS interop type. |
| |
| **DON'T** use `as` to cast a JS interop value to a JS interop type represented |
| by an incompatible `dart:js_interop` type. |
| |
| **BAD:** |
| ```dart |
| extension type Window(JSObject o) {} |
| |
| void compute(String s, JSBoolean b, Window w, List<String> l, |
| List<JSObject> lo) { |
| s as JSString; // LINT, casting Dart type to JS interop type |
| b as bool; // LINT, casting JS interop type to Dart type |
| b as JSNumber; // LINT, JSBoolean and JSNumber are incompatible |
| b as Window; // LINT, JSBoolean and JSObject are incompatible |
| w as JSBoolean; // LINT, JSObject and JSBoolean are incompatible |
| l as List<JSString>; // LINT, casting Dart value with Dart type argument to |
| // Dart type with JS interop type argument |
| lo as List<String>; // LINT, casting Dart value with JS interop type argument |
| // to Dart type with Dart type argument |
| lo as List<JSBoolean>; // LINT, casting Dart value with JS interop type |
| // argument to Dart type with incompatible JS interop |
| // type argument |
| } |
| ``` |
| |
| Prefer using `dart:js_interop` conversion methods to convert a JS interop value |
| to a Dart value and vice versa. |
| |
| **GOOD:** |
| ```dart |
| extension type Window(JSObject o) {} |
| extension type Document(JSObject o) {} |
| |
| void compute(String s, JSBoolean b, Window w, JSArray<JSString> a, |
| List<String> ls, JSObject o, List<JSAny> la) { |
| s.toJS; // OK, converts the Dart type to a JS type |
| b.toDart; // OK, converts the JS type to a Dart type |
| a.toDart; // OK, converts the JS type to a Dart type |
| w as Document; // OK, but no runtime check that `w` is a JS Document |
| ls.map((e) => e.toJS).toList(); // OK, converts the Dart types to JS types |
| o as JSArray<JSString>; // OK, JSObject and JSArray are compatible |
| la as List<JSString>; // OK, JSAny and JSString are compatible |
| (o as Object) as JSObject; // OK, Object is a supertype of JSAny |
| } |
| ``` |
| invalid_runtime_check_with_js_interop_types_dart_is_js: |
| sharedName: invalid_runtime_check_with_js_interop_types |
| problemMessage: "Runtime check between '{0}' and '{1}' checks whether a Dart value is a JS interop type, which might not be platform-consistent." |
| hasPublishedDocs: false |
| invalid_runtime_check_with_js_interop_types_js_as_dart: |
| sharedName: invalid_runtime_check_with_js_interop_types |
| problemMessage: "Cast from '{0}' to '{1}' casts a JS interop value to a Dart type, which might not be platform-consistent." |
| correctionMessage: "Try using conversion methods from 'dart:js_interop' to convert between JS interop types and Dart types." |
| hasPublishedDocs: false |
| invalid_runtime_check_with_js_interop_types_js_as_incompatible_js: |
| sharedName: invalid_runtime_check_with_js_interop_types |
| problemMessage: "Cast from '{0}' to '{1}' casts a JS interop value to an incompatible JS interop type, which might not be platform-consistent." |
| hasPublishedDocs: false |
| invalid_runtime_check_with_js_interop_types_js_is_dart: |
| sharedName: invalid_runtime_check_with_js_interop_types |
| problemMessage: "Runtime check between '{0}' and '{1}' checks whether a JS interop value is a Dart type, which might not be platform-consistent." |
| hasPublishedDocs: false |
| invalid_runtime_check_with_js_interop_types_js_is_inconsistent_js: |
| sharedName: invalid_runtime_check_with_js_interop_types |
| problemMessage: "Runtime check between '{0}' and '{1}' involves a non-trivial runtime check between two JS interop types that might not be platform-consistent." |
| correctionMessage: "Try using a JS interop member like 'isA' from 'dart:js_interop' to check the underlying type of JS interop values." |
| hasPublishedDocs: false |
| invalid_runtime_check_with_js_interop_types_js_is_unrelated_js: |
| sharedName: invalid_runtime_check_with_js_interop_types |
| problemMessage: "Runtime check between '{0}' and '{1}' involves a runtime check between a JS interop value and an unrelated JS interop type that will always be true and won't check the underlying type." |
| correctionMessage: "Try using a JS interop member like 'isA' from 'dart:js_interop' to check the underlying type of JS interop values, or make the JS interop type a supertype using 'implements'." |
| hasPublishedDocs: false |
| invariant_booleans: |
| state: |
| stable: "2.0" |
| removed: "3.0" |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| NOTE: This rule is removed in Dart 3.0.0; it is no longer functional. |
| |
| **DON'T** test for conditions that can be inferred at compile time or test the |
| same condition twice. |
| |
| Conditional statements using a condition which cannot be anything but `false` |
| have the effect of making blocks of code non-functional. If the condition |
| cannot evaluate to anything but `true`, the conditional statement is completely |
| redundant, and makes the code less readable. |
| It is quite likely that the code does not match the programmer's intent. |
| Either the condition should be removed or it should be updated so that it does |
| not always evaluate to `true` or `false` and does not perform redundant tests. |
| This rule will hint to the test conflicting with the linted one. |
| |
| **BAD:** |
| ```dart |
| // foo can't be both equal and not equal to bar in the same expression |
| if(foo == bar && something && foo != bar) {...} |
| ``` |
| |
| **BAD:** |
| ```dart |
| void compute(int foo) { |
| if (foo == 4) { |
| doSomething(); |
| // we know foo is equal to 4 at this point, so the next condition is always false |
| if (foo > 4) {...} |
| ... |
| } |
| ... |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void compute(bool foo) { |
| if (foo) { |
| return; |
| } |
| doSomething(); |
| // foo is always false here |
| if (foo){...} |
| ... |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void nestedOK() { |
| if (foo == bar) { |
| foo = baz; |
| if (foo != bar) {...} |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void nestedOk2() { |
| if (foo == bar) { |
| return; |
| } |
| |
| foo = baz; |
| if (foo == bar) {...} // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void nestedOk5() { |
| if (foo != null) { |
| if (bar != null) { |
| return; |
| } |
| } |
| |
| if (bar != null) {...} // OK |
| } |
| ``` |
| iterable_contains_unrelated_type: |
| state: |
| stable: "2.0" |
| removed: "3.3" |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| NOTE: This rule is removed in Dart 3.3.0; it is no longer functional. |
| |
| **DON'T** invoke `contains` on `Iterable` with an instance of different type |
| than the parameter type. |
| |
| Doing this will invoke `==` on its elements and most likely will return `false`. |
| |
| **BAD:** |
| ```dart |
| void someFunction() { |
| var list = <int>[]; |
| if (list.contains('1')) print('someFunction'); // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void someFunction3() { |
| List<int> list = <int>[]; |
| if (list.contains('1')) print('someFunction3'); // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void someFunction8() { |
| List<DerivedClass2> list = <DerivedClass2>[]; |
| DerivedClass3 instance; |
| if (list.contains(instance)) print('someFunction8'); // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| abstract class SomeIterable<E> implements Iterable<E> {} |
| |
| abstract class MyClass implements SomeIterable<int> { |
| bool badMethod(String thing) => this.contains(thing); // LINT |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction10() { |
| var list = []; |
| if (list.contains(1)) print('someFunction10'); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction1() { |
| var list = <int>[]; |
| if (list.contains(1)) print('someFunction1'); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction4() { |
| List<int> list = <int>[]; |
| if (list.contains(1)) print('someFunction4'); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction5() { |
| List<ClassBase> list = <ClassBase>[]; |
| DerivedClass1 instance; |
| if (list.contains(instance)) print('someFunction5'); // OK |
| } |
| |
| abstract class ClassBase {} |
| |
| class DerivedClass1 extends ClassBase {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction6() { |
| List<Mixin> list = <Mixin>[]; |
| DerivedClass2 instance; |
| if (list.contains(instance)) print('someFunction6'); // OK |
| } |
| |
| abstract class ClassBase {} |
| |
| abstract class Mixin {} |
| |
| class DerivedClass2 extends ClassBase with Mixin {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction7() { |
| List<Mixin> list = <Mixin>[]; |
| DerivedClass3 instance; |
| if (list.contains(instance)) print('someFunction7'); // OK |
| } |
| |
| abstract class ClassBase {} |
| |
| abstract class Mixin {} |
| |
| class DerivedClass3 extends ClassBase implements Mixin {} |
| ``` |
| join_return_with_assignment: |
| problemMessage: "Assignment could be inlined in 'return' statement." |
| correctionMessage: "Try inlining the assigned value in the 'return' statement." |
| state: |
| stable: "2.0" |
| categories: [brevity, style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DO** join return statement with assignment when possible. |
| |
| **BAD:** |
| ```dart |
| class A { |
| B _lazyInstance; |
| static B get instance { |
| _lazyInstance ??= B(); // LINT |
| return _lazyInstance; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| B _lazyInstance; |
| static B get instance => _lazyInstance ??= B(); |
| } |
| ``` |
| leading_newlines_in_multiline_strings: |
| problemMessage: "Missing a newline at the beginning of a multiline string." |
| correctionMessage: "Try adding a newline at the beginning of the string." |
| state: |
| stable: "2.8" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Multiline strings are easier to read when they start with a newline (a newline |
| starting a multiline string is ignored). |
| |
| **BAD:** |
| ```dart |
| var s1 = '''{ |
| "a": 1, |
| "b": 2 |
| }'''; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var s1 = ''' |
| { |
| "a": 1, |
| "b": 2 |
| }'''; |
| |
| var s2 = '''This one-liner multiline string is ok. It usually allows to escape both ' and " in the string.'''; |
| ``` |
| library_annotations: |
| problemMessage: "This annotation should be attached to a library directive." |
| correctionMessage: "Try attaching the annotation to a library directive." |
| state: |
| stable: "2.19" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an annotation that applies to |
| a whole library isn't associated with a `library` directive. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the `TestOn` |
| annotation, which applies to the whole library, is associated with an |
| `import` directive rather than a `library` directive: |
| |
| ```dart |
| [!@TestOn('browser')!] |
| |
| import 'package:test/test.dart'; |
| |
| void main() {} |
| ``` |
| |
| #### Common fixes |
| |
| Associate the annotation with a `library` directive, adding one if |
| necessary: |
| |
| ```dart |
| @TestOn('browser') |
| library; |
| |
| import 'package:test/test.dart'; |
| |
| void main() {} |
| ``` |
| deprecatedDetails: |- |
| Attach library annotations to library directives, rather than |
| some other library-level element. |
| |
| **BAD:** |
| ```dart |
| @TestOn('browser') |
| |
| import 'package:test/test.dart'; |
| |
| void main() {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| @TestOn('browser') |
| library; |
| |
| import 'package:test/test.dart'; |
| |
| void main() {} |
| ``` |
| |
| **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. |
| library_names: |
| problemMessage: "The library name '{0}' isn't a lower_case_with_underscores identifier." |
| correctionMessage: "Try changing the name to follow the lower_case_with_underscores style." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the name of a library doesn't |
| use the lower_case_with_underscores naming convention. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the library name |
| `libraryName` isn't a lower_case_with_underscores identifier: |
| |
| ```dart |
| library [!libraryName!]; |
| ``` |
| |
| #### Common fixes |
| |
| If the library name is not required, then remove the library name: |
| |
| ```dart |
| library; |
| ``` |
| |
| If the library name is required, then convert it to use the |
| lower_case_with_underscores naming convention: |
| |
| ```dart |
| library library_name; |
| ``` |
| deprecatedDetails: |- |
| **DO** name libraries using `lowercase_with_underscores`. |
| |
| Some file systems are not case-sensitive, so many projects require filenames to |
| be all lowercase. Using a separating character allows names to still be readable |
| in that form. Using underscores as the separator ensures that the name is still |
| a valid Dart identifier, which may be helpful if the language later supports |
| symbolic imports. |
| |
| **BAD:** |
| ```dart |
| library peg-parser; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| library peg_parser; |
| ``` |
| |
| The lint `file_names` can be used to enforce the same kind of naming on the |
| file. |
| library_prefixes: |
| problemMessage: "The prefix '{0}' isn't a lower_case_with_underscores identifier." |
| correctionMessage: "Try changing the prefix to follow the lower_case_with_underscores style." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an import prefix doesn't use |
| the lower_case_with_underscores naming convention. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the prefix |
| `ffiSupport` isn't a lower_case_with_underscores identifier: |
| |
| ```dart |
| import 'package:ffi/ffi.dart' as [!ffiSupport!]; |
| ``` |
| |
| #### Common fixes |
| |
| Convert the prefix to use the lower_case_with_underscores naming |
| convention: |
| |
| ```dart |
| import 'package:ffi/ffi.dart' as ffi_support; |
| ``` |
| deprecatedDetails: |- |
| **DO** use `lowercase_with_underscores` when specifying a library prefix. |
| |
| **BAD:** |
| ```dart |
| import 'dart:math' as Math; |
| import 'dart:json' as JSON; |
| import 'package:js/js.dart' as JS; |
| import 'package:javascript_utils/javascript_utils.dart' as jsUtils; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| import 'dart:math' as math; |
| import 'dart:json' as json; |
| import 'package:js/js.dart' as js; |
| import 'package:javascript_utils/javascript_utils.dart' as js_utils; |
| ``` |
| library_private_types_in_public_api: |
| problemMessage: "Invalid use of a private type in a public API." |
| correctionMessage: "Try making the private type public, or making the API that uses the private type also be private." |
| state: |
| stable: "2.14" |
| categories: [publicInterface] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a type that is not part of the |
| public API of a library is referenced in the public API of that library. |
| |
| Using a private type in a public API can make the API unusable outside the |
| defining library. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the parameter `c` of |
| the public function `f` has a type that is library private (`_C`): |
| |
| ```dart |
| void f([!_C!] c) {} |
| |
| class _C {} |
| ``` |
| |
| #### Common fixes |
| |
| If the API doesn't need to be used outside the defining library, then make |
| it private: |
| |
| ```dart |
| void _f(_C c) {} |
| |
| class _C {} |
| ``` |
| |
| If the API needs to be part of the public API of the library, then either |
| use a different type that's public, or make the referenced type public: |
| |
| ```dart |
| void f(C c) {} |
| |
| class C {} |
| ``` |
| deprecatedDetails: |- |
| **AVOID** using library private types in public APIs. |
| |
| For the purposes of this lint, a public API is considered to be any top-level or |
| member declaration unless the declaration is library private or contained in a |
| declaration that's library private. The following uses of types are checked: |
| |
| - the return type of a function or method, |
| - the type of any parameter of a function or method, |
| - the bound of a type parameter to any function, method, class, mixin, |
| extension's extended type, or type alias, |
| - the type of any top level variable or field, |
| - any type used in the declaration of a type alias (for example |
| `typedef F = _Private Function();`), or |
| - any type used in the `on` clause of an extension or a mixin |
| |
| **BAD:** |
| ```dart |
| f(_Private p) { ... } |
| class _Private {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| f(String s) { ... } |
| ``` |
| lines_longer_than_80_chars: |
| problemMessage: "The line length exceeds the 80-character limit." |
| correctionMessage: "Try breaking the line across multiple lines." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **AVOID** lines longer than 80 characters |
| |
| Readability studies show that long lines of text are harder to read because your |
| eye has to travel farther when moving to the beginning of the next line. This is |
| why newspapers and magazines use multiple columns of text. |
| |
| If you really find yourself wanting lines longer than 80 characters, our |
| experience is that your code is likely too verbose and could be a little more |
| compact. The main offender is usually `VeryLongCamelCaseClassNames`. Ask |
| yourself, “Does each word in that type name tell me something critical or |
| prevent a name collision?” If not, consider omitting it. |
| |
| Note that `dart format` does 99% of this for you, but the last 1% is you. It |
| does not split long string literals to fit in 80 columns, so you have to do |
| that manually. |
| |
| We make an exception for URIs and file paths. When those occur in comments or |
| strings (usually in imports and exports), they may remain on a single line even |
| if they go over the line limit. This makes it easier to search source files for |
| a given path. |
| list_remove_unrelated_type: |
| state: |
| stable: "2.0" |
| removed: "3.3" |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| NOTE: This rule is removed in Dart 3.3.0; it is no longer functional. |
| |
| **DON'T** invoke `remove` on `List` with an instance of different type than |
| the parameter type. |
| |
| Doing this will invoke `==` on its elements and most likely will |
| return `false`. |
| |
| **BAD:** |
| ```dart |
| void someFunction() { |
| var list = <int>[]; |
| if (list.remove('1')) print('someFunction'); // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void someFunction3() { |
| List<int> list = <int>[]; |
| if (list.remove('1')) print('someFunction3'); // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void someFunction8() { |
| List<DerivedClass2> list = <DerivedClass2>[]; |
| DerivedClass3 instance; |
| if (list.remove(instance)) print('someFunction8'); // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| abstract class SomeList<E> implements List<E> {} |
| |
| abstract class MyClass implements SomeList<int> { |
| bool badMethod(String thing) => this.remove(thing); // LINT |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction10() { |
| var list = []; |
| if (list.remove(1)) print('someFunction10'); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction1() { |
| var list = <int>[]; |
| if (list.remove(1)) print('someFunction1'); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction4() { |
| List<int> list = <int>[]; |
| if (list.remove(1)) print('someFunction4'); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction5() { |
| List<ClassBase> list = <ClassBase>[]; |
| DerivedClass1 instance; |
| if (list.remove(instance)) print('someFunction5'); // OK |
| } |
| |
| abstract class ClassBase {} |
| |
| class DerivedClass1 extends ClassBase {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction6() { |
| List<Mixin> list = <Mixin>[]; |
| DerivedClass2 instance; |
| if (list.remove(instance)) print('someFunction6'); // OK |
| } |
| |
| abstract class ClassBase {} |
| |
| abstract class Mixin {} |
| |
| class DerivedClass2 extends ClassBase with Mixin {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction7() { |
| List<Mixin> list = <Mixin>[]; |
| DerivedClass3 instance; |
| if (list.remove(instance)) print('someFunction7'); // OK |
| } |
| |
| abstract class ClassBase {} |
| |
| abstract class Mixin {} |
| |
| class DerivedClass3 extends ClassBase implements Mixin {} |
| ``` |
| literal_only_boolean_expressions: |
| problemMessage: "The Boolean expression has a constant value." |
| correctionMessage: "Try changing the expression." |
| state: |
| experimental: "2.0" |
| stable: "2.2" |
| categories: [unusedCode] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the value of the condition in |
| an `if` or loop statement is known to be either always `true` or always |
| `false`. An exception is made for a `while` loop whose condition is the |
| Boolean literal `true`. |
| |
| #### Examples |
| |
| The following code produces this diagnostic because the condition will |
| always evaluate to `true`: |
| |
| ```dart |
| void f() { |
| [!if (true) { |
| print('true'); |
| }!] |
| } |
| ``` |
| |
| The lint will evaluate a subset of expressions that are composed of |
| constants, so the following code will also produce this diagnostic because |
| the condition will always evaluate to `false`: |
| |
| ```dart |
| void g(int i) { |
| [!if (1 == 0 || 3 > 4) { |
| print('false'); |
| }!] |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the condition is wrong, then correct the condition so that it's value |
| can't be known at compile time: |
| |
| ```dart |
| void g(int i) { |
| if (i == 0 || i > 4) { |
| print('false'); |
| } |
| } |
| ``` |
| |
| If the condition is correct, then simplify the code to not evaluate the |
| condition: |
| |
| ```dart |
| void f() { |
| print('true'); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** test for conditions composed only by literals, since the value can be |
| inferred at compile time. |
| |
| Conditional statements using a condition which cannot be anything but FALSE have |
| the effect of making blocks of code non-functional. If the condition cannot |
| evaluate to anything but `true`, the conditional statement is completely |
| redundant, and makes the code less readable. |
| It is quite likely that the code does not match the programmer's intent. |
| Either the condition should be removed or it should be updated so that it does |
| not always evaluate to `true` or `false`. |
| |
| **BAD:** |
| ```dart |
| void bad() { |
| if (true) {} // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void bad() { |
| if (true && 1 != 0) {} // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void bad() { |
| if (1 != 0 && true) {} // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void bad() { |
| if (1 < 0 && true) {} // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void bad() { |
| if (true && false) {} // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void bad() { |
| if (1 != 0) {} // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void bad() { |
| if (true && 1 != 0 || 3 < 4) {} // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void bad() { |
| if (1 != 0 || 3 < 4 && true) {} // LINT |
| } |
| ``` |
| |
| **NOTE:** that an exception is made for the common `while (true) { }` idiom, |
| which is often reasonably preferred to the equivalent `for (;;)`. |
| |
| **GOOD:** |
| ```dart |
| void good() { |
| while (true) { |
| // Do stuff. |
| } |
| } |
| ``` |
| matching_super_parameters: |
| problemMessage: "The super parameter named '{0}'' does not share the same name as the corresponding parameter in the super constructor, '{1}'." |
| correctionMessage: "Try using the name of the corresponding parameter in the super constructor." |
| state: |
| stable: "3.0" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DO** use super parameter names that match their corresponding super |
| constructor's parameter names. |
| |
| **BAD:** |
| |
| ```dart |
| class Rectangle { |
| final int width; |
| final int height; |
| |
| Rectangle(this.width, this.height); |
| } |
| |
| class ColoredRectangle extends Rectangle { |
| final Color color; |
| |
| ColoredRectangle( |
| this.color, |
| super.height, // Bad, actually corresponds to the `width` parameter. |
| super.width, // Bad, actually corresponds to the `height` parameter. |
| ); |
| } |
| ``` |
| |
| **GOOD:** |
| |
| ```dart |
| class Rectangle { |
| final int width; |
| final int height; |
| |
| Rectangle(this.width, this.height); |
| } |
| |
| class ColoredRectangle extends Rectangle { |
| final Color color; |
| |
| ColoredRectangle( |
| this.color, |
| super.width, |
| super.height, |
| ); |
| } |
| ``` |
| missing_code_block_language_in_doc_comment: |
| problemMessage: "The code block is missing a specified language." |
| correctionMessage: "Try adding a language to the code block." |
| state: |
| stable: "3.4" |
| categories: [errorProne] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DO** specify the language used in the code block of a doc comment. |
| |
| To enable proper syntax highlighting of Markdown code blocks, |
| [`dart doc`](https://dart.dev/tools/dart-doc) strongly recommends code blocks to |
| specify the language used after the initial code fence. |
| |
| See [highlight.js](https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md) |
| for the list of languages supported by `dart doc`. |
| To disable syntax highlighting or if no language is suitable, |
| you can specify `none` as the language. |
| |
| **BAD:** |
| ```dart |
| /// ``` |
| /// void main() {} |
| /// ``` |
| class A {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| /// ```dart |
| /// void main() {} |
| /// ``` |
| class A {} |
| ``` |
| missing_whitespace_between_adjacent_strings: |
| problemMessage: "Missing whitespace between adjacent strings." |
| correctionMessage: "Try adding whitespace between the strings." |
| state: |
| stable: "2.8" |
| categories: [errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic for a pair of adjacent string |
| literals unless either the left-hand string ends in whitespace or the |
| right-hand string begins with whitespace. |
| |
| #### Example |
| |
| The following code produces this diagnostic because neither the left nor |
| the right string literal includes a space to separate the words that will |
| be joined: |
| |
| ```dart |
| var s = |
| [!'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed'!] |
| 'do eiusmod tempor incididunt ut labore et dolore magna'; |
| ``` |
| |
| #### Common fixes |
| |
| Add whitespace at the end of the left-hand literal or at the beginning of |
| the right-hand literal: |
| |
| ```dart |
| var s = |
| 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed ' |
| 'do eiusmod tempor incididunt ut labore et dolore magna'; |
| ``` |
| deprecatedDetails: |- |
| Add a trailing whitespace to prevent missing whitespace between adjacent |
| strings. |
| |
| With long text split across adjacent strings it's easy to forget a whitespace |
| between strings. |
| |
| **BAD:** |
| ```dart |
| var s = |
| 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed' |
| 'do eiusmod tempor incididunt ut labore et dolore magna'; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var s = |
| 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed ' |
| 'do eiusmod tempor incididunt ut labore et dolore magna'; |
| ``` |
| no_adjacent_strings_in_list: |
| problemMessage: "Don't use adjacent strings in a list literal." |
| correctionMessage: "Try adding a comma between the strings." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when two string literals are |
| adjacent in a list literal. Adjacent strings in Dart are concatenated |
| together to form a single string, but the intent might be for each string |
| to be a separate element in the list. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the strings `'a'` and |
| `'b'` are adjacent: |
| |
| ```dart |
| List<String> list = [[!'a' 'b'!], 'c']; |
| ``` |
| |
| #### Common fixes |
| |
| If the two strings are intended to be separate elements of the list, then |
| add a comma between them: |
| |
| ```dart |
| List<String> list = ['a', 'b', 'c']; |
| ``` |
| |
| If the two strings are intended to be a single concatenated string, then |
| either manually merge the strings: |
| |
| ```dart |
| List<String> list = ['ab', 'c']; |
| ``` |
| |
| Or use the `+` operator to concatenate the strings: |
| |
| ```dart |
| List<String> list = ['a' + 'b', 'c']; |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use adjacent strings in a list. |
| |
| This can indicate a forgotten comma. |
| |
| **BAD:** |
| ```dart |
| List<String> list = <String>[ |
| 'a' |
| 'b', |
| 'c', |
| ]; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| List<String> list = <String>[ |
| 'a' + |
| 'b', |
| 'c', |
| ]; |
| ``` |
| no_default_cases: |
| problemMessage: "Invalid use of 'default' member in a switch." |
| correctionMessage: "Try enumerating all the possible values of the switch expression." |
| state: |
| experimental: "2.9" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Switches on enums and enum-like classes should not use a `default` clause. |
| |
| 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 default behavior outside switch statements. |
| |
| **BAD:** |
| ```dart |
| switch (testEnum) { |
| case TestEnum.A: |
| return '123'; |
| case TestEnum.B: |
| return 'abc'; |
| default: |
| return null; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| switch (testEnum) { |
| case TestEnum.A: |
| return '123'; |
| case TestEnum.B: |
| return 'abc'; |
| } |
| // Default here. |
| return null; |
| ``` |
| no_duplicate_case_values: |
| problemMessage: "The value of the case clause ('{0}') is equal to the value of an earlier case clause ('{1}')." |
| correctionMessage: "Try removing or changing the value." |
| state: |
| stable: "2.0" |
| categories: [errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when two or more `case` clauses in |
| the same `switch` statement have the same value. |
| |
| Any `case` clauses after the first can't be executed, so having duplicate |
| `case` clauses is misleading. |
| |
| This diagnostic is often the result of either a typo or a change to the |
| value of a constant. |
| |
| #### Example |
| |
| The following code produces this diagnostic because two case clauses have |
| the same value (1): |
| |
| ```dart |
| // @dart = 2.14 |
| void f(int v) { |
| switch (v) { |
| case 1: |
| break; |
| case [!1!]: |
| break; |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If one of the clauses should have a different value, then change the value |
| of the clause: |
| |
| ```dart |
| void f(int v) { |
| switch (v) { |
| case 1: |
| break; |
| case 2: |
| break; |
| } |
| } |
| ``` |
| |
| If the value is correct, then merge the statements into a single clause: |
| |
| ```dart |
| void f(int v) { |
| switch (v) { |
| case 1: |
| break; |
| } |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use more than one case with same value. |
| |
| This is usually a typo or changed value of constant. |
| |
| **BAD:** |
| ```dart |
| const int A = 1; |
| switch (v) { |
| case 1: |
| case 2: |
| case A: |
| case 2: |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| const int A = 1; |
| switch (v) { |
| case A: |
| case 2: |
| } |
| ``` |
| |
| NOTE: this lint only reports duplicate cases in libraries opted in to Dart 2.19 |
| and below. In Dart 3.0 and after, duplicate cases are reported as dead code |
| by the analyzer. |
| no_leading_underscores_for_library_prefixes: |
| problemMessage: "The library prefix '{0}' starts with an underscore." |
| correctionMessage: "Try renaming the prefix to not start with an underscore." |
| state: |
| stable: "2.16" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the name of a prefix declared |
| on an import starts with an underscore. |
| |
| Library prefixes are inherently not visible outside the declaring library, |
| so a leading underscore indicating private adds no value. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the prefix `_core` |
| starts with an underscore: |
| |
| ```dart |
| import 'dart:core' as [!_core!]; |
| ``` |
| |
| #### Common fixes |
| |
| Remove the underscore: |
| |
| ```dart |
| import 'dart:core' as core; |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use a leading underscore for library prefixes. |
| There is no concept of "private" for library prefixes. When one of those has a |
| name that starts with an underscore, it sends a confusing signal to the reader. |
| To avoid that, don't use leading underscores in those names. |
| |
| **BAD:** |
| ```dart |
| import 'dart:core' as _core; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| import 'dart:core' as core; |
| ``` |
| no_leading_underscores_for_local_identifiers: |
| problemMessage: "The local variable '{0}' starts with an underscore." |
| correctionMessage: "Try renaming the variable to not start with an underscore." |
| state: |
| stable: "2.16" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the name of a local variable |
| starts with an underscore. |
| |
| Local variables are inherently not visible outside the declaring library, |
| so a leading underscore indicating private adds no value. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the parameter `_s` |
| starts with an underscore: |
| |
| ```dart |
| int f(String [!_s!]) => _s.length; |
| ``` |
| |
| #### Common fixes |
| |
| Remove the underscore: |
| |
| ```dart |
| int f(String s) => s.length; |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use a leading underscore for identifiers that aren't private. Dart |
| uses a leading underscore in an identifier to mark members and top-level |
| declarations as private. This trains users to associate a leading underscore |
| with one of those kinds of declarations. They see `_` and think "private". |
| There is no concept of "private" for local variables or parameters. When one of |
| those has a name that starts with an underscore, it sends a confusing signal to |
| the reader. To avoid that, don't use leading underscores in those names. |
| |
| **EXCEPTION:**: An unused parameter can be named `_`, `__`, `___`, etc. This is |
| common practice in callbacks where you are passed a value but you don't need |
| to use it. Giving it a name that consists solely of underscores is the idiomatic |
| way to indicate that the value isn't used. |
| |
| **BAD:** |
| ```dart |
| void print(String _name) { |
| var _size = _name.length; |
| ... |
| } |
| ``` |
| **GOOD:** |
| |
| ```dart |
| void print(String name) { |
| var size = name.length; |
| ... |
| } |
| ``` |
| |
| **OK:** |
| |
| ```dart |
| [1,2,3].map((_) => print('Hello')); |
| ``` |
| no_literal_bool_comparisons: |
| problemMessage: "Unnecessary comparison to a boolean literal." |
| correctionMessage: "Remove the comparison and use the negate `!` operator if necessary." |
| state: |
| stable: "3.0" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-true-or-false-in-equality-operations): |
| |
| **DON'T** use `true` or `false` in equality operations. |
| |
| This lint applies only if the expression is of a non-nullable `bool` type. |
| |
| **BAD:** |
| ```dart |
| if (someBool == true) { |
| print('true!'); |
| } |
| while (someBool == false) { |
| print('still false!'); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| if (someBool) { |
| print('true!'); |
| } |
| while (!someBool) { |
| print('still false!'); |
| } |
| ``` |
| no_logic_in_create_state: |
| problemMessage: "Don't put any logic in 'createState'." |
| correctionMessage: "Try moving the logic out of 'createState'." |
| state: |
| stable: "2.8" |
| categories: [errorProne, flutter] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an implementation of |
| `createState` in a subclass of `StatefulWidget` contains any logic other |
| than the return of the result of invoking a zero argument constructor. |
| |
| #### Examples |
| |
| The following code produces this diagnostic because the constructor |
| invocation has arguments: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| class MyWidget extends StatefulWidget { |
| @override |
| MyState createState() => [!MyState(0)!]; |
| } |
| |
| class MyState extends State { |
| int x; |
| |
| MyState(this.x); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Rewrite the code so that `createState` doesn't contain any logic: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| class MyWidget extends StatefulWidget { |
| @override |
| MyState createState() => MyState(); |
| } |
| |
| class MyState extends State { |
| int x = 0; |
| |
| MyState(); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** put any logic in `createState()`. |
| |
| Implementations of `createState()` should return a new instance |
| of a State object and do nothing more. Since state access is preferred |
| via the `widget` field, passing data to `State` objects using custom |
| constructor parameters should also be avoided and so further, the State |
| constructor is required to be passed no arguments. |
| |
| **BAD:** |
| ```dart |
| MyState global; |
| |
| class MyStateful extends StatefulWidget { |
| @override |
| MyState createState() { |
| global = MyState(); |
| return global; |
| } |
| } |
| ``` |
| |
| ```dart |
| class MyStateful extends StatefulWidget { |
| @override |
| MyState createState() => MyState()..field = 42; |
| } |
| ``` |
| |
| ```dart |
| class MyStateful extends StatefulWidget { |
| @override |
| MyState createState() => MyState(42); |
| } |
| ``` |
| |
| |
| **GOOD:** |
| ```dart |
| class MyStateful extends StatefulWidget { |
| @override |
| MyState createState() { |
| return MyState(); |
| } |
| } |
| ``` |
| no_runtimeType_toString: |
| problemMessage: "Using 'toString' on a 'Type' is not safe in production code." |
| correctionMessage: "Try removing the usage of 'toString' or restructuring the code." |
| state: |
| stable: "2.8" |
| categories: [nonPerformant] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Calling `toString` on a runtime type is a non-trivial operation that can |
| negatively impact performance. It's better to avoid it. |
| |
| **BAD:** |
| ```dart |
| class A { |
| String toString() => '$runtimeType()'; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| String toString() => 'A()'; |
| } |
| ``` |
| |
| This lint has some exceptions where performance is not a problem or where real |
| type information is more important than performance: |
| |
| * in an assertion |
| * in a throw expression |
| * in a catch clause |
| * in a mixin declaration |
| * in an abstract class declaration |
| no_self_assignments: |
| problemMessage: "The variable or property is being assigned to itself." |
| correctionMessage: "Try removing the assignment that has no direct effect." |
| state: |
| stable: "3.1" |
| categories: [unintentional] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DON'T** assign a variable to itself. Usually this is a mistake. |
| |
| **BAD:** |
| ```dart |
| class C { |
| int x; |
| |
| C(int x) { |
| x = x; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class C { |
| int x; |
| |
| C(int x) : x = x; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class C { |
| int x; |
| |
| C(int x) { |
| this.x = x; |
| } |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| class C { |
| int _x = 5; |
| |
| int get x => _x; |
| |
| set x(int x) { |
| _x = x; |
| _customUpdateLogic(); |
| } |
| |
| void _customUpdateLogic() { |
| print('updated'); |
| } |
| |
| void example() { |
| x = x; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class C { |
| int _x = 5; |
| |
| int get x => _x; |
| |
| set x(int x) { |
| _x = x; |
| _customUpdateLogic(); |
| } |
| |
| void _customUpdateLogic() { |
| print('updated'); |
| } |
| |
| void example() { |
| _customUpdateLogic(); |
| } |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| class C { |
| int x = 5; |
| |
| void update(C other) { |
| this.x = this.x; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class C { |
| int x = 5; |
| |
| void update(C other) { |
| this.x = other.x; |
| } |
| } |
| ``` |
| no_wildcard_variable_uses: |
| problemMessage: "The referenced identifier is a wildcard." |
| correctionMessage: "Use an identifier name that is not a wildcard." |
| state: |
| stable: "3.1" |
| categories: [languageFeatureUsage, unintentional] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when either a parameter or local |
| variable whose name consists of only underscores is referenced. Such |
| names will become non-binding in a future version of the Dart language, |
| making the reference illegal. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the name of the |
| parameter consists of two underscores: |
| |
| ```dart |
| // @dart = 3.6 |
| void f(int __) { |
| print([!__!]); |
| } |
| ``` |
| |
| The following code produces this diagnostic because the name of the |
| local variable consists of a single underscore: |
| |
| ```dart |
| // @dart = 3.6 |
| void f() { |
| int _ = 0; |
| print([!_!]); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the variable or parameter is intended to be referenced, then give it a |
| name that has at least one non-underscore character: |
| |
| ```dart |
| void f(int p) { |
| print(p); |
| } |
| ``` |
| |
| If the variable or parameter is not intended to be referenced, then |
| replace the reference with a different expression: |
| |
| ```dart |
| void f() { |
| print(0); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use wildcard parameters or variables. |
| |
| Wildcard parameters and local variables |
| (e.g. underscore-only names like `_`, `__`, `___`, etc.) will |
| become non-binding in a future version of the Dart language. |
| Any existing code that uses wildcard parameters or variables will |
| break. In anticipation of this change, and to make adoption easier, |
| this lint disallows wildcard and variable parameter uses. |
| |
| |
| **BAD:** |
| ```dart |
| var _ = 1; |
| print(_); // LINT |
| ``` |
| |
| ```dart |
| void f(int __) { |
| print(__); // LINT multiple underscores too |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| for (var _ in [1, 2, 3]) count++; |
| ``` |
| |
| ```dart |
| var [a, _, b, _] = [1, 2, 3, 4]; |
| ``` |
| non_constant_identifier_names: |
| problemMessage: "The variable name '{0}' isn't a lowerCamelCase identifier." |
| correctionMessage: "Try changing the name to follow the lowerCamelCase style." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the name of a class member, |
| top-level declaration, variable, parameter, named parameter, or named |
| constructor that isn't declared to be `const`, doesn't use the |
| lowerCamelCase convention. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the top-level variable |
| `Count` doesn't start with a lowercase letter: |
| |
| ```dart |
| var [!Count!] = 0; |
| ``` |
| |
| #### Common fixes |
| |
| Change the name in the declaration to follow the lowerCamelCase |
| convention: |
| |
| ```dart |
| var count = 0; |
| ``` |
| deprecatedDetails: |- |
| **DO** name non-constant identifiers using lowerCamelCase. |
| |
| Class members, top-level definitions, variables, parameters, named parameters |
| and named constructors should capitalize the first letter of each word |
| except the first word, and use no separators. |
| |
| **GOOD:** |
| ```dart |
| var item; |
| |
| HttpRequest httpRequest; |
| |
| align(clearItems) { |
| // ... |
| } |
| ``` |
| noop_primitive_operations: |
| problemMessage: "The expression has no effect and can be removed." |
| correctionMessage: "Try removing the expression." |
| state: |
| stable: "2.14" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Some operations on primitive types are idempotent and can be removed. |
| |
| **BAD:** |
| |
| ```dart |
| doubleValue.toDouble(); |
| |
| intValue.toInt(); |
| intValue.round(); |
| intValue.ceil(); |
| intValue.floor(); |
| intValue.truncate(); |
| |
| string.toString(); |
| string = 'hello\n' |
| '' |
| 'world'; |
| |
| 'string with ${x.toString()}'; |
| ``` |
| |
| Note that the empty string literals at the beginning or end of a string are |
| allowed, as they are typically used to format the string literal across multiple |
| lines: |
| |
| ```dart |
| // OK |
| string = '' |
| 'hello\n' |
| 'world\n'; |
| |
| // OK |
| string = 'hello\n' |
| 'world\n' |
| ''; |
| ``` |
| null_check_on_nullable_type_parameter: |
| problemMessage: "The null check operator shouldn't be used on a variable whose type is a potentially nullable type parameter." |
| correctionMessage: "Try explicitly testing for 'null'." |
| state: |
| experimental: "2.12" |
| stable: "2.17" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a null check operator is used |
| on a variable whose type is `T?`, where `T` is a type parameter that |
| allows the type argument to be nullable (either has no bound or has a |
| bound that is nullable). |
| |
| Given a generic type parameter `T` which has a nullable bound, it is very |
| easy to introduce erroneous null checks when working with a variable of |
| type `T?`. Specifically, it is not uncommon to have `T? x;` and want to |
| assert that `x` has been set to a valid value of type `T`. A common |
| mistake is to do so using `x!`. This is almost always incorrect, because |
| if `T` is a nullable type, `x` may validly hold `null` as a value of type |
| `T`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because `t` has the type `T?` |
| and `T` allows the type argument to be nullable (because it has no |
| `extends` clause): |
| |
| ```dart |
| T f<T>(T? t) => t[!!!]; |
| ``` |
| |
| #### Common fixes |
| |
| Use the type parameter to cast the variable: |
| |
| ```dart |
| T f<T>(T? t) => t as T; |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use `null` check on a potentially nullable type parameter. |
| |
| Given a generic type parameter `T` which has a nullable bound (e.g., the default |
| bound of `Object?`), it is very easy to introduce erroneous `null` checks when |
| working with a variable of type `T?`. Specifically, it is not uncommon to have |
| `T? x;` and want to assert that `x` has been set to a valid value of type `T`. |
| A common mistake is to do so using `x!`. This is almost always incorrect, since |
| if `T` is a nullable type, `x` may validly hold `null` as a value of type `T`. |
| |
| **BAD:** |
| ```dart |
| T run<T>(T callback()) { |
| T? result; |
| (() { result = callback(); })(); |
| return result!; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| T run<T>(T callback()) { |
| T? result; |
| (() { result = callback(); })(); |
| return result as T; |
| } |
| ``` |
| null_closures: |
| problemMessage: "Closure can't be 'null' because it might be invoked." |
| correctionMessage: "Try providing a non-null closure." |
| state: |
| stable: "2.0" |
| categories: [errorProne] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DON'T** pass `null` as an argument where a closure is expected. |
| |
| Often a closure that is passed to a method will only be called conditionally, |
| so that tests and "happy path" production calls do not reveal that `null` will |
| result in an exception being thrown. |
| |
| This rule only catches null literals being passed where closures are expected |
| in the following locations: |
| |
| #### Constructors |
| |
| * From `dart:async` |
| * `Future` at the 0th positional parameter |
| * `Future.microtask` at the 0th positional parameter |
| * `Future.sync` at the 0th positional parameter |
| * `Timer` at the 0th positional parameter |
| * `Timer.periodic` at the 1st positional parameter |
| * From `dart:core` |
| * `List.generate` at the 1st positional parameter |
| |
| #### Static functions |
| |
| * From `dart:async` |
| * `scheduleMicrotask` at the 0th positional parameter |
| * `Future.doWhile` at the 0th positional parameter |
| * `Future.forEach` at the 0th positional parameter |
| * `Future.wait` at the named parameter `cleanup` |
| * `Timer.run` at the 0th positional parameter |
| |
| #### Instance methods |
| |
| * From `dart:async` |
| * `Future.then` at the 0th positional parameter |
| * `Future.complete` at the 0th positional parameter |
| * From `dart:collection` |
| * `Queue.removeWhere` at the 0th positional parameter |
| * `Queue.retain |
| * `Iterable.firstWhere` at the 0th positional parameter, and the named |
| parameter `orElse` |
| * `Iterable.forEach` at the 0th positional parameter |
| * `Iterable.fold` at the 1st positional parameter |
| * `Iterable.lastWhere` at the 0th positional parameter, and the named |
| parameter `orElse` |
| * `Iterable.map` at the 0th positional parameter |
| * `Iterable.reduce` at the 0th positional parameter |
| * `Iterable.singleWhere` at the 0th positional parameter, and the named |
| parameter `orElse` |
| * `Iterable.skipWhile` at the 0th positional parameter |
| * `Iterable.takeWhile` at the 0th positional parameter |
| * `Iterable.where` at the 0th positional parameter |
| * `List.removeWhere` at the 0th positional parameter |
| * `List.retainWhere` at the 0th positional parameter |
| * `String.replaceAllMapped` at the 1st positional parameter |
| * `String.replaceFirstMapped` at the 1st positional parameter |
| * `String.splitMapJoin` at the named parameters `onMatch` and `onNonMatch` |
| |
| **BAD:** |
| ```dart |
| [1, 3, 5].firstWhere((e) => e.isOdd, orElse: null); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| [1, 3, 5].firstWhere((e) => e.isOdd, orElse: () => null); |
| ``` |
| omit_local_variable_types: |
| problemMessage: "Unnecessary type annotation on a local variable." |
| correctionMessage: "Try removing the type annotation." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DON'T** redundantly type annotate initialized local variables. |
| |
| Local variables, especially in modern code where functions tend to be small, |
| have very little scope. Omitting the type focuses the reader's attention on the |
| more important *name* of the variable and its initialized value. |
| |
| **BAD:** |
| ```dart |
| List<List<Ingredient>> possibleDesserts(Set<Ingredient> pantry) { |
| List<List<Ingredient>> desserts = <List<Ingredient>>[]; |
| for (final List<Ingredient> recipe in cookbook) { |
| if (pantry.containsAll(recipe)) { |
| desserts.add(recipe); |
| } |
| } |
| |
| return desserts; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| List<List<Ingredient>> possibleDesserts(Set<Ingredient> pantry) { |
| var desserts = <List<Ingredient>>[]; |
| for (final recipe in cookbook) { |
| if (pantry.containsAll(recipe)) { |
| desserts.add(recipe); |
| } |
| } |
| |
| return desserts; |
| } |
| ``` |
| |
| Sometimes the inferred type is not the type you want the variable to have. For |
| example, you may intend to assign values of other types later. In that case, |
| annotate the variable with the type you want. |
| |
| **GOOD:** |
| ```dart |
| Widget build(BuildContext context) { |
| Widget result = Text('You won!'); |
| if (applyPadding) { |
| result = Padding(padding: EdgeInsets.all(8.0), child: result); |
| } |
| return result; |
| } |
| ``` |
| omit_obvious_local_variable_types: |
| problemMessage: "Omit the type annotation on a local variable when the type is obvious." |
| correctionMessage: "Try removing the type annotation." |
| state: |
| experimental: "3.6" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Don't type annotate initialized local variables when the type is obvious. |
| |
| Local variables, especially in modern code where functions tend to be small, |
| have very little scope. Omitting the type focuses the reader's attention on the |
| more important *name* of the variable and its initialized value. Hence, local |
| variable type annotations that are obvious should be omitted. |
| |
| **BAD:** |
| ```dart |
| List<List<Ingredient>> possibleDesserts(Set<Ingredient> pantry) { |
| List<List<Ingredient>> desserts = <List<Ingredient>>[]; |
| for (final List<Ingredient> recipe in cookbook) { |
| if (pantry.containsAll(recipe)) { |
| desserts.add(recipe); |
| } |
| } |
| |
| return desserts; |
| } |
| |
| const cookbook = <List<Ingredient>>[....]; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| List<List<Ingredient>> possibleDesserts(Set<Ingredient> pantry) { |
| var desserts = <List<Ingredient>>[]; |
| for (final List<Ingredient> recipe in cookbook) { |
| if (pantry.containsAll(recipe)) { |
| desserts.add(recipe); |
| } |
| } |
| |
| return desserts; |
| } |
| |
| const cookbook = <List<Ingredient>>[....]; |
| ``` |
| |
| Sometimes the inferred type is not the type you want the variable to have. For |
| example, you may intend to assign values of other types later. You may also |
| wish to write a type annotation explicitly because the type of the initializing |
| expression is non-obvious and it will be helpful for future readers of the |
| code to document this type. Or you may wish to commit to a specific type such |
| that future updates of dependencies (in nearby code, in imports, anywhere) |
| will not silently change the type of that variable, thus introducing |
| compile-time errors or run-time bugs in locations where this variable is used. |
| In those cases, go ahead and annotate the variable with the type you want. |
| |
| **GOOD:** |
| ```dart |
| Widget build(BuildContext context) { |
| Widget result = someGenericFunction(42) ?? Text('You won!'); |
| if (applyPadding) { |
| result = Padding(padding: EdgeInsets.all(8.0), child: result); |
| } |
| return result; |
| } |
| ``` |
| |
| **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/sdk/issues/58773. |
| omit_obvious_property_types: |
| problemMessage: "The type annotation isn't needed because it is obvious." |
| correctionMessage: "Try removing the type annotation." |
| state: |
| experimental: "3.7" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Don't type annotate initialized top-level or static variables when the type is |
| obvious. |
| |
| **BAD:** |
| ```dart |
| final int myTopLevelVariable = 7; |
| |
| class A { |
| static String myStaticVariable = 'Hello'; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| final myTopLevelVariable = 7; |
| |
| class A { |
| static myStaticVariable = 'Hello'; |
| } |
| ``` |
| |
| Sometimes the inferred type is not the type you want the variable to have. For |
| example, you may intend to assign values of other types later. You may also |
| wish to write a type annotation explicitly because the type of the initializing |
| expression is non-obvious and it will be helpful for future readers of the |
| code to document this type. Or you may wish to commit to a specific type such |
| that future updates of dependencies (in nearby code, in imports, anywhere) |
| will not silently change the type of that variable, thus introducing |
| compile-time errors or run-time bugs in locations where this variable is used. |
| In those cases, go ahead and annotate the variable with the type you want. |
| |
| **GOOD:** |
| ```dart |
| final num myTopLevelVariable = 7; |
| |
| class A { |
| static String? myStaticVariable = 'Hello'; |
| } |
| ``` |
| |
| **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/sdk/issues/59550. |
| one_member_abstracts: |
| problemMessage: "Unnecessary use of an abstract class." |
| correctionMessage: "Try making '{0}' a top-level function and removing the class." |
| state: |
| stable: "2.0" |
| categories: [effectiveDart, languageFeatureUsage, style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/design#avoid-defining-a-one-member-abstract-class-when-a-simple-function-will-do): |
| |
| **AVOID** defining a one-member abstract class when a simple function will do. |
| |
| Unlike Java, Dart has first-class functions, closures, and a nice light syntax |
| for using them. If all you need is something like a callback, just use a |
| function. If you're defining a class and it only has a single abstract member |
| with a meaningless name like `call` or `invoke`, there is a good chance |
| you just want a function. |
| |
| **BAD:** |
| ```dart |
| abstract class Predicate { |
| bool test(item); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| typedef Predicate = bool Function(item); |
| ``` |
| only_throw_errors: |
| problemMessage: "Don't throw instances of classes that don't extend either 'Exception' or 'Error'." |
| correctionMessage: "Try throwing a different class of object." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the value being thrown isn't a |
| subclass of either `Exception` or `Error`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the string `'f'` is |
| being thrown: |
| |
| ```dart |
| void f() => throw [!'f'!]; |
| ``` |
| |
| #### Common fixes |
| |
| Replace the value with an instance of a subclass of either `Exception` or |
| `Error`: |
| |
| ```dart |
| void f() => throw ArgumentError('f'); |
| ``` |
| deprecatedDetails: |- |
| **DO** throw only instances of classes that extend `dart.core.Error` or |
| `dart.core.Exception`. |
| |
| Throwing instances that do not extend `Error` or `Exception` is a bad practice; |
| doing this is usually a hack for something that should be implemented more |
| thoroughly. |
| |
| **BAD:** |
| ```dart |
| void throwString() { |
| throw 'hello world!'; // LINT |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void throwArgumentError() { |
| Error error = ArgumentError('oh!'); |
| throw error; // OK |
| } |
| ``` |
| overridden_fields: |
| problemMessage: "Field overrides a field inherited from '{0}'." |
| correctionMessage: "Try removing the field, overriding the getter and setter if necessary." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a class defines a field that |
| overrides a field from a superclass. |
| |
| Overriding a field with another field causes the object to have two |
| distinct fields, but because the fields have the same name only one of the |
| fields can be referenced in a given scope. That can lead to confusion |
| where a reference to one of the fields can be mistaken for a reference to |
| the other. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the field `f` in `B` |
| shadows the field `f` in `A`: |
| |
| ```dart |
| class A { |
| int f = 1; |
| } |
| |
| class B extends A { |
| @override |
| int [!f!] = 2; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the two fields are representing the same property, then remove the |
| field from the subclass: |
| |
| ```dart |
| class A { |
| int f = 1; |
| } |
| |
| class B extends A {} |
| ``` |
| |
| If the two fields should be distinct, then rename one of the fields: |
| |
| ```dart |
| class A { |
| int f = 1; |
| } |
| |
| class B extends A { |
| int g = 2; |
| } |
| ``` |
| |
| If the two fields are related in some way, but can't be the same, then |
| find a different way to implement the semantics you need. |
| deprecatedDetails: |- |
| **DON'T** override fields. |
| |
| Overriding fields is almost always done unintentionally. Regardless, it is a |
| bad practice to do so. |
| |
| **BAD:** |
| ```dart |
| class Base { |
| Object field = 'lorem'; |
| |
| Object something = 'change'; |
| } |
| |
| class Bad1 extends Base { |
| @override |
| final field = 'ipsum'; // LINT |
| } |
| |
| class Bad2 extends Base { |
| @override |
| Object something = 'done'; // LINT |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Base { |
| Object field = 'lorem'; |
| |
| Object something = 'change'; |
| } |
| |
| class Ok extends Base { |
| Object newField; // OK |
| |
| final Object newFinal = 'ignore'; // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| abstract class BaseLoggingHandler { |
| Base transformer; |
| } |
| |
| class LogPrintHandler implements BaseLoggingHandler { |
| @override |
| Derived transformer; // OK |
| } |
| ``` |
| package_api_docs: |
| problemMessage: "Missing documentation for public API." |
| correctionMessage: "Try adding a documentation comment." |
| state: |
| stable: "2.0" |
| removed: "3.7" |
| categories: [effectiveDart, publicInterface] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **NOTE:** This lint has been removed because it is has not |
| been fully functional since at least Dart 2.0. |
| Remove all inclusions of this lint from your analysis options. |
| |
| **DO** provide doc comments for all public APIs. |
| |
| As described in the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files), |
| public APIs consist in everything in your package's `lib` folder, minus |
| implementation files in `lib/src`, adding elements explicitly exported with an |
| `export` directive. |
| |
| For example, given `lib/foo.dart`: |
| ```dart |
| export 'src/bar.dart' show Bar; |
| export 'src/baz.dart'; |
| |
| class Foo { } |
| |
| class _Foo { } |
| ``` |
| its API includes: |
| |
| * `Foo` (but not `_Foo`) |
| * `Bar` (exported) and |
| * all *public* elements in `src/baz.dart` |
| |
| All public API members should be documented with `///` doc-style comments. |
| |
| **BAD:** |
| ```dart |
| class Bar { |
| void bar(); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| /// A Foo. |
| abstract class Foo { |
| /// Start foo-ing. |
| void start() => _start(); |
| |
| _start(); |
| } |
| ``` |
| |
| Advice for writing good doc comments can be found in the |
| [Doc Writing Guidelines](https://dart.dev/effective-dart/documentation). |
| package_names: |
| problemMessage: "The package name '{0}' isn't a lower_case_with_underscores identifier." |
| correctionMessage: "Try changing the name to follow the lower_case_with_underscores style." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the name of a package doesn't |
| use the lower_case_with_underscores naming convention. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the name of the |
| package uses the lowerCamelCase naming convention: |
| |
| ```yaml |
| name: [!somePackage!] |
| ``` |
| |
| #### Common fixes |
| |
| Rewrite the name of the package using the lower_case_with_underscores |
| naming convention: |
| |
| ```yaml |
| name: some_package |
| ``` |
| deprecatedDetails: |- |
| From the [Pubspec format description](https://dart.dev/tools/pub/pubspec): |
| |
| **DO** use `lowercase_with_underscores` for package names. |
| |
| Package names should be all lowercase, with underscores to separate words, |
| `just_like_this`. Use only basic Latin letters and Arabic digits: \[a-z0-9\_\]. |
| Also, make sure the name is a valid Dart identifier -- that it doesn't start |
| with digits and isn't a reserved word. |
| package_prefixed_library_names: |
| problemMessage: "The library name is not a dot-separated path prefixed by the package name." |
| correctionMessage: "Try changing the name to '{0}'." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a library has a name that |
| doesn't follow these guidelines: |
| |
| - Prefix all library names with the package name. |
| - Make the entry library have the same name as the package. |
| - For all other libraries in a package, after the package name add the |
| dot-separated path to the library's Dart file. |
| - For libraries under `lib`, omit the top directory name. |
| |
| For example, given a package named `my_package`, here are the library |
| names for various files in the package: |
| |
| ```dart |
| // In lib/my_package.dart |
| library my_package; |
| |
| // In lib/other.dart |
| library my_package.other; |
| |
| // In lib/foo/bar.dart |
| library my_package.foo.bar; |
| |
| // In example/foo/bar.dart |
| library my_package.example.foo.bar; |
| |
| // In lib/src/private.dart |
| library my_package.src.private; |
| ``` |
| |
| #### Example |
| |
| Assuming that the file containing the following code is not in a file |
| named `special.dart` in the `lib` directory of a package named `something` |
| (which would be an exception to the rule), the analyzer produces this |
| diagnostic because the name of the library doesn't conform to the |
| guidelines above: |
| |
| ```dart |
| library [!something.special!]; |
| ``` |
| |
| #### Common fixes |
| |
| Change the name of the library to conform to the guidelines. |
| deprecatedDetails: |- |
| **DO** prefix library names with the package name and a dot-separated path. |
| |
| This guideline helps avoid the warnings you get when two libraries have the same |
| name. Here are the rules we recommend: |
| |
| * Prefix all library names with the package name. |
| * Make the entry library have the same name as the package. |
| * For all other libraries in a package, after the package name add the |
| dot-separated path to the library's Dart file. |
| * For libraries under `lib`, omit the top directory name. |
| |
| For example, say the package name is `my_package`. Here are the library names |
| for various files in the package: |
| |
| **GOOD:** |
| ```dart |
| // In lib/my_package.dart |
| library my_package; |
| |
| // In lib/other.dart |
| library my_package.other; |
| |
| // In lib/foo/bar.dart |
| library my_package.foo.bar; |
| |
| // In example/foo/bar.dart |
| library my_package.example.foo.bar; |
| |
| // In lib/src/private.dart |
| library my_package.src.private; |
| ``` |
| parameter_assignments: |
| problemMessage: "Invalid assignment to the parameter '{0}'." |
| correctionMessage: "Try using a local variable in place of the parameter." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DON'T** assign new values to parameters of methods or functions. |
| |
| Assigning new values to parameters is generally a bad practice unless an |
| operator such as `??=` is used. Otherwise, arbitrarily reassigning parameters |
| is usually a mistake. |
| |
| **BAD:** |
| ```dart |
| void badFunction(int parameter) { // LINT |
| parameter = 4; |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void badFunction(int required, {int optional: 42}) { // LINT |
| optional ??= 8; |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void badFunctionPositional(int required, [int optional = 42]) { // LINT |
| optional ??= 8; |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| class A { |
| void badMethod(int parameter) { // LINT |
| parameter = 4; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void ok(String parameter) { |
| print(parameter); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void actuallyGood(int required, {int optional}) { // OK |
| optional ??= ...; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void actuallyGoodPositional(int required, [int optional]) { // OK |
| optional ??= ...; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| void ok(String parameter) { |
| print(parameter); |
| } |
| } |
| ``` |
| prefer_adjacent_string_concatenation: |
| problemMessage: "String literals shouldn't be concatenated by the '+' operator." |
| correctionMessage: "Try removing the operator to use adjacent strings." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the `+` operator is used to |
| concatenate two string literals. |
| |
| #### Example |
| |
| The following code produces this diagnostic because two string literals |
| are being concatenated by using the `+` operator: |
| |
| ```dart |
| var s = 'a' [!+!] 'b'; |
| ``` |
| |
| #### Common fixes |
| |
| Remove the operator: |
| |
| ```dart |
| var s = 'a' 'b'; |
| ``` |
| deprecatedDetails: |- |
| **DO** use adjacent strings to concatenate string literals. |
| |
| **BAD:** |
| ```dart |
| raiseAlarm( |
| 'ERROR: Parts of the spaceship are on fire. Other ' + |
| 'parts are overrun by martians. Unclear which are which.'); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| raiseAlarm( |
| 'ERROR: Parts of the spaceship are on fire. Other ' |
| 'parts are overrun by martians. Unclear which are which.'); |
| ``` |
| prefer_asserts_in_initializer_lists: |
| problemMessage: "Assert should be in the initializer list." |
| correctionMessage: "Try moving the assert to the initializer list." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the body of a constructor |
| begins with one or more assert statements. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the body of the |
| constructor begins with an assert statement: |
| |
| ```dart |
| class C { |
| C(int i) { |
| [!assert!](i != 0); |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Move the assert to the initializer list, removing the body if there are |
| only assert statements in it: |
| |
| ```dart |
| class C { |
| C(int i) : assert(i != 0); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** put asserts in initializer lists. |
| |
| **BAD:** |
| ```dart |
| class A { |
| A(int a) { |
| assert(a != 0); |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| A(int a) : assert(a != 0); |
| } |
| ``` |
| prefer_asserts_with_message: |
| problemMessage: "Missing a message in an assert." |
| correctionMessage: "Try adding a message to the assert." |
| state: |
| stable: "2.3" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an assert statement doesn't |
| have a message. |
| |
| #### Example |
| |
| The following code produces this diagnostic because there's no message |
| in the assert statement: |
| |
| ```dart |
| void f(String s) { |
| [!assert(s.isNotEmpty);!] |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Add a message to the assert statement: |
| |
| ```dart |
| void f(String s) { |
| assert(s.isNotEmpty, 'The argument must not be empty.'); |
| } |
| ``` |
| deprecatedDetails: |- |
| When assertions fail it's not always simple to understand why. Adding a message |
| to the `assert` helps the developer to understand why the AssertionError occurs. |
| |
| **BAD:** |
| ```dart |
| f(a) { |
| assert(a != null); |
| } |
| |
| class A { |
| A(a) : assert(a != null); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| f(a) { |
| assert(a != null, 'a must not be null'); |
| } |
| |
| class A { |
| A(a) : assert(a != null, 'a must not be null'); |
| } |
| ``` |
| prefer_bool_in_asserts: |
| state: |
| stable: "2.0" |
| removed: "3.0" |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| NOTE: This rule is removed in Dart 3.0.0; it is no longer functional. |
| |
| **DO** use a boolean for assert conditions. |
| |
| Not using booleans in assert conditions can lead to code where it isn't clear |
| what the intention of the assert statement is. |
| |
| **BAD:** |
| ```dart |
| assert(() { |
| f(); |
| return true; |
| }); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| assert(() { |
| f(); |
| return true; |
| }()); |
| ``` |
| prefer_collection_literals: |
| problemMessage: "Unnecessary constructor invocation." |
| correctionMessage: "Try using a collection literal." |
| state: |
| stable: "2.0" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a constructor is used to create |
| a list, map, or set, but a literal would produce the same result. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the constructor for |
| `Map` is being used to create a map that could also be created using a |
| literal: |
| |
| ```dart |
| var m = [!Map<String, String>()!]; |
| ``` |
| |
| #### Common fixes |
| |
| Use the literal representation: |
| |
| ```dart |
| var m = <String, String>{}; |
| ``` |
| deprecatedDetails: |- |
| **DO** use collection literals when possible. |
| |
| **BAD:** |
| ```dart |
| var addresses = Map<String, String>(); |
| var uniqueNames = Set<String>(); |
| var ids = LinkedHashSet<int>(); |
| var coordinates = LinkedHashMap<int, int>(); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var addresses = <String, String>{}; |
| var uniqueNames = <String>{}; |
| var ids = <int>{}; |
| var coordinates = <int, int>{}; |
| ``` |
| |
| **EXCEPTIONS:** |
| |
| When a `LinkedHashSet` or `LinkedHashMap` is expected, a collection literal is |
| not preferred (or allowed). |
| |
| ```dart |
| void main() { |
| LinkedHashSet<int> linkedHashSet = LinkedHashSet.from([1, 2, 3]); // OK |
| LinkedHashMap linkedHashMap = LinkedHashMap(); // OK |
| |
| printSet(LinkedHashSet<int>()); // LINT |
| printHashSet(LinkedHashSet<int>()); // OK |
| |
| printMap(LinkedHashMap<int, int>()); // LINT |
| printHashMap(LinkedHashMap<int, int>()); // OK |
| } |
| |
| void printSet(Set<int> ids) => print('$ids!'); |
| void printHashSet(LinkedHashSet<int> ids) => printSet(ids); |
| void printMap(Map map) => print('$map!'); |
| void printHashMap(LinkedHashMap map) => printMap(map); |
| ``` |
| prefer_conditional_assignment: |
| problemMessage: "The 'if' statement could be replaced by a null-aware assignment." |
| correctionMessage: "Try using the '??=' operator to conditionally assign a value." |
| state: |
| stable: "2.0" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an assignment to a variable is |
| conditional based on whether the variable has the value `null` and the |
| `??=` operator could be used instead. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the parameter `s` is |
| being compared to `null` in order to determine whether to assign a |
| different value: |
| |
| ```dart |
| int f(String? s) { |
| [!if (s == null) { |
| s = ''; |
| }!] |
| return s.length; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use the `??=` operator instead of an explicit `if` statement: |
| |
| ```dart |
| int f(String? s) { |
| s ??= ''; |
| return s.length; |
| } |
| ``` |
| deprecatedDetails: |- |
| **PREFER** using `??=` over testing for `null`. |
| |
| As Dart has the `??=` operator, it is advisable to use it where applicable to |
| improve the brevity of your code. |
| |
| **BAD:** |
| ```dart |
| String get fullName { |
| if (_fullName == null) { |
| _fullName = getFullUserName(this); |
| } |
| return _fullName; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| String get fullName { |
| return _fullName ??= getFullUserName(this); |
| } |
| ``` |
| prefer_const_constructors: |
| problemMessage: "Use 'const' with the constructor to improve performance." |
| correctionMessage: "Try adding the 'const' keyword to the constructor invocation." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an invocation of a const |
| constructor isn't either preceded by `const` or in a [constant context][]. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the invocation of the |
| `const` constructor is neither prefixed by `const` nor in a |
| [constant context][]: |
| |
| ```dart |
| class C { |
| const C(); |
| } |
| |
| C c = [!C()!]; |
| ``` |
| |
| #### Common fixes |
| |
| If the context can be made a [constant context][], then do so: |
| |
| ```dart |
| class C { |
| const C(); |
| } |
| |
| const C c = C(); |
| ``` |
| |
| If the context can't be made a [constant context][], then add `const` |
| before the constructor invocation: |
| |
| ```dart |
| class C { |
| const C(); |
| } |
| |
| C c = const C(); |
| ``` |
| deprecatedDetails: |- |
| **PREFER** using `const` for instantiating constant constructors. |
| |
| If a constructor can be invoked as const to produce a canonicalized instance, |
| it's preferable to do so. |
| |
| **BAD:** |
| ```dart |
| class A { |
| const A(); |
| } |
| |
| void accessA() { |
| A a = new A(); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| const A(); |
| } |
| |
| void accessA() { |
| A a = const A(); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| final int x; |
| |
| const A(this.x); |
| } |
| |
| A foo(int x) => new A(x); |
| ``` |
| prefer_const_constructors_in_immutables: |
| problemMessage: "Constructors in '@immutable' classes should be declared as 'const'." |
| correctionMessage: "Try adding 'const' to the constructor declaration." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a non-`const` constructor is |
| found in a class that has the `@immutable` annotation. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the constructor in `C` |
| isn't declared as `const` even though `C` has the `@immutable` annotation: |
| |
| ```dart |
| import 'package:meta/meta.dart'; |
| |
| @immutable |
| class C { |
| final f; |
| |
| [!C!](this.f); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the class really is intended to be immutable, then add the `const` |
| modifier to the constructor: |
| |
| ```dart |
| import 'package:meta/meta.dart'; |
| |
| @immutable |
| class C { |
| final f; |
| |
| const C(this.f); |
| } |
| ``` |
| |
| If the class is mutable, then remove the `@immutable` annotation: |
| |
| ```dart |
| class C { |
| final f; |
| |
| C(this.f); |
| } |
| ``` |
| deprecatedDetails: |- |
| **PREFER** declaring `const` constructors on `@immutable` classes. |
| |
| If a class is immutable, it is usually a good idea to make its constructor a |
| `const` constructor. |
| |
| **BAD:** |
| ```dart |
| @immutable |
| class A { |
| final a; |
| A(this.a); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| @immutable |
| class A { |
| final a; |
| const A(this.a); |
| } |
| ``` |
| prefer_const_declarations: |
| problemMessage: "Use 'const' for final variables initialized to a constant value." |
| correctionMessage: "Try replacing 'final' with 'const'." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a top-level variable, static |
| field, or local variable is marked as `final` and is initialized to a |
| constant value. |
| |
| #### Examples |
| |
| The following code produces this diagnostic because the top-level variable |
| `v` is both `final` and initialized to a constant value: |
| |
| ```dart |
| [!final v = const <int>[]!]; |
| ``` |
| |
| The following code produces this diagnostic because the static field `f` |
| is both `final` and initialized to a constant value: |
| |
| ```dart |
| class C { |
| static [!final f = const <int>[]!]; |
| } |
| ``` |
| |
| The following code produces this diagnostic because the local variable `v` |
| is both `final` and initialized to a constant value: |
| |
| ```dart |
| void f() { |
| [!final v = const <int>[]!]; |
| print(v); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Replace the keyword `final` with `const` and remove `const` from the |
| initializer: |
| |
| ```dart |
| class C { |
| static const f = <int>[]; |
| } |
| ``` |
| deprecatedDetails: |- |
| **PREFER** using `const` for constant-valued declarations. |
| |
| Constant declarations are more hot-reload friendly and allow |
| values to be used in other constant expressions. |
| |
| **BAD:** |
| ```dart |
| final o = const <int>[]; |
| |
| class A { |
| static final o = const <int>[]; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| const o = <int>[]; |
| |
| class A { |
| static const o = <int>[]; |
| } |
| ``` |
| prefer_const_literals_to_create_immutables: |
| problemMessage: "Use 'const' literals as arguments to constructors of '@immutable' classes." |
| correctionMessage: "Try adding 'const' before the literal." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a non-const list, map, or set |
| literal is passed as an argument to a constructor declared in a class |
| annotated with `@immutable`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the list literal |
| (`[1]`) is being passed to a constructor in an immutable class but isn't |
| a constant list: |
| |
| ```dart |
| import 'package:meta/meta.dart'; |
| |
| @immutable |
| class C { |
| final f; |
| |
| const C(this.f); |
| } |
| |
| C c = C([![1]!]); |
| ``` |
| |
| #### Common fixes |
| |
| If the context can be made a [constant context][], then do so: |
| |
| ```dart |
| import 'package:meta/meta.dart'; |
| |
| @immutable |
| class C { |
| final f; |
| |
| const C(this.f); |
| } |
| |
| const C c = C([1]); |
| ``` |
| |
| If the context can't be made a [constant context][] but the constructor |
| can be invoked using `const`, then add `const` before the constructor |
| invocation: |
| |
| ```dart |
| import 'package:meta/meta.dart'; |
| |
| @immutable |
| class C { |
| final f; |
| |
| const C(this.f); |
| } |
| |
| C c = const C([1]); |
| ``` |
| |
| If the context can't be made a [constant context][] and the constructor |
| can't be invoked using `const`, then add the keyword `const` before the |
| collection literal: |
| |
| ```dart |
| import 'package:meta/meta.dart'; |
| |
| @immutable |
| class C { |
| final f; |
| |
| const C(this.f); |
| } |
| |
| C c = C(const [1]); |
| ``` |
| deprecatedDetails: |- |
| **PREFER** using `const` for instantiating list, map and set literals used as |
| parameters in immutable class instantiations. |
| |
| **BAD:** |
| ```dart |
| @immutable |
| class A { |
| A(this.v); |
| final v; |
| } |
| |
| A a1 = new A([1]); |
| A a2 = new A({}); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| A a1 = new A(const [1]); |
| A a2 = new A(const {}); |
| ``` |
| prefer_constructors_over_static_methods: |
| problemMessage: "Static method should be a constructor." |
| correctionMessage: "Try converting the method into a constructor." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a static method returns a newly |
| created instance of the class and could, therefore, be a constructor. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the static method |
| `all` could be a constructor: |
| |
| ```dart |
| class C { |
| final int a, b, c; |
| C(this.a, this.b, this.c); |
| static C [!all!](int i) => C(i, i, i); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Convert the static method to a named constructor: |
| |
| ```dart |
| class C { |
| final int a, b, c; |
| C(this.a, this.b, this.c); |
| C.all(int i) : a = i, b = i, c = i; |
| } |
| ``` |
| deprecatedDetails: |- |
| **PREFER** defining constructors instead of static methods to create instances. |
| |
| In most cases, it makes more sense to use a named constructor rather than a |
| static method because it makes instantiation clearer. |
| |
| **BAD:** |
| ```dart |
| class Point { |
| num x, y; |
| Point(this.x, this.y); |
| static Point polar(num theta, num radius) { |
| return Point(radius * math.cos(theta), |
| radius * math.sin(theta)); |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Point { |
| num x, y; |
| Point(this.x, this.y); |
| Point.polar(num theta, num radius) |
| : x = radius * math.cos(theta), |
| y = radius * math.sin(theta); |
| } |
| ``` |
| prefer_contains_always_false: |
| sharedName: prefer_contains |
| problemMessage: "Always 'false' because 'indexOf' is always greater than or equal to -1." |
| categories: [style] |
| hasPublishedDocs: false |
| todo: |- |
| TODO(brianwilkerson): Should be warning rather than lint, |
| as represents a bug rather than style preference. |
| prefer_contains_always_true: |
| sharedName: prefer_contains |
| problemMessage: "Always 'true' because 'indexOf' is always greater than or equal to -1." |
| hasPublishedDocs: false |
| todo: |- |
| TODO(brianwilkerson): Should be warning rather than lint, |
| as represents a bug rather than style preference. |
| prefer_contains_use_contains: |
| sharedName: prefer_contains |
| problemMessage: "Unnecessary use of 'indexOf' to test for containment." |
| correctionMessage: "Try using 'contains'." |
| state: |
| stable: "2.0" |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the method `indexOf` is used and |
| the result is only compared with `-1` or `0` in a way where the semantics |
| are equivalent to using `contains`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the condition in the |
| `if` statement is checking to see whether the list contains the string: |
| |
| ```dart |
| void f(List<String> l, String s) { |
| if ([!l.indexOf(s) < 0!]) { |
| // ... |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use `contains` instead, negating the condition when necessary: |
| |
| ```dart |
| void f(List<String> l, String s) { |
| if (l.contains(s)) { |
| // ... |
| } |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use `indexOf` to see if a collection contains an element. |
| |
| Calling `indexOf` to see if a collection contains something is difficult to read |
| and may have poor performance. |
| |
| Instead, prefer `contains`. |
| |
| **BAD:** |
| ```dart |
| if (lunchBox.indexOf('sandwich') == -1) return 'so hungry...'; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| if (!lunchBox.contains('sandwich')) return 'so hungry...'; |
| ``` |
| prefer_double_quotes: |
| problemMessage: "Unnecessary use of single quotes." |
| correctionMessage: "Try using double quotes unless the string contains double quotes." |
| state: |
| stable: "2.4" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a string literal uses single |
| quotes (`'`) when it could use double quotes (`"`) without needing extra |
| escapes and without hurting readability. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the string literal |
| uses single quotes but doesn't need to: |
| |
| ```dart |
| void f(String name) { |
| print([!'Hello $name'!]); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use double quotes in place of single quotes: |
| |
| ```dart |
| void f(String name) { |
| print("Hello $name"); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** use double quotes where they wouldn't require additional escapes. |
| |
| That means strings with a double quote may use apostrophes so that the double |
| quote isn't escaped (note: we don't lint the other way around, ie, a double |
| quoted string with an escaped double quote is not flagged). |
| |
| It's also rare, but possible, to have strings within string interpolations. In |
| this case, it's much more readable to use a single quote somewhere. So single |
| quotes are allowed either within, or containing, an interpolated string literal. |
| Arguably strings within string interpolations should be its own type of lint. |
| |
| **BAD:** |
| ```dart |
| useStrings( |
| 'should be double quote', |
| r'should be double quote', |
| r\'''should be double quotes\''') |
| ``` |
| |
| **GOOD:** |
| ```dart |
| useStrings( |
| "should be double quote", |
| r"should be double quote", |
| r"""should be double quotes""", |
| 'ok with " inside', |
| 'nested \${a ? "strings" : "can"} be wrapped by a double quote', |
| "and nested \${a ? 'strings' : 'can be double quoted themselves'}"); |
| ``` |
| prefer_equal_for_default_values: |
| state: |
| stable: "2.0" |
| removed: "3.0" |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| NOTE: This rule is removed in Dart 3.0; it is no longer functional. |
| |
| **DO** use `=` to separate a named parameter from its default value. |
| |
| **BAD:** |
| ```dart |
| m({a: 1}) |
| ``` |
| |
| **GOOD:** |
| ```dart |
| m({a = 1}) |
| ``` |
| prefer_expression_function_bodies: |
| problemMessage: "Unnecessary use of a block function body." |
| correctionMessage: "Try using an expression function body." |
| state: |
| stable: "2.0" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the body of a function consists |
| of a single return statement with an expression. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the body of `f` has a |
| single return statement: |
| |
| ```dart |
| int f() [!{ |
| return 0; |
| }!] |
| ``` |
| |
| #### Common fixes |
| |
| If the body is complete, then replace the body with an expression body: |
| |
| ```dart |
| int f() => 0; |
| ``` |
| |
| If the body isn't complete, then add the missing statements. |
| deprecatedDetails: |- |
| **CONSIDER** using => for short members whose body is a single return statement. |
| |
| **BAD:** |
| ```dart |
| get width { |
| return right - left; |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| bool ready(num time) { |
| return minTime == null || minTime <= time; |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| containsValue(String value) { |
| return getValues().contains(value); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| get width => right - left; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| bool ready(num time) => minTime == null || minTime <= time; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| containsValue(String value) => getValues().contains(value); |
| ``` |
| prefer_final_fields: |
| problemMessage: "The private field {0} could be 'final'." |
| correctionMessage: "Try making the field 'final'." |
| state: |
| stable: "2.0" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a private field is only |
| assigned one time. The field can be initialized in multiple constructors |
| and still be flagged because only one of those constructors can ever run. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the field `_f` is only |
| assigned one time, in the field's initializer: |
| |
| ```dart |
| class C { |
| int [!_f = 1!]; |
| |
| int get f => _f; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Mark the field `final`: |
| |
| ```dart |
| class C { |
| final int _f = 1; |
| |
| int get f => _f; |
| } |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/design#prefer-making-fields-and-top-level-variables-final): |
| |
| **DO** prefer declaring private fields as `final` if they are not reassigned |
| later in the library. |
| |
| Declaring fields as `final` when possible is a good practice because it helps |
| avoid accidental reassignments and allows the compiler to do optimizations. |
| |
| **BAD:** |
| ```dart |
| class BadImmutable { |
| var _label = 'hola mundo! BadImmutable'; // LINT |
| var label = 'hola mundo! BadImmutable'; // OK |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| class MultipleMutable { |
| var _label = 'hola mundo! GoodMutable', _offender = 'mumble mumble!'; // LINT |
| var _someOther; // LINT |
| |
| MultipleMutable() : _someOther = 5; |
| |
| MultipleMutable(this._someOther); |
| |
| void changeLabel() { |
| _label= 'hello world! GoodMutable'; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class GoodImmutable { |
| final label = 'hola mundo! BadImmutable', bla = 5; // OK |
| final _label = 'hola mundo! BadImmutable', _bla = 5; // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class GoodMutable { |
| var _label = 'hola mundo! GoodMutable'; |
| |
| void changeLabel() { |
| _label = 'hello world! GoodMutable'; |
| } |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| class AssignedInAllConstructors { |
| var _label; // LINT |
| AssignedInAllConstructors(this._label); |
| AssignedInAllConstructors.withDefault() : _label = 'Hello'; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class NotAssignedInAllConstructors { |
| var _label; // OK |
| NotAssignedInAllConstructors(); |
| NotAssignedInAllConstructors.withDefault() : _label = 'Hello'; |
| } |
| ``` |
| prefer_final_in_for_each_pattern: |
| sharedName: prefer_final_in_for_each |
| problemMessage: "The pattern should be final." |
| correctionMessage: "Try making the pattern final." |
| state: |
| stable: "2.1" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the loop variable in a for-each |
| statement isn't marked as being `final`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the loop variable `e` |
| isn't marked as being `final`: |
| |
| ```dart |
| void f(List<int> l) { |
| for (var [!e!] in l) { |
| print(e); |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Add the modifier `final` to the loop variable, removing the `var` if there |
| is one: |
| |
| ```dart |
| void f(List<int> l) { |
| for (final e in l) { |
| print(e); |
| } |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** prefer declaring for-each loop variables as final if they are not |
| reassigned later in the code. |
| |
| Declaring for-each loop variables as final when possible is a good practice |
| because it helps avoid accidental reassignments and allows the compiler to do |
| optimizations. |
| |
| **BAD:** |
| ```dart |
| for (var element in elements) { // LINT |
| print('Element: $element'); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| for (final element in elements) { |
| print('Element: $element'); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| for (var element in elements) { |
| element = element + element; |
| print('Element: $element'); |
| } |
| ``` |
| prefer_final_in_for_each_variable: |
| sharedName: prefer_final_in_for_each |
| problemMessage: "The variable '{0}' should be final." |
| correctionMessage: "Try making the variable final." |
| hasPublishedDocs: false |
| prefer_final_locals: |
| problemMessage: "Local variables should be final." |
| correctionMessage: "Try making the variable final." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a local variable isn't marked |
| as being `final`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the variable `s` isn't |
| marked as being `final`: |
| |
| ```dart |
| int f(int i) { |
| [!var!] s = i + 1; |
| return s; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Add the modifier `final` to the variable, removing the `var` if there is |
| one: |
| |
| ```dart |
| int f(int i) { |
| final s = i + 1; |
| return s; |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** prefer declaring variables as final if they are not reassigned later in |
| the code. |
| |
| Declaring variables as final when possible is a good practice because it helps |
| avoid accidental reassignments and allows the compiler to do optimizations. |
| |
| **BAD:** |
| ```dart |
| void badMethod() { |
| var label = 'hola mundo! badMethod'; // LINT |
| print(label); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void goodMethod() { |
| final label = 'hola mundo! goodMethod'; |
| print(label); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void mutableCase() { |
| var label = 'hola mundo! mutableCase'; |
| print(label); |
| label = 'hello world'; |
| print(label); |
| } |
| ``` |
| prefer_final_parameters: |
| problemMessage: "The parameter '{0}' should be final." |
| correctionMessage: "Try making the parameter final." |
| state: |
| stable: "2.14" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a parameter of a constructor, |
| method, function, or closure isn't marked as being `final`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the parameter `s` |
| isn't a `final` parameter: |
| |
| ```dart |
| String f([!String s!]) => s; |
| ``` |
| |
| #### Common fixes |
| |
| Add the modifier `final` to the parameter: |
| |
| ```dart |
| String f(final String s) => s; |
| ``` |
| deprecatedDetails: |- |
| **DO** prefer declaring parameters as final if they are not reassigned in |
| the function body. |
| |
| Declaring parameters as final when possible is a good practice because it helps |
| avoid accidental reassignments. |
| |
| **BAD:** |
| ```dart |
| void badParameter(String label) { // LINT |
| print(label); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void goodParameter(final String label) { // OK |
| print(label); |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void badExpression(int value) => print(value); // LINT |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void goodExpression(final int value) => print(value); // OK |
| ``` |
| |
| **BAD:** |
| ```dart |
| [1, 4, 6, 8].forEach((value) => print(value + 2)); // LINT |
| ``` |
| |
| **GOOD:** |
| ```dart |
| [1, 4, 6, 8].forEach((final value) => print(value + 2)); // OK |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void mutableParameter(String label) { // OK |
| print(label); |
| label = 'Hello Linter!'; |
| print(label); |
| } |
| ``` |
| prefer_for_elements_to_map_fromIterable: |
| problemMessage: "Use 'for' elements when building maps from iterables." |
| correctionMessage: "Try using a collection literal with a 'for' element." |
| state: |
| stable: "2.3" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when `Map.fromIterable` is used to |
| build a map that could be built using the `for` element. |
| |
| #### Example |
| |
| The following code produces this diagnostic because `fromIterable` is |
| being used to build a map that could be built using a `for` element: |
| |
| ```dart |
| void f(Iterable<String> data) { |
| [!Map<String, int>.fromIterable( |
| data, |
| key: (element) => element, |
| value: (element) => element.length, |
| )!]; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use a `for` element to build the map: |
| |
| ```dart |
| void f(Iterable<String> data) { |
| <String, int>{ |
| for (var element in data) |
| element: element.length |
| }; |
| } |
| ``` |
| deprecatedDetails: |- |
| When building maps from iterables, it is preferable to use `for` elements. |
| |
| Using 'for' elements brings several benefits including: |
| |
| - Performance |
| - Flexibility |
| - Readability |
| - Improved type inference |
| - Improved interaction with null safety |
| |
| |
| **BAD:** |
| ```dart |
| Map<String, WidgetBuilder>.fromIterable( |
| kAllGalleryDemos, |
| key: (demo) => '${demo.routeName}', |
| value: (demo) => demo.buildRoute, |
| ); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| return { |
| for (var demo in kAllGalleryDemos) |
| '${demo.routeName}': demo.buildRoute, |
| }; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| // Map<int, Student> is not required, type is inferred automatically. |
| final pizzaRecipients = { |
| ...studentLeaders, |
| for (var student in classG) |
| if (student.isPassing) student.id: student, |
| }; |
| ``` |
| prefer_foreach: |
| problemMessage: "Use 'forEach' and a tear-off rather than a 'for' loop to apply a function to every element." |
| correctionMessage: "Try using 'forEach' and a tear-off rather than a 'for' loop." |
| state: |
| experimental: "2.0" |
| stable: "2.2" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `for` loop is used to operate |
| on every member of a collection and the method `forEach` could be used |
| instead. |
| |
| #### Example |
| |
| The following code produces this diagnostic because a `for` loop is being |
| used to invoke a single function for each key in `m`: |
| |
| ```dart |
| void f(Map<String, int> m) { |
| [!for (final key in m.keys) { |
| print(key); |
| }!] |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Replace the for loop with an invocation of `forEach`: |
| |
| ```dart |
| void f(Map<String, int> m) { |
| m.keys.forEach(print); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** use `forEach` if you are only going to apply a function or a method |
| to all the elements of an iterable. |
| |
| Using `forEach` when you are only going to apply a function or method to all |
| elements of an iterable is a good practice because it makes your code more |
| terse. |
| |
| **BAD:** |
| ```dart |
| for (final key in map.keys.toList()) { |
| map.remove(key); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| map.keys.toList().forEach(map.remove); |
| ``` |
| |
| **NOTE:** Replacing a for each statement with a forEach call may change the |
| behavior in the case where there are side-effects on the iterable itself. |
| ```dart |
| for (final v in myList) { |
| foo().f(v); // This code invokes foo() many times. |
| } |
| |
| myList.forEach(foo().f); // But this one invokes foo() just once. |
| ``` |
| prefer_function_declarations_over_variables: |
| problemMessage: "Use a function declaration rather than a variable assignment to bind a function to a name." |
| correctionMessage: "Try rewriting the closure assignment as a function declaration." |
| state: |
| stable: "2.0" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a closure is assigned to a |
| local variable and the local variable is not re-assigned anywhere. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the local variable `f` |
| is initialized to be a closure and isn't assigned any other value: |
| |
| ```dart |
| void g() { |
| var [!f = (int i) => i * 2!]; |
| f(1); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Replace the local variable with a local function: |
| |
| ```dart |
| void g() { |
| int f(int i) => i * 2; |
| f(1); |
| } |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/usage#do-use-a-function-declaration-to-bind-a-function-to-a-name): |
| |
| **DO** use a function declaration to bind a function to a name. |
| |
| As Dart allows local function declarations, it is a good practice to use them in |
| the place of function literals. |
| |
| **BAD:** |
| ```dart |
| void main() { |
| var localFunction = () { |
| ... |
| }; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void main() { |
| localFunction() { |
| ... |
| } |
| } |
| ``` |
| prefer_generic_function_type_aliases: |
| problemMessage: "Use the generic function type syntax in 'typedef's." |
| correctionMessage: "Try using the generic function type syntax ('{0}')." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a typedef is written using the |
| older syntax for function type aliases in which the name being declared is |
| embedded in the function type. |
| |
| #### Example |
| |
| The following code produces this diagnostic because it uses the older |
| syntax: |
| |
| ```dart |
| typedef void [!F!]<T>(); |
| ``` |
| |
| #### Common fixes |
| |
| Rewrite the typedef to use the newer syntax: |
| |
| ```dart |
| typedef F<T> = void Function(); |
| ``` |
| deprecatedDetails: |- |
| **PREFER** generic function type aliases. |
| |
| With the introduction of generic functions, function type aliases |
| (`typedef void F()`) couldn't express all of the possible kinds of |
| parameterization that users might want to express. Generic function type aliases |
| (`typedef F = void Function()`) fixed that issue. |
| |
| For consistency and readability reasons, it's better to only use one syntax and |
| thus prefer generic function type aliases. |
| |
| **BAD:** |
| ```dart |
| typedef void F(); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| typedef F = void Function(); |
| ``` |
| prefer_if_elements_to_conditional_expressions: |
| problemMessage: "Use an 'if' element to conditionally add elements." |
| correctionMessage: "Try using an 'if' element rather than a conditional expression." |
| state: |
| stable: "2.3" |
| categories: [brevity, style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| When building collections, it is preferable to use `if` elements rather than |
| conditionals. |
| |
| **BAD:** |
| ```dart |
| var list = ['a', 'b', condition ? 'c' : null].where((e) => e != null).toList(); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var list = ['a', 'b', if (condition) 'c']; |
| ``` |
| prefer_if_null_operators: |
| problemMessage: "Use the '??' operator rather than '?:' when testing for 'null'." |
| correctionMessage: "Try rewriting the code to use '??'." |
| state: |
| stable: "2.4" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a conditional expression (using |
| the `?:` operator) is used to select a different value when a local |
| variable is `null`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the variable `s` is |
| being compared to `null` so that a different value can be returned when |
| `s` is `null`: |
| |
| ```dart |
| String f(String? s) => [!s == null ? '' : s!]; |
| ``` |
| |
| #### Common fixes |
| |
| Use the if-null operator instead: |
| |
| ```dart |
| String f(String? s) => s ?? ''; |
| ``` |
| deprecatedDetails: |- |
| **PREFER** using `??` operators instead of `null` checks and conditional |
| expressions. |
| |
| **BAD:** |
| ```dart |
| v = a == null ? b : a; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| v = a ?? b; |
| ``` |
| prefer_initializing_formals: |
| problemMessage: "Use an initializing formal to assign a parameter to a field." |
| correctionMessage: "Try using an initialing formal ('this.{0}') to initialize the field." |
| state: |
| stable: "2.0" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a constructor parameter is used |
| to initialize a field without modification. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the parameter `c` is |
| only used to set the field `c`: |
| |
| ```dart |
| class C { |
| int c; |
| |
| C(int c) : [!this.c = c!]; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use an initializing formal parameter to initialize the field: |
| |
| ```dart |
| class C { |
| int c; |
| |
| C(this.c); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** use initializing formals when possible. |
| |
| Using initializing formals when possible makes your code more terse. |
| |
| **BAD:** |
| ```dart |
| class Point { |
| num? x, y; |
| Point(num x, num y) { |
| this.x = x; |
| this.y = y; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Point { |
| num? x, y; |
| Point(num this.x, num this.y); |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| class Point { |
| num? x, y; |
| Point({num? x, num? y}) { |
| this.x = x; |
| this.y = y; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Point { |
| num? x, y; |
| Point({required num this.x, required num this.y}); |
| } |
| ``` |
| |
| **NOTE:** |
| This rule will not generate a lint for named parameters unless the parameter |
| name and the field name are the same. The reason for this is that resolving |
| such a lint would require either renaming the field or renaming the parameter, |
| and both of those actions would potentially be a breaking change. For example, |
| the following will not generate a lint: |
| |
| ```dart |
| class Point { |
| bool? isEnabled; |
| Point({bool? enabled}) { |
| this.isEnabled = enabled; // OK |
| } |
| } |
| ``` |
| |
| **NOTE:** |
| Also note that it is possible to enforce a type that is stricter than the |
| initialized field with an initializing formal parameter. In the following |
| example the unnamed `Bid` constructor requires a non-null `int` despite |
| `amount` being declared nullable (`int?`). |
| |
| ```dart |
| class Bid { |
| final int? amount; |
| Bid(int this.amount); |
| Bid.pass() : amount = null; |
| } |
| ``` |
| prefer_inlined_adds_multiple: |
| sharedName: prefer_inlined_adds |
| problemMessage: "The addition of multiple list items could be inlined." |
| correctionMessage: "Try adding the items to the list literal directly." |
| state: |
| stable: "2.3" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| deprecatedDetails: |- |
| Declare elements in list literals inline, rather than using `add` and |
| `addAll` methods where possible. |
| |
| |
| **BAD:** |
| ```dart |
| var l = ['a']..add('b')..add('c'); |
| var l2 = ['a']..addAll(['b', 'c']); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var l = ['a', 'b', 'c']; |
| var l2 = ['a', 'b', 'c']; |
| ``` |
| prefer_inlined_adds_single: |
| sharedName: prefer_inlined_adds |
| problemMessage: "The addition of a list item could be inlined." |
| correctionMessage: "Try adding the item to the list literal directly." |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the methods `add` and `addAll` |
| are invoked on a list literal where the elements being added could be |
| included in the list literal. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the `add` method is |
| being used to add `b`, when it could have been included directly in the |
| list literal: |
| |
| ```dart |
| List<String> f(String a, String b) { |
| return [a]..[!add!](b); |
| } |
| ``` |
| |
| The following code produces this diagnostic because the `addAll` method is |
| being used to add the elements of `b`, when it could have been included |
| directly in the list literal: |
| |
| ```dart |
| List<String> f(String a, List<String> b) { |
| return [a]..[!addAll!](b); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the `add` method is being used, then make the argument an element of |
| the list and remove the invocation: |
| |
| ```dart |
| List<String> f(String a, String b) { |
| return [a, b]; |
| } |
| ``` |
| |
| If the `addAll` method is being used, then use the spread operator on the |
| argument to add its elements to the list and remove the invocation: |
| |
| ```dart |
| List<String> f(String a, List<String> b) { |
| return [a, ...b]; |
| } |
| ``` |
| prefer_int_literals: |
| problemMessage: "Unnecessary use of a 'double' literal." |
| correctionMessage: "Try using an 'int' literal." |
| state: |
| stable: "2.1" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DO** use int literals rather than the corresponding double literal. |
| |
| **BAD:** |
| ```dart |
| const double myDouble = 8.0; |
| final anotherDouble = myDouble + 7.0e2; |
| main() { |
| someMethod(6.0); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| const double myDouble = 8; |
| final anotherDouble = myDouble + 700; |
| main() { |
| someMethod(6); |
| } |
| ``` |
| prefer_interpolation_to_compose_strings: |
| problemMessage: "Use interpolation to compose strings and values." |
| correctionMessage: "Try using string interpolation to build the composite string." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when string literals and computed |
| strings are being concatenated using the `+` operator, but string |
| interpolation would achieve the same result. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the String `s` is |
| concatenated with other strings using the `+` operator: |
| |
| ```dart |
| String f(String s) { |
| return [!'(' + s!] + ')'; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use string interpolation: |
| |
| ```dart |
| String f(List<String> l) { |
| return '(${l[0]}, ${l[1]})'; |
| } |
| ``` |
| deprecatedDetails: |- |
| **PREFER** using interpolation to compose strings and values. |
| |
| Using interpolation when composing strings and values is usually easier to write |
| and read than concatenation. |
| |
| **BAD:** |
| ```dart |
| 'Hello, ' + person.name + ' from ' + person.city + '.'; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| 'Hello, ${person.name} from ${person.city}.' |
| ``` |
| prefer_is_empty_always_false: |
| sharedName: prefer_is_empty |
| problemMessage: "The comparison is always 'false' because the length is always greater than or equal to 0." |
| categories: [errorProne] |
| hasPublishedDocs: false |
| todo: |- |
| TODO(brianwilkerson): Should be warning rather than lint, |
| as represents a bug rather than style preference. |
| prefer_is_empty_always_true: |
| sharedName: prefer_is_empty |
| problemMessage: "The comparison is always 'true' because the length is always greater than or equal to 0." |
| hasPublishedDocs: false |
| todo: |- |
| TODO(brianwilkerson): Should be warning rather than lint, |
| as represents a bug rather than style preference. |
| prefer_is_empty_use_is_empty: |
| sharedName: prefer_is_empty |
| problemMessage: "Use 'isEmpty' instead of 'length' to test whether the collection is empty." |
| correctionMessage: "Try rewriting the expression to use 'isEmpty'." |
| state: |
| stable: "2.0" |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the result of invoking either |
| `Iterable.length` or `Map.length` is compared for equality with zero |
| (`0`). |
| |
| #### Example |
| |
| The following code produces this diagnostic because the result of invoking |
| `length` is checked for equality with zero: |
| |
| ```dart |
| int f(Iterable<int> p) => [!p.length == 0!] ? 0 : p.first; |
| ``` |
| |
| #### Common fixes |
| |
| Replace the use of `length` with a use of either `isEmpty` or |
| `isNotEmpty`: |
| |
| ```dart |
| void f(Iterable<int> p) => p.isEmpty ? 0 : p.first; |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use `length` to see if a collection is empty. |
| |
| The `Iterable` contract does not require that a collection know its length or be |
| able to provide it in constant time. Calling `length` just to see if the |
| collection contains anything can be painfully slow. |
| |
| Instead, there are faster and more readable getters: `isEmpty` and |
| `isNotEmpty`. Use the one that doesn't require you to negate the result. |
| |
| **BAD:** |
| ```dart |
| if (lunchBox.length == 0) return 'so hungry...'; |
| if (words.length != 0) return words.join(' '); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| if (lunchBox.isEmpty) return 'so hungry...'; |
| if (words.isNotEmpty) return words.join(' '); |
| ``` |
| prefer_is_empty_use_is_not_empty: |
| sharedName: prefer_is_empty |
| problemMessage: "Use 'isNotEmpty' instead of 'length' to test whether the collection is empty." |
| correctionMessage: "Try rewriting the expression to use 'isNotEmpty'." |
| hasPublishedDocs: true |
| prefer_is_not_empty: |
| problemMessage: "Use 'isNotEmpty' rather than negating the result of 'isEmpty'." |
| correctionMessage: "Try rewriting the expression to use 'isNotEmpty'." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the result of invoking |
| `Iterable.isEmpty` or `Map.isEmpty` is negated. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the result of invoking |
| `Iterable.isEmpty` is negated: |
| |
| ```dart |
| void f(Iterable<int> p) => [!!p.isEmpty!] ? p.first : 0; |
| ``` |
| |
| #### Common fixes |
| |
| Rewrite the code to use `isNotEmpty`: |
| |
| ```dart |
| void f(Iterable<int> p) => p.isNotEmpty ? p.first : 0; |
| ``` |
| deprecatedDetails: |- |
| **PREFER** `x.isNotEmpty` to `!x.isEmpty` for `Iterable` and `Map` instances. |
| |
| When testing whether an iterable or map is empty, prefer `isNotEmpty` over |
| `!isEmpty` to improve code readability. |
| |
| **BAD:** |
| ```dart |
| if (!sources.isEmpty) { |
| process(sources); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| if (todo.isNotEmpty) { |
| sendResults(request, todo.isEmpty); |
| } |
| ``` |
| prefer_is_not_operator: |
| problemMessage: "Use the 'is!' operator rather than negating the value of the 'is' operator." |
| correctionMessage: "Try rewriting the condition to use the 'is!' operator." |
| state: |
| stable: "2.7" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the prefix `!` operator is used |
| to negate the result of an `is` test. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the result of testing |
| to see whether `o` is a `String` is negated using the prefix `!` operator: |
| |
| ```dart |
| String f(Object o) { |
| if ([!!(o is String)!]) { |
| return o.toString(); |
| } |
| return o; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use the `is!` operator instead: |
| |
| ```dart |
| String f(Object o) { |
| if (o is! String) { |
| return o.toString(); |
| } |
| return o; |
| } |
| ``` |
| deprecatedDetails: |- |
| When checking if an object is not of a specified type, it is preferable to use the 'is!' operator. |
| |
| **BAD:** |
| ```dart |
| if (!(foo is Foo)) { |
| ... |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| if (foo is! Foo) { |
| ... |
| } |
| ``` |
| prefer_iterable_whereType: |
| problemMessage: "Use 'whereType' to select elements of a given type." |
| correctionMessage: "Try rewriting the expression to use 'whereType'." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the method `Iterable.where` is |
| being used to filter elements based on their type. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the method `where` is |
| being used to access only the strings within the iterable: |
| |
| ```dart |
| Iterable<Object> f(Iterable<Object> p) => p.[!where!]((e) => e is String); |
| ``` |
| |
| #### Common fixes |
| |
| Rewrite the code to use `whereType`: |
| |
| ```dart |
| Iterable<String> f(Iterable<Object> p) => p.whereType<String>(); |
| ``` |
| |
| This might also allow you to tighten the types in your code or remove |
| other type checks. |
| deprecatedDetails: |- |
| **PREFER** `iterable.whereType<T>()` over `iterable.where((e) => e is T)`. |
| |
| **BAD:** |
| ```dart |
| iterable.where((e) => e is MyClass); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| iterable.whereType<MyClass>(); |
| ``` |
| prefer_mixin: |
| problemMessage: "Only mixins should be mixed in." |
| correctionMessage: "Try converting '{0}' to a mixin." |
| state: |
| stable: "2.1" |
| categories: [languageFeatureUsage, style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Dart 2.1 introduced a new syntax for mixins that provides a safe way for a mixin |
| to invoke inherited members using `super`. The new style of mixins should always |
| be used for types that are to be mixed in. As a result, this lint will flag any |
| uses of a class in a `with` clause. |
| |
| **BAD:** |
| ```dart |
| class A {} |
| class B extends Object with A {} |
| ``` |
| |
| **OK:** |
| ```dart |
| mixin M {} |
| class C with M {} |
| ``` |
| prefer_null_aware_method_calls: |
| problemMessage: "Use a null-aware invocation of the 'call' method rather than explicitly testing for 'null'." |
| correctionMessage: "Try using '?.call()' to invoke the function." |
| state: |
| stable: "2.14" |
| categories: [brevity, style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Instead of checking nullability of a function/method `f` before calling it, |
| you can use `f?.call()`. |
| |
| **BAD:** |
| ```dart |
| if (f != null) f!(); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| f?.call(); |
| ``` |
| prefer_null_aware_operators: |
| problemMessage: "Use the null-aware operator '?.' rather than an explicit 'null' comparison." |
| correctionMessage: "Try using '?.'." |
| state: |
| stable: "2.2" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a comparison with `null` is |
| used to guard a member reference, and `null` is used as a result when the |
| guarded target is `null`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the invocation of |
| `length` is guarded by a `null` comparison even though the default value |
| is `null`: |
| |
| ```dart |
| int? f(List<int>? p) { |
| return [!p == null ? null : p.length!]; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use a null-aware access operator instead: |
| |
| ```dart |
| int? f(List<int>? p) { |
| return p?.length; |
| } |
| ``` |
| deprecatedDetails: |- |
| **PREFER** using `null`-aware operators instead of `null` checks in conditional |
| expressions. |
| |
| **BAD:** |
| ```dart |
| v = a == null ? null : a.b; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| v = a?.b; |
| ``` |
| prefer_relative_imports: |
| problemMessage: "Use relative imports for files in the 'lib' directory." |
| correctionMessage: "Try converting the URI to a relative URI." |
| state: |
| stable: "2.6" |
| categories: [errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an `import` in a library inside |
| the `lib` directory uses a `package:` URI to refer to another library in |
| the same package. |
| |
| #### Example |
| |
| The following code produces this diagnostic because it uses a `package:` |
| URI when a relative URI could have been used: |
| |
| ```dart |
| import 'package:my_package/bar.dart'; |
| ``` |
| |
| #### Common fixes |
| |
| Use a relative URI to import the library: |
| |
| ```dart |
| import 'bar.dart'; |
| ``` |
| deprecatedDetails: |- |
| **PREFER** 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 relative imports for files within the |
| `lib/` directory. |
| |
| **BAD:** |
| ```dart |
| import 'package:my_package/bar.dart'; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| import 'bar.dart'; |
| ``` |
| prefer_single_quotes: |
| problemMessage: "Unnecessary use of double quotes." |
| correctionMessage: "Try using single quotes unless the string contains single quotes." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a string literal uses double |
| quotes (`"`) when it could use single quotes (`'`) without needing extra |
| escapes and without hurting readability. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the string literal |
| uses double quotes but doesn't need to: |
| |
| ```dart |
| void f(String name) { |
| print([!"Hello $name"!]); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use single quotes in place of double quotes: |
| |
| ```dart |
| void f(String name) { |
| print('Hello $name'); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** use single quotes where they wouldn't require additional escapes. |
| |
| That means strings with an apostrophe may use double quotes so that the |
| apostrophe isn't escaped (note: we don't lint the other way around, ie, a single |
| quoted string with an escaped apostrophe is not flagged). |
| |
| It's also rare, but possible, to have strings within string interpolations. In |
| this case, it's much more readable to use a double quote somewhere. So double |
| quotes are allowed either within, or containing, an interpolated string literal. |
| Arguably strings within string interpolations should be its own type of lint. |
| |
| **BAD:** |
| ```dart |
| useStrings( |
| "should be single quote", |
| r"should be single quote", |
| r"""should be single quotes""") |
| ``` |
| |
| **GOOD:** |
| ```dart |
| useStrings( |
| 'should be single quote', |
| r'should be single quote', |
| r\'''should be single quotes\''', |
| "here's ok", |
| "nested \${a ? 'strings' : 'can'} be wrapped by a double quote", |
| 'and nested \${a ? "strings" : "can be double quoted themselves"}'); |
| ``` |
| prefer_spread_collections: |
| problemMessage: "The addition of multiple elements could be inlined." |
| correctionMessage: "Try using the spread operator ('...') to inline the addition." |
| state: |
| stable: "2.3" |
| categories: [brevity, style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Use spread collections when possible. |
| |
| Collection literals are excellent when you want to create a new collection out |
| of individual items. But, when existing items are already stored in another |
| collection, spread collection syntax leads to simpler code. |
| |
| **BAD:** |
| |
| ```dart |
| Widget build(BuildContext context) { |
| return CupertinoPageScaffold( |
| child: ListView( |
| children: [ |
| Tab2Header(), |
| ]..addAll(buildTab2Conversation()), |
| ), |
| ); |
| } |
| ``` |
| |
| ```dart |
| var ints = [1, 2, 3]; |
| print(['a']..addAll(ints.map((i) => i.toString()))..addAll(['c'])); |
| ``` |
| |
| ```dart |
| var things; |
| var l = ['a']..addAll(things ?? const []); |
| ``` |
| |
| |
| **GOOD:** |
| |
| ```dart |
| Widget build(BuildContext context) { |
| return CupertinoPageScaffold( |
| child: ListView( |
| children: [ |
| Tab2Header(), |
| ...buildTab2Conversation(), |
| ], |
| ), |
| ); |
| } |
| ``` |
| |
| ```dart |
| var ints = [1, 2, 3]; |
| print(['a', ...ints.map((i) => i.toString()), 'c'); |
| ``` |
| |
| ```dart |
| var things; |
| var l = ['a', ...?things]; |
| ``` |
| prefer_typing_uninitialized_variables_for_field: |
| sharedName: prefer_typing_uninitialized_variables |
| problemMessage: "An uninitialized field should have an explicit type annotation." |
| correctionMessage: "Try adding a type annotation." |
| state: |
| stable: "2.0" |
| categories: [errorProne, unintentional] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a variable without an |
| initializer doesn't have an explicit type annotation. |
| |
| Without either a type annotation or an initializer, a variable has the |
| type `dynamic`, which allows any value to be assigned to the variable, |
| often causing hard to identify bugs. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the variable `r` |
| doesn't have either a type annotation or an initializer: |
| |
| ```dart |
| Object f() { |
| var [!r!]; |
| r = ''; |
| return r; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the variable can be initialized, then add an initializer: |
| |
| ```dart |
| Object f() { |
| var r = ''; |
| return r; |
| } |
| ``` |
| |
| If the variable can't be initialized, then add an explicit type |
| annotation: |
| |
| ```dart |
| Object f() { |
| String r; |
| r = ''; |
| return r; |
| } |
| ``` |
| deprecatedDetails: |- |
| **PREFER** specifying a type annotation for uninitialized variables and fields. |
| |
| Forgoing type annotations for uninitialized variables is a bad practice because |
| you may accidentally assign them to a type that you didn't originally intend to. |
| |
| **BAD:** |
| ```dart |
| class BadClass { |
| static var bar; // LINT |
| var foo; // LINT |
| |
| void method() { |
| var bar; // LINT |
| bar = 5; |
| print(bar); |
| } |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void aFunction() { |
| var bar; // LINT |
| bar = 5; |
| ... |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class GoodClass { |
| static var bar = 7; |
| var foo = 42; |
| int baz; // OK |
| |
| void method() { |
| int baz; |
| var bar = 5; |
| ... |
| } |
| } |
| ``` |
| prefer_typing_uninitialized_variables_for_local_variable: |
| sharedName: prefer_typing_uninitialized_variables |
| problemMessage: "An uninitialized variable should have an explicit type annotation." |
| correctionMessage: "Try adding a type annotation." |
| hasPublishedDocs: true |
| prefer_void_to_null: |
| problemMessage: "Unnecessary use of the type 'Null'." |
| correctionMessage: "Try using 'void' instead." |
| state: |
| experimental: "2.1" |
| stable: "2.2" |
| categories: [errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when `Null` is used in a location |
| where `void` would be a valid choice. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the function `f` is |
| declared to return `null` (at some future time): |
| |
| ```dart |
| Future<[!Null!]> f() async {} |
| ``` |
| |
| #### Common fixes |
| |
| Replace the use of `Null` with a use of `void`: |
| |
| ```dart |
| Future<void> f() async {} |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use the type Null where void would work. |
| |
| **BAD:** |
| ```dart |
| Null f() {} |
| Future<Null> f() {} |
| Stream<Null> f() {} |
| f(Null x) {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void f() {} |
| Future<void> f() {} |
| Stream<void> f() {} |
| f(void x) {} |
| ``` |
| |
| Some exceptions include formulating special function types: |
| |
| ```dart |
| Null Function(Null, Null); |
| ``` |
| |
| and for making empty literals which are safe to pass into read-only locations |
| for any type of map or list: |
| |
| ```dart |
| <Null>[]; |
| <int, Null>{}; |
| ``` |
| provide_deprecation_message: |
| problemMessage: "Missing a deprecation message." |
| correctionMessage: "Try using the constructor to provide a message ('@Deprecated(\"message\")')." |
| state: |
| stable: "2.2" |
| categories: [publicInterface] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `deprecated` annotation is |
| used instead of the `Deprecated` annotation. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the function `f` is |
| annotated with `deprecated`: |
| |
| ```dart |
| [!@deprecated!] |
| void f() {} |
| ``` |
| |
| #### Common fixes |
| |
| Convert the code to use the longer form: |
| |
| ```dart |
| @Deprecated('Use g instead. Will be removed in 4.0.0.') |
| void f() {} |
| ``` |
| deprecatedDetails: |- |
| **DO** specify a deprecation message (with migration instructions and/or a |
| removal schedule) in the `Deprecated` constructor. |
| |
| **BAD:** |
| ```dart |
| @deprecated |
| void oldFunction(arg1, arg2) {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| @Deprecated(""" |
| [oldFunction] is being deprecated in favor of [newFunction] (with slightly |
| different parameters; see [newFunction] for more information). [oldFunction] |
| will be removed on or after the 4.0.0 release. |
| """) |
| void oldFunction(arg1, arg2) {} |
| ``` |
| public_member_api_docs: |
| problemMessage: "Missing documentation for a public member." |
| correctionMessage: "Try adding documentation for the member." |
| state: |
| stable: "2.0" |
| categories: [publicInterface, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the declaration of part of the |
| public API of a package doesn't have a documentation comment. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the class `C` doesn't |
| have a documentation comment: |
| |
| ```dart |
| class [!C!] {} |
| ``` |
| |
| #### Common fixes |
| |
| Add a documentation comment. |
| |
| ```dart |
| /// Documentation comment. |
| class C {} |
| ``` |
| deprecatedDetails: |- |
| **DO** document all public members. |
| |
| All non-overriding public members should be documented with `///` doc-style |
| comments. |
| |
| **BAD:** |
| ```dart |
| class Bad { |
| void meh() { } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| /// A good thing. |
| abstract class Good { |
| /// Start doing your thing. |
| void start() => _start(); |
| |
| _start(); |
| } |
| ``` |
| |
| In case a public member overrides a member it is up to the declaring member |
| to provide documentation. For example, in the following, `Sub` needn't |
| document `init` (though it certainly may, if there's need). |
| |
| **GOOD:** |
| ```dart |
| /// Base of all things. |
| abstract class Base { |
| /// Initialize the base. |
| void init(); |
| } |
| |
| /// A sub base. |
| class Sub extends Base { |
| @override |
| void init() { ... } |
| } |
| ``` |
| |
| Note that consistent with `dart doc`, an exception to the rule is made when |
| documented getters have corresponding undocumented setters. In this case the |
| setters inherit the docs from the getters. |
| recursive_getters: |
| problemMessage: "The getter '{0}' recursively returns itself." |
| correctionMessage: "Try changing the value being returned." |
| state: |
| stable: "2.0" |
| categories: [errorProne, unintentional] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a getter invokes itself, |
| resulting in an infinite loop. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the getter `count` |
| invokes itself: |
| |
| ```dart |
| class C { |
| int _count = 0; |
| |
| int get [!count!] => count; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Change the getter to not invoke itself: |
| |
| ```dart |
| class C { |
| int _count = 0; |
| |
| int get count => _count; |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** create recursive getters. |
| |
| Recursive getters are getters which return themselves as a value. This is |
| usually a typo. |
| |
| **BAD:** |
| ```dart |
| int get field => field; // LINT |
| ``` |
| |
| **BAD:** |
| ```dart |
| int get otherField { |
| return otherField; // LINT |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| int get field => _field; |
| ``` |
| require_trailing_commas: |
| problemMessage: "Missing a required trailing comma." |
| correctionMessage: "Try adding a trailing comma." |
| state: |
| stable: "2.14" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DO** use trailing commas for all multi-line parameter lists and argument |
| lists. A parameter list or argument list that fits on one line, including the |
| opening parenthesis and closing parenthesis, does not require a trailing comma. |
| |
| **BAD:** |
| ```dart |
| void run() { |
| method('does not fit on one line', |
| 'test test test test test test test test test test test'); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void run() { |
| method( |
| 'does not fit on one line', |
| 'test test test test test test test test test test test', |
| ); |
| } |
| ``` |
| |
| **EXCEPTION:** If the final argument in an argument list is positional (vs |
| named) and is either a function literal with curly braces, a map literal, a set |
| literal, or a list literal, then a trailing comma is not required. |
| This exception only applies if the final argument does not fit entirely on one |
| line. |
| |
| **NOTE:** This lint rule assumes that code has been formatted with `dart format` |
| and may produce false positives on unformatted code. |
| secure_pubspec_urls: |
| problemMessage: "The '{0}' protocol shouldn't be used because it isn't secure." |
| correctionMessage: "Try using a secure protocol, such as 'https'." |
| state: |
| stable: "2.16" |
| categories: [pub] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a URL in a `pubspec.yaml` file is |
| using a non-secure scheme, such as `http`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the `pubspec.yaml` file |
| contains an `http` URL: |
| |
| ```yaml |
| dependencies: |
| example: any |
| repository: [!http://github.com/dart-lang/example!] |
| ``` |
| |
| #### Common fixes |
| |
| Change the scheme of the URL to use a secure scheme, such as `https`: |
| |
| ```yaml |
| dependencies: |
| example: any |
| repository: https://github.com/dart-lang/example |
| ``` |
| deprecatedDetails: |- |
| **DO** Use secure urls in `pubspec.yaml`. |
| |
| Use `https` instead of `http` or `git:`. |
| |
| **BAD:** |
| ```yaml |
| repository: http://github.com/dart-lang/example |
| ``` |
| |
| ```yaml |
| git: |
| url: git://github.com/dart-lang/example/example.git |
| ``` |
| |
| **GOOD:** |
| ```yaml |
| repository: https://github.com/dart-lang/example |
| ``` |
| sized_box_for_whitespace: |
| problemMessage: "Use a 'SizedBox' to add whitespace to a layout." |
| correctionMessage: "Try using a 'SizedBox' rather than a 'Container'." |
| state: |
| stable: "2.9" |
| categories: [flutter, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `Container` is created using |
| only the `height` and/or `width` arguments. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the `Container` has |
| only the `width` argument: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget buildRow() { |
| return Row( |
| children: <Widget>[ |
| const Text('...'), |
| [!Container!]( |
| width: 4, |
| child: Text('...'), |
| ), |
| const Expanded( |
| child: Text('...'), |
| ), |
| ], |
| ); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Replace the `Container` with a `SizedBox` of the same dimensions: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget buildRow() { |
| return Row( |
| children: <Widget>[ |
| Text('...'), |
| SizedBox( |
| width: 4, |
| child: Text('...'), |
| ), |
| Expanded( |
| child: Text('...'), |
| ), |
| ], |
| ); |
| } |
| ``` |
| deprecatedDetails: |- |
| Use `SizedBox` to add whitespace to a layout. |
| |
| A `Container` is a heavier Widget than a `SizedBox`, and as bonus, `SizedBox` |
| has a `const` constructor. |
| |
| **BAD:** |
| ```dart |
| Widget buildRow() { |
| return Row( |
| children: <Widget>[ |
| const MyLogo(), |
| Container(width: 4), |
| const Expanded( |
| child: Text('...'), |
| ), |
| ], |
| ); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Widget buildRow() { |
| return Row( |
| children: const <Widget>[ |
| MyLogo(), |
| SizedBox(width: 4), |
| Expanded( |
| child: Text('...'), |
| ), |
| ], |
| ); |
| } |
| ``` |
| sized_box_shrink_expand: |
| problemMessage: "Use 'SizedBox.{0}' to avoid needing to specify the 'height' and 'width'." |
| correctionMessage: "Try using 'SizedBox.{0}' and removing the 'height' and 'width' arguments." |
| state: |
| stable: "2.16" |
| categories: [flutter, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `SizedBox` constructor |
| invocation specifies the values of both `height` and `width` as either |
| `0.0` or `double.infinity`. |
| |
| #### Examples |
| |
| The following code produces this diagnostic because both the `height` and |
| `width` are `0.0`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget build() { |
| return [!SizedBox!]( |
| height: 0.0, |
| width: 0.0, |
| child: const Text(''), |
| ); |
| } |
| ``` |
| |
| The following code produces this diagnostic because both the `height` and |
| `width` are `double.infinity`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget build() { |
| return [!SizedBox!]( |
| height: double.infinity, |
| width: double.infinity, |
| child: const Text(''), |
| ); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If both are `0.0`, then use `SizedBox.shrink`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget build() { |
| return SizedBox.shrink( |
| child: const Text(''), |
| ); |
| } |
| ``` |
| |
| If both are `double.infinity`, then use `SizedBox.expand`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget build() { |
| return SizedBox.expand( |
| child: const Text(''), |
| ); |
| } |
| ``` |
| deprecatedDetails: |- |
| Use `SizedBox.shrink(...)` and `SizedBox.expand(...)` constructors |
| appropriately. |
| |
| Either the `SizedBox.shrink(...)` or `SizedBox.expand(...)` constructor should |
| be used instead of the more general `SizedBox(...)` constructor when one of the |
| named constructors capture the intent of the code more succinctly. |
| |
| **Examples** |
| |
| **BAD:** |
| ```dart |
| Widget buildLogo() { |
| return SizedBox( |
| height: 0, |
| width: 0, |
| child: const MyLogo(), |
| ); |
| } |
| ``` |
| |
| ```dart |
| Widget buildLogo() { |
| return SizedBox( |
| height: double.infinity, |
| width: double.infinity, |
| child: const MyLogo(), |
| ); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Widget buildLogo() { |
| return SizedBox.shrink( |
| child: const MyLogo(), |
| ); |
| } |
| ``` |
| |
| ```dart |
| Widget buildLogo() { |
| return SizedBox.expand( |
| child: const MyLogo(), |
| ); |
| } |
| ``` |
| slash_for_doc_comments: |
| problemMessage: "Use the end-of-line form ('///') for doc comments." |
| correctionMessage: "Try rewriting the comment to use '///'." |
| state: |
| stable: "2.0" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a documentation comment uses |
| the block comment style (delimited by `/**` and `*/`). |
| |
| #### Example |
| |
| The following code produces this diagnostic because the documentation |
| comment for `f` uses a block comment style: |
| |
| ```dart |
| [!/** |
| * Example. |
| */!] |
| void f() {} |
| ``` |
| |
| #### Common fixes |
| |
| Use an end-of-line comment style: |
| |
| ```dart |
| /// Example. |
| void f() {} |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/documentation#do-use--doc-comments-to-document-members-and-types): |
| |
| **DO** use `///` for documentation comments. |
| |
| Although Dart supports two syntaxes of doc comments (`///` and `/**`), we |
| prefer using `///` for doc comments. |
| |
| **GOOD:** |
| ```dart |
| /// Parses a set of option strings. For each option: |
| /// |
| /// * If it is `null`, then it is ignored. |
| /// * If it is a string, then [validate] is called on it. |
| /// * If it is any other type, it is *not* validated. |
| void parse(List options) { |
| // ... |
| } |
| ``` |
| |
| Within a doc comment, you can use markdown for formatting. |
| sort_child_properties_last: |
| problemMessage: "The '{0}' argument should be last in widget constructor invocations." |
| correctionMessage: "Try moving the argument to the end of the argument list." |
| state: |
| stable: "2.4" |
| categories: [flutter, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the `child` or `children` |
| argument isn't the last argument in an invocation of a widget class' |
| constructor. An exception is made if all of the arguments after the |
| `child` or `children` argument are function expressions. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the `child` argument |
| isn't the last argument in the invocation of the `Center` constructor: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget createWidget() { |
| return Center( |
| [!child: Text('...')!], |
| widthFactor: 0.5, |
| ); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Move the `child` or `children` argument to be last: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget createWidget() { |
| return Center( |
| widthFactor: 0.5, |
| child: Text('...'), |
| ); |
| } |
| ``` |
| deprecatedDetails: |- |
| Sort child properties last in widget instance creations. This improves |
| readability and plays nicest with UI as Code visualization in IDEs with UI as |
| Code Guides in editors (such as IntelliJ) where Properties in the correct order |
| appear clearly associated with the constructor call and separated from the |
| children. |
| |
| **BAD:** |
| ```dart |
| return Scaffold( |
| appBar: AppBar( |
| title: Text(widget.title), |
| ), |
| body: Center( |
| child: Column( |
| children: <Widget>[ |
| Text( |
| 'You have pushed the button this many times:', |
| ), |
| Text( |
| '$_counter', |
| style: Theme.of(context).textTheme.display1, |
| ), |
| ], |
| mainAxisAlignment: MainAxisAlignment.center, |
| ), |
| widthFactor: 0.5, |
| ), |
| floatingActionButton: FloatingActionButton( |
| child: Icon(Icons.add), |
| onPressed: _incrementCounter, |
| tooltip: 'Increment', |
| ), |
| ); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| return Scaffold( |
| appBar: AppBar( |
| title: Text(widget.title), |
| ), |
| body: Center( |
| widthFactor: 0.5, |
| child: Column( |
| mainAxisAlignment: MainAxisAlignment.center, |
| children: <Widget>[ |
| Text( |
| 'You have pushed the button this many times:', |
| ), |
| Text( |
| '$_counter', |
| style: Theme.of(context).textTheme.display1, |
| ), |
| ], |
| ), |
| ), |
| floatingActionButton: FloatingActionButton( |
| onPressed: _incrementCounter, |
| tooltip: 'Increment', |
| child: Icon(Icons.add), |
| ), |
| ); |
| ``` |
| |
| Exception: It's allowed to have parameter with a function expression after the |
| `child` property. |
| sort_constructors_first: |
| problemMessage: "Constructor declarations should be before non-constructor declarations." |
| correctionMessage: "Try moving the constructor declaration before all other members." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a constructor declaration is |
| preceded by one or more non-constructor declarations. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the constructor for |
| `C` appears after the method `m`: |
| |
| ```dart |
| class C { |
| void m() {} |
| |
| [!C!](); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Move all of the constructor declarations before any other declarations: |
| |
| ```dart |
| class C { |
| C(); |
| |
| void m() {} |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** sort constructor declarations before other members. |
| |
| **BAD:** |
| ```dart |
| abstract class Visitor { |
| double value; |
| visitSomething(Something s); |
| Visitor(); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| abstract class Animation<T> { |
| const Animation(this.value); |
| double value; |
| void addListener(VoidCallback listener); |
| } |
| ``` |
| sort_pub_dependencies: |
| problemMessage: "Dependencies not sorted alphabetically." |
| correctionMessage: "Try sorting the dependencies alphabetically (A to Z)." |
| state: |
| stable: "2.1" |
| categories: [pub] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the keys in a dependency map in |
| the `pubspec.yaml` file aren't sorted alphabetically. The dependency maps |
| that are checked are the `dependencies`, `dev_dependencies`, and |
| `dependency_overrides` maps. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the entries in the |
| `dependencies` map are not sorted: |
| |
| ```yaml |
| dependencies: |
| path: any |
| collection: any |
| ``` |
| |
| #### Common fixes |
| |
| Sort the entries: |
| |
| ```yaml |
| dependencies: |
| collection: any |
| path: any |
| ``` |
| deprecatedDetails: |- |
| **DO** sort pub dependencies alphabetically (A to Z) in `pubspec.yaml`. |
| |
| Sorting list of pub dependencies makes maintenance easier. |
| sort_unnamed_constructors_first: |
| problemMessage: "Invalid location for the unnamed constructor." |
| correctionMessage: "Try moving the unnamed constructor before all other constructors." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an unnamed constructor appears |
| after a named constructor. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the unnamed |
| constructor is after the named constructor: |
| |
| ```dart |
| class C { |
| C.named(); |
| |
| [!C!](); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Move the unnamed constructor before any other constructors: |
| |
| ```dart |
| class C { |
| C(); |
| |
| C.named(); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** sort unnamed constructor declarations first, before named ones. |
| |
| **BAD:** |
| ```dart |
| class _PriorityItem { |
| factory _PriorityItem.forName(bool isStatic, String name, _MemberKind kind) => ... |
| _PriorityItem(this.isStatic, this.kind, this.isPrivate); |
| ... |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| abstract class CancelableFuture<T> implements Future<T> { |
| factory CancelableFuture(computation()) => ... |
| factory CancelableFuture.delayed(Duration duration, [computation()]) => ... |
| ... |
| } |
| ``` |
| specify_nonobvious_local_variable_types: |
| problemMessage: "Specify the type of a local variable when the type is non-obvious." |
| correctionMessage: "Try adding a type annotation." |
| state: |
| experimental: "3.6" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Do type annotate initialized local variables when the type is non-obvious. |
| |
| Type annotations on local variables can serve as a request for type inference, |
| documenting the expected outcome of the type inference step, and declaratively |
| allowing the compiler and analyzer to solve the possibly complex task of |
| finding type arguments and annotations in the initializing expression that |
| yield the desired result. |
| |
| Type annotations on local variables can also inform readers about the type |
| of the initializing expression, which will allow them to proceed reading the |
| subsequent lines of code with known good information about the type of the |
| given variable (which may not be immediately evident by looking at the |
| initializing expression). |
| |
| An expression is considered to have a non-obvious type when it does not |
| have an obvious type. |
| |
| An expression e has an obvious type in the following cases: |
| |
| - e is a non-collection literal. For instance, 1, true, 'Hello, $name!'. |
| - e is a collection literal with actual type arguments. For instance, |
| <int, bool>{}. |
| - e is a list literal or a set literal where at least one element has an |
| obvious type, and all elements have the same type. For instance, [1, 2] and |
| { [true, false], [] }, but not [1, 1.5]. |
| - e is a map literal where all key-value pair have a key with an obvious type |
| and a value with an obvious type, and all keys have the same type, and all |
| values have the same type. For instance, { #a: <int>[] }, but not |
| {1: 1, 2: true}. |
| - e is an instance creation expression whose class part is not raw. For |
| instance C(14) if C is a non-generic class, or C<int>(14) if C accepts one |
| type argument, but not C(14) if C accepts one or more type arguments. |
| - e is a cascade whose target has an obvious type. For instance, |
| 1..isEven..isEven has an obvious type because 1 has an obvious type. |
| - e is a type cast. For instance, myComplexExpression as int. |
| |
| **BAD:** |
| ```dart |
| List<List<Ingredient>> possibleDesserts(Set<Ingredient> pantry) { |
| var desserts = genericFunctionDeclaredFarAway(<num>[42], 'Something'); |
| for (final recipe in cookbook) { |
| if (pantry.containsAll(recipe)) { |
| desserts.add(recipe); |
| } |
| } |
| |
| return desserts; |
| } |
| |
| const List<List<Ingredient>> cookbook = ...; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| List<List<Ingredient>> possibleDesserts(Set<Ingredient> pantry) { |
| List<List<Ingredient>> desserts = genericFunctionDeclaredFarAway( |
| <num>[42], |
| 'Something', |
| ); |
| for (final List<Ingredient> recipe in cookbook) { |
| if (pantry.containsAll(recipe)) { |
| desserts.add(recipe); |
| } |
| } |
| |
| return desserts; |
| } |
| |
| const List<List<Ingredient>> cookbook = ...; |
| ``` |
| |
| **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/sdk/issues/58773. |
| specify_nonobvious_property_types: |
| problemMessage: "A type annotation is needed because it isn't obvious." |
| correctionMessage: "Try adding a type annotation." |
| state: |
| experimental: "3.7" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Do type annotate initialized top-level or static variables when the type is |
| non-obvious. |
| |
| Type annotations on top-level or static variables can serve as a request for |
| type inference, documenting the expected outcome of the type inference step, |
| and declaratively allowing the compiler and analyzer to solve the possibly |
| complex task of finding type arguments and annotations in the initializing |
| expression that yield the desired result. |
| |
| Type annotations on top-level or static variables can also inform readers about |
| the type of the initializing expression, which will allow them to proceed |
| reading the locations in code where this variable is used with known good |
| information about the type of the given variable (which may not be immediately |
| evident by looking at the initializing expression). |
| |
| An expression is considered to have a non-obvious type when it does not |
| have an obvious type. |
| |
| An expression e has an obvious type in the following cases: |
| |
| - e is a non-collection literal. For instance, 1, true, 'Hello, $name!'. |
| - e is a collection literal with actual type arguments. For instance, |
| <int, bool>{}. |
| - e is a list literal or a set literal where at least one element has an |
| obvious type, and all elements have the same type. For instance, [1, 2] and |
| { [true, false], [] }, but not [1, 1.5]. |
| - e is a map literal where all key-value pair have a key with an obvious type |
| and a value with an obvious type, and all keys have the same type, and all |
| values have the same type. For instance, { #a: <int>[] }, but not |
| {1: 1, 2: true}. |
| - e is an instance creation expression whose class part is not raw. For |
| instance C(14) if C is a non-generic class, or C<int>(14) if C accepts one |
| type argument, but not C(14) if C accepts one or more type arguments. |
| - e is a cascade whose target has an obvious type. For instance, |
| 1..isEven..isEven has an obvious type because 1 has an obvious type. |
| - e is a type cast. For instance, `myComplexExpression as int`. |
| |
| **BAD:** |
| ```dart |
| final myTopLevelVariable = |
| genericFunctionWrittenByOtherFolks(with, args); |
| |
| class A { |
| static var myStaticVariable = |
| myTopLevelVariable.update('foo', null); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| final Map<String, Widget?> myTopLevelVariable = |
| genericFunctionWrittenByOtherFolks(with, args); |
| |
| class A { |
| static Map<String, Widget?> myStaticVariable = |
| myTopLevelVariable.update('foo', null); |
| } |
| ``` |
| |
| **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/sdk/issues/59550. |
| strict_top_level_inference_add_type: |
| sharedName: strict_top_level_inference |
| problemMessage: "Missing type annotation." |
| correctionMessage: "Try adding a type annotation." |
| state: |
| stable: "3.7" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Do type annotate top-level and class-like member declarations, where types |
| are not inferred from super-interfaces or initializers. |
| |
| The lint warns about every omitted return type, parameter type, and |
| variable type of a top-level declaration or class-like-namespace-level |
| declaration (static or instance member or constructor declaration), which |
| is not given a type by inference, and which therefore defaults to dynamic. |
| |
| The only omitted types that can be given a type by top-level inference, |
| are those of variable declarations with initializer expressions, and |
| return and parameter types of instance members that override a consistent |
| combined super-interface signature. |
| |
| Setters do not need a return type, as it is always assumed to be `void`. |
| |
| **BAD:** |
| ```dart |
| var _zeroPointCache; |
| class Point { |
| get zero => ...; |
| final x, y; |
| Point(x, y) {} |
| closest(b, c) => distance(b) <= distance(c) ? b : c; |
| distance(other) => ...; |
| } |
| _sq(v) => v * v; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Point? _zeroPointCache; |
| class Point { |
| Point get zero => ...; |
| final int x, y; |
| Point(int x, int y) {} |
| closest(Point b, Point c) => |
| distance(b) <= distance(c) ? b : c; |
| distance(Point other) => ...; |
| } |
| int _sq(int v) => v * v; |
| ``` |
| strict_top_level_inference_replace_keyword: |
| sharedName: strict_top_level_inference |
| problemMessage: "Missing type annotation." |
| correctionMessage: "Try replacing '{0}' with a type annotation." |
| hasPublishedDocs: false |
| strict_top_level_inference_split_to_types: |
| sharedName: strict_top_level_inference |
| problemMessage: "Missing type annotation." |
| correctionMessage: "Try splitting the declaration and specify the different type annotations." |
| hasPublishedDocs: false |
| super_goes_last: |
| state: |
| stable: "2.0" |
| removed: "3.0" |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| NOTE: This rule is removed in Dart 3.0.0; it is no longer functional. |
| |
| **DO** place the `super` call last in a constructor initialization list. |
| |
| Field initializers are evaluated in the order that they appear in the |
| constructor initialization list. If you place a `super()` call in the middle of |
| an initializer list, the superclass's initializers will be evaluated right then |
| before evaluating the rest of the subclass's initializers. |
| |
| What it doesn't mean is that the superclass's constructor body will be executed |
| then. That always happens after all initializers are run regardless of where |
| `super` appears. It's vanishingly rare that the order of initializers matters, |
| so the placement of `super` in the list almost never matters either. |
| |
| Getting in the habit of placing it last improves consistency, visually |
| reinforces when the superclass's constructor body is run, and may help |
| performance. |
| |
| **BAD:** |
| ```dart |
| View(Style style, List children) |
| : super(style), |
| _children = children { |
| ``` |
| |
| **GOOD:** |
| ```dart |
| View(Style style, List children) |
| : _children = children, |
| super(style) { |
| ``` |
| switch_on_type: |
| problemMessage: "Avoid switch statements on a 'Type'." |
| correctionMessage: "Try using pattern matching on a variable instead." |
| state: |
| stable: "3.9" |
| categories: [unintentional, style, languageFeatureUsage, errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a switch statement or switch |
| expression is used on either the value of a `Type` or a `toString` call |
| on a `Type`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the switch statement |
| is used on a `Type`: |
| |
| ```dart |
| void f(Object o) { |
| switch ([!o.runtimeType!]) { |
| case const (int): |
| print('int'); |
| case const (String): |
| print('String'); |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use pattern matching on the variable instead: |
| |
| ```dart |
| void f(Object o) { |
| switch (o) { |
| case int(): |
| print('int'); |
| case String(): |
| print('String'); |
| } |
| } |
| ``` |
| deprecatedDetails: |- |
| **AVOID** using switch on `Type`. |
| |
| Switching on `Type` is not type-safe and can lead to bugs if the |
| class hierarchy changes. Prefer to use pattern matching on the variable |
| instead. |
| |
| **BAD:** |
| ```dart |
| void f(Object o) { |
| switch (o.runtimeType) { |
| case int: |
| print('int'); |
| case String: |
| print('String'); |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void f(Object o) { |
| switch(o) { |
| case int(): |
| print('int'); |
| case String _: |
| print('String'); |
| default: |
| print('other'); |
| } |
| } |
| ``` |
| test_types_in_equals: |
| problemMessage: "Missing type test for '{0}' in '=='." |
| correctionMessage: "Try testing the type of '{0}'." |
| state: |
| stable: "2.0" |
| categories: [errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an override of the `==` |
| operator doesn't include a type test on the value of the parameter. |
| |
| #### Example |
| |
| The following code produces this diagnostic because `other` is not type |
| tested: |
| |
| ```dart |
| class C { |
| final int f; |
| |
| C(this.f); |
| |
| @override |
| bool operator ==(Object other) { |
| return ([!other as C!]).f == f; |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Perform an `is` test as part of computing the return value: |
| |
| ```dart |
| class C { |
| final int f; |
| |
| C(this.f); |
| |
| @override |
| bool operator ==(Object other) { |
| return other is C && other.f == f; |
| } |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** test type of argument in `operator ==(Object other)`. |
| |
| Not testing the type might result in runtime type errors which will be |
| unexpected for consumers of your class. |
| |
| **BAD:** |
| ```dart |
| class Field { |
| } |
| |
| class Bad { |
| final Field someField; |
| |
| Bad(this.someField); |
| |
| @override |
| bool operator ==(Object other) { |
| Bad otherBad = other as Bad; // LINT |
| bool areEqual = otherBad != null && otherBad.someField == someField; |
| return areEqual; |
| } |
| |
| @override |
| int get hashCode { |
| return someField.hashCode; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Field { |
| } |
| |
| class Good { |
| final Field someField; |
| |
| Good(this.someField); |
| |
| @override |
| bool operator ==(Object other) { |
| if (identical(this, other)) { |
| return true; |
| } |
| return other is Good && |
| this.someField == other.someField; |
| } |
| |
| @override |
| int get hashCode { |
| return someField.hashCode; |
| } |
| } |
| ``` |
| throw_in_finally: |
| problemMessage: "Use of '{0}' in 'finally' block." |
| correctionMessage: "Try moving the '{0}' outside the 'finally' block." |
| state: |
| stable: "2.0" |
| categories: [errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `throw` statement is found |
| inside a `finally` block. |
| |
| #### Example |
| |
| The following code produces this diagnostic because there is a `throw` |
| statement inside a `finally` block: |
| |
| ```dart |
| void f() { |
| try { |
| // ... |
| } catch (e) { |
| // ... |
| } finally { |
| [!throw 'error'!]; |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Rewrite the code so that the `throw` statement isn't inside a `finally` |
| block: |
| |
| ```dart |
| void f() { |
| try { |
| // ... |
| } catch (e) { |
| // ... |
| } |
| throw 'error'; |
| } |
| ``` |
| deprecatedDetails: |- |
| **AVOID** throwing exceptions in `finally` blocks. |
| |
| Throwing exceptions in `finally` blocks will inevitably cause unexpected |
| behavior that is hard to debug. |
| |
| **BAD:** |
| ```dart |
| class BadThrow { |
| double nonCompliantMethod() { |
| try { |
| print('hello world! ${1 / 0}'); |
| } catch (e) { |
| print(e); |
| } finally { |
| throw 'Find the hidden error :P'; // LINT |
| } |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Ok { |
| double compliantMethod() { |
| var i = 5; |
| try { |
| i = 1 / 0; |
| } catch (e) { |
| print(e); // OK |
| } |
| return i; |
| } |
| } |
| ``` |
| tighten_type_of_initializing_formals: |
| problemMessage: "Use a type annotation rather than 'assert' to enforce non-nullability." |
| correctionMessage: "Try adding a type annotation and removing the 'assert'." |
| state: |
| stable: "2.12" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an `assert` is being used in |
| the initializer list of a constructor to ensure that only a non-`null` |
| value is being used to initialize a field. |
| |
| #### Example |
| |
| The following code produces this diagnostic because an `assert` is being |
| used to catch an error that could be caught by the type system: |
| |
| ```dart |
| class C { |
| final String? s; |
| |
| C([!this.s!]) : assert(s != null); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Remove the `assert` and add the non-nullable type before the initializing |
| formal: |
| |
| ```dart |
| class C { |
| final String? s; |
| |
| C(String this.s); |
| } |
| ``` |
| deprecatedDetails: |- |
| Tighten the type of an initializing formal if a non-null assert exists. This |
| allows the type system to catch problems rather than have them only be caught at |
| run-time. |
| |
| **BAD:** |
| ```dart |
| class A { |
| A.c1(this.p) : assert(p != null); |
| A.c2(this.p); |
| final String? p; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| A.c1(String this.p); |
| A.c2(this.p); |
| final String? p; |
| } |
| |
| class B { |
| String? b; |
| B(this.b); |
| } |
| |
| class C extends B { |
| B(String super.b); |
| } |
| ``` |
| type_annotate_public_apis: |
| problemMessage: "Missing type annotation on a public API." |
| correctionMessage: "Try adding a type annotation." |
| state: |
| stable: "2.0" |
| categories: [effectiveDart, publicInterface] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the declaration of part of the |
| public API of a package doesn't have explicit type annotations. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the function `f` |
| doesn't have an explicit return type and the parameters `x` and `y` don't |
| have explicit types: |
| |
| ```dart |
| [!f!](x, y) => ''; |
| ``` |
| |
| #### Common fixes |
| |
| Add type annotations to the API: |
| |
| ```dart |
| String f(int x, int y) => ''; |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/design#do-type-annotate-fields-and-top-level-variables-if-the-type-isnt-obvious): |
| |
| **PREFER** type annotating public APIs. |
| |
| Type annotations are important documentation for how a library should be used. |
| Annotating the parameter and return types of public methods and functions helps |
| users understand what the API expects and what it provides. |
| |
| Note that if a public API accepts a range of values that Dart's type system |
| cannot express, then it is acceptable to leave that untyped. In that case, the |
| implicit `dynamic` is the correct type for the API. |
| |
| For code internal to a library (either private, or things like nested functions) |
| annotate where you feel it helps, but don't feel that you *must* provide them. |
| |
| **BAD:** |
| ```dart |
| install(id, destination) { |
| // ... |
| } |
| ``` |
| |
| Here, it's unclear what `id` is. A string? And what is `destination`? A string |
| or a `File` object? Is this method synchronous or asynchronous? |
| |
| **GOOD:** |
| ```dart |
| Future<bool> install(PackageId id, String destination) { |
| // ... |
| } |
| ``` |
| |
| With types, all of this is clarified. |
| type_init_formals: |
| problemMessage: "Don't needlessly type annotate initializing formals." |
| correctionMessage: "Try removing the type." |
| state: |
| stable: "2.0" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an initializing formal |
| parameter (`this.x`) or a super parameter (`super.x`) has an explicit type |
| annotation that is the same as the field or overridden parameter. |
| |
| If a constructor parameter is using `this.x` to initialize a field, then |
| the type of the parameter is implicitly the same type as the field. If a |
| constructor parameter is using `super.x` to forward to a super |
| constructor, then the type of the parameter is implicitly the same as the |
| super constructor parameter. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the parameter `this.c` |
| has an explicit type that is the same as the field `c`: |
| |
| ```dart |
| class C { |
| int c; |
| |
| C([!int!] this.c); |
| } |
| ``` |
| |
| The following code produces this diagnostic because the parameter |
| `super.a` has an explicit type that is the same as the parameter `a` from |
| the superclass: |
| |
| ```dart |
| class A { |
| A(int a); |
| } |
| |
| class B extends A { |
| B([!int!] super.a); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Remove the type annotation from the parameter: |
| |
| ```dart |
| class C { |
| int c; |
| |
| C(this.c); |
| } |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/design#dont-type-annotate-initializing-formals): |
| |
| **DON'T** type annotate initializing formals. |
| |
| If a constructor parameter is using `this.x` to initialize a field, then the |
| type of the parameter is understood to be the same type as the field. If a |
| a constructor parameter is using `super.x` to forward to a super constructor, |
| then the type of the parameter is understood to be the same as the super |
| constructor parameter. |
| |
| Type annotating an initializing formal with a different type than that of the |
| field is OK. |
| |
| **BAD:** |
| ```dart |
| class Point { |
| int x, y; |
| Point(int this.x, int this.y); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Point { |
| int x, y; |
| Point(this.x, this.y); |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| class A { |
| int a; |
| A(this.a); |
| } |
| |
| class B extends A { |
| B(int super.a); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| int a; |
| A(this.a); |
| } |
| |
| class B extends A { |
| B(super.a); |
| } |
| ``` |
| type_literal_in_constant_pattern: |
| problemMessage: "Use 'TypeName _' instead of a type literal." |
| correctionMessage: "Replace with 'TypeName _'." |
| state: |
| stable: "3.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a type literal appears as a |
| pattern. |
| |
| #### Example |
| |
| The following code produces this diagnostic because a type literal is used |
| as a constant pattern: |
| |
| ```dart |
| void f(Object? x) { |
| if (x case [!num!]) { |
| // ... |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the type literal is intended to match an object of the given type, then |
| use either a variable pattern: |
| |
| ```dart |
| void f(Object? x) { |
| if (x case num _) { |
| // ... |
| } |
| } |
| ``` |
| |
| Or an object pattern: |
| |
| ```dart |
| void f(Object? x) { |
| if (x case num()) { |
| // ... |
| } |
| } |
| ``` |
| |
| If the type literal is intended to match the type literal, then write it |
| as a constant pattern: |
| |
| ```dart |
| void f(Object? x) { |
| if (x case const (num)) { |
| // ... |
| } |
| } |
| ``` |
| deprecatedDetails: |- |
| If you meant to test if the object has type `Foo`, instead write `Foo _`. |
| |
| **BAD:** |
| ```dart |
| void f(Object? x) { |
| if (x case num) { |
| print('int or double'); |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void f(Object? x) { |
| if (x case num _) { |
| print('int or double'); |
| } |
| } |
| ``` |
| |
| If you do mean to test that the matched value (which you expect to have the |
| type `Type`) is equal to the type literal `Foo`, then this lint can be |
| silenced using `const (Foo)`. |
| |
| **BAD:** |
| ```dart |
| void f(Object? x) { |
| if (x case int) { |
| print('int'); |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void f(Object? x) { |
| if (x case const (int)) { |
| print('int'); |
| } |
| } |
| ``` |
| unawaited_futures: |
| problemMessage: "Missing an 'await' for the 'Future' computed by this expression." |
| correctionMessage: "Try adding an 'await' or wrapping the expression with 'unawaited'." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic on an expression with a `Future` |
| type, only in a few specific cases: |
| |
| * when the expression is itself a statement (like `f();`), |
| * when the expression is part of a cascade (like `C()..f()`), |
| * when the expression is a String interpolation (like `'${f()}'`). |
| |
| The analyzer only produces this diagnostic on expressions inside an |
| `async` or `async*` function. |
| |
| The two common corrections are to 'await' the expression, or to wrap the |
| expression in a call to `unawaited()`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the function `g` |
| returns a future, but the future isn't awaited: |
| |
| ```dart |
| Future<void> f() async { |
| [!g!](); |
| } |
| |
| Future<int> g() => Future.value(0); |
| ``` |
| |
| #### Common fixes |
| |
| If the future needs to complete before the following code is executed, |
| then add an `await` before the invocation: |
| |
| ```dart |
| Future<void> f() async { |
| await g(); |
| } |
| |
| Future<int> g() => Future.value(0); |
| ``` |
| |
| If the future doesn't need to complete before the following code is |
| executed, then wrap the `Future`-returning invocation in an invocation of |
| the `unawaited` function: |
| |
| ```dart |
| import 'dart:async'; |
| |
| Future<void> f() async { |
| unawaited(g()); |
| } |
| |
| Future<int> g() => Future.value(0); |
| ``` |
| deprecatedDetails: |- |
| **DO** await functions that return a `Future` inside of an async function body. |
| |
| It's easy to forget await in async methods as naming conventions usually don't |
| tell us if a method is sync or async (except for some in `dart:io`). |
| |
| When you really _do_ want to start a fire-and-forget `Future`, the recommended |
| way is to use `unawaited` from `dart:async`. The `// ignore` and |
| `// ignore_for_file` comments also work. |
| |
| **BAD:** |
| ```dart |
| void main() async { |
| doSomething(); // Likely a bug. |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Future doSomething() => ...; |
| |
| void main() async { |
| await doSomething(); |
| |
| unawaited(doSomething()); // Explicitly-ignored fire-and-forget. |
| } |
| ``` |
| unintended_html_in_doc_comment: |
| problemMessage: "Angle brackets will be interpreted as HTML." |
| correctionMessage: "Try using backticks around the content with angle brackets, or try replacing `<` with `<` and `>` with `>`." |
| state: |
| stable: "3.5" |
| categories: [errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a documentation comment |
| contains angle bracketed text (`<...>`) that isn't one of the allowed |
| exceptions. |
| |
| Such text is interpreted by markdown to be an HTML tag, which is rarely |
| what was intended. |
| |
| See the [lint rule description](https://dart.dev/tools/linter-rules/unintended_html_in_doc_comment) |
| for the list of allowed exceptions. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the documentation |
| comment contains the text `<int>`, which isn't one of the allowed |
| exceptions: |
| |
| ```dart |
| /// Converts a List[!<int>!] to a comma-separated String. |
| String f(List<int> l) => ''; |
| ``` |
| |
| #### Common fixes |
| |
| If the text was intended to be part of a code span, then add backticks |
| around the code: |
| |
| ```dart |
| /// Converts a `List<int>` to a comma-separated String. |
| String f(List<int> l) => ''; |
| ``` |
| |
| If the text was intended to be part of a link, then add square brackets |
| around the code: |
| |
| ```dart |
| /// Converts a [List<int>] to a comma-separated String. |
| String f(List<int> l) => ''; |
| ``` |
| |
| If the text was intended to be printed as-is, including the angle |
| brackets, then add backslash escapes before the angle brackets: |
| |
| ```dart |
| /// Converts a List\<int\> to a comma-separated String. |
| String f(List<int> l) => ''; |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use angle-bracketed text, `<…>`, in a doc comment unless you want to |
| write an HTML tag or link. |
| |
| Markdown allows HTML tags as part of the Markdown code, so you can write, for |
| example, `T<sub>1</sub>`. Markdown does not restrict the allowed tags, it just |
| includes the tags verbatim in the output. |
| |
| Dartdoc only allows some known and valid HTML tags, and will omit any disallowed |
| HTML tag from the output. See the list of allowed tags and directives below. |
| Your doc comment should not contain any HTML tags that are not on this list. |
| |
| Markdown also allows you to write an "auto-link" to an URL as for example |
| `<https://example.com/page.html>`, delimited only by `<...>`. Such a link is |
| allowed by Dartdoc as well. |
| A `<...>` delimited text is an auto-link if it is a valid absolute URL, starting |
| with a scheme of at least two characters followed by a colon, like |
| `<mailto:mr_example@example.com>`. |
| |
| Any other other occurrence of `<word...>` or `</word...>` is likely a mistake |
| and this lint will warn about it. |
| If something looks like an HTML tag, meaning it starts with `<` or `</` |
| and then a letter, and it has a later matching `>`, then it's considered an |
| invalid HTML tag unless it is an auto-link, or it starts with an *allowed* |
| HTML tag. |
| |
| Such a mistake can, for example, happen if writing Dart code with type arguments |
| outside of a code span, for example `The type List<int> is ...`, where `<int>` |
| looks like an HTML tag. Missing the end quote of a code span can have the same |
| effect: ``The type `List<int> is ...`` will also treat `<int>` as an HTML tag. |
| |
| Allows the following HTML directives: HTML comments, `<!-- text -->`, processing |
| instructions, `<?...?>`, CDATA-sections, and `<[CDATA...]>`. |
| Allows DartDoc links like `[List<int>]` which are not after a `]` or before a |
| `[` or `(`, and allows the following recognized HTML tags: |
| `a`, `abbr`, `address`, `area`, `article`, `aside`, `audio`, `b`, |
| `bdi`, `bdo`, `blockquote`, `br`, `button`, `canvas`, `caption`, |
| `cite`, `code`, `col`, `colgroup`, `data`, `datalist`, `dd`, `del`, |
| `dfn`, `div`, `dl`, `dt`, `em`, `fieldset`, `figcaption`, `figure`, |
| `footer`, `form`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `header`, `hr`, |
| `i`, `iframe`, `img`, `input`, `ins`, `kbd`, `keygen`, `label`, |
| `legend`, `li`, `link`, `main`, `map`, `mark`, `meta`, `meter`, `nav`, |
| `noscript`, `object`, `ol`, `optgroup`, `option`, `output`, `p`, |
| `param`, `pre`, `progress`, `q`, `s`, `samp`, `script`, `section`, |
| `select`, `small`, `source`, `span`, `strong`, `style`, `sub`, `sup`, |
| `table`, `tbody`, `td`, `template`, `textarea`, `tfoot`, `th`, `thead`, |
| `time`, `title`, `tr`, `track`, `u`, `ul`, `var`, `video` and `wbr`. |
| |
| **BAD:** |
| ```dart |
| /// The type List<int>. |
| /// <assignment> -> <variable> = <expression> |
| ``` |
| |
| **GOOD:** |
| ```dart |
| /// The type `List<int>`. |
| /// The type [List<int>] |
| /// `<assignment> -> <variable> = <expression>` |
| /// \<assignment\> -> \<variable\> = \<expression\>` |
| /// <https://example.com/example> |
| ``` |
| unnecessary_async: |
| problemMessage: "Don't make a function 'async' if it doesn't use 'await'." |
| correctionMessage: "Try removing the 'async' modifier." |
| state: |
| experimental: "3.7" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Functions that don't do `await` don't have to be `async`. |
| |
| Usually such functions also don't have to return a `Future`, which allows |
| an invoker to avoid `await` in its code, etc. Synchronous code in |
| general runs faster, and is easier to reason about. |
| |
| **BAD:** |
| ```dart |
| void f() async { |
| // await Future.delayed(const Duration(seconds: 2)); |
| print(0); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void f() { |
| // await Future.delayed(const Duration(seconds: 2)); |
| print(0); |
| } |
| ``` |
| unnecessary_await_in_return: |
| problemMessage: "Unnecessary 'await'." |
| correctionMessage: "Try removing the 'await'." |
| state: |
| stable: "2.1" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Avoid returning an awaited expression when the expression type is assignable to |
| the function's return type. |
| |
| |
| **BAD:** |
| ```dart |
| Future<int> future; |
| Future<int> f1() async => await future; |
| Future<int> f2() async { |
| return await future; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Future<int> future; |
| Future<int> f1() => future; |
| Future<int> f2() { |
| return future; |
| } |
| ``` |
| unnecessary_brace_in_string_interps: |
| problemMessage: "Unnecessary braces in a string interpolation." |
| correctionMessage: "Try removing the braces." |
| state: |
| stable: "2.0" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a string interpolation with |
| braces is used to interpolate a simple identifier and isn't followed by |
| alphanumeric text. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the interpolation |
| element `${s}` uses braces when they are not necessary: |
| |
| ```dart |
| String f(String s) { |
| return '"[!${s}!]"'; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Remove the unnecessary braces: |
| |
| ```dart |
| String f(String s) { |
| return '"$s"'; |
| } |
| ``` |
| deprecatedDetails: |- |
| **AVOID** using braces in interpolation when not needed. |
| |
| If you're just interpolating a simple identifier, and it's not immediately |
| followed by more alphanumeric text, the `{}` can and should be omitted. |
| |
| **BAD:** |
| ```dart |
| print("Hi, ${name}!"); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| print("Hi, $name!"); |
| ``` |
| unnecessary_breaks: |
| problemMessage: "Unnecessary 'break' statement." |
| correctionMessage: "Try removing the 'break'." |
| state: |
| stable: "3.0" |
| categories: [brevity, style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Only use a `break` in a non-empty switch case statement if you need to break |
| before the end of the case body. Dart does not support fallthrough execution |
| for non-empty cases, so `break`s at the end of non-empty switch case statements |
| are unnecessary. |
| |
| **BAD:** |
| ```dart |
| switch (1) { |
| case 1: |
| print("one"); |
| break; |
| case 2: |
| print("two"); |
| break; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| switch (1) { |
| case 1: |
| print("one"); |
| case 2: |
| print("two"); |
| } |
| ``` |
| |
| ```dart |
| switch (1) { |
| case 1: |
| case 2: |
| print("one or two"); |
| } |
| ``` |
| |
| ```dart |
| switch (1) { |
| case 1: |
| break; |
| case 2: |
| print("just two"); |
| } |
| ``` |
| |
| NOTE: This lint only reports unnecessary breaks in libraries with a |
| [language version](https://dart.dev/resources/language/evolution#language-versioning) |
| of 3.0 or greater. Explicit breaks are still required in Dart 2.19 and below. |
| unnecessary_const: |
| problemMessage: "Unnecessary 'const' keyword." |
| correctionMessage: "Try removing the keyword." |
| state: |
| stable: "2.0" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the keyword `const` is used in |
| a [constant context][]. The keyword isn't required because it's implied. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the keyword `const` in |
| the list literal isn't needed: |
| |
| ```dart |
| const l = [!const!] <int>[]; |
| ``` |
| |
| The list is implicitly `const` because of the keyword `const` on the |
| variable declaration. |
| |
| #### Common fixes |
| |
| Remove the unnecessary keyword: |
| |
| ```dart |
| const l = <int>[]; |
| ``` |
| deprecatedDetails: |- |
| **AVOID** repeating `const` keyword in a `const` context. |
| |
| **BAD:** |
| ```dart |
| class A { const A(); } |
| m(){ |
| const a = const A(); |
| final b = const [const A()]; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { const A(); } |
| m(){ |
| const a = A(); |
| final b = const [A()]; |
| } |
| ``` |
| unnecessary_constructor_name: |
| problemMessage: "Unnecessary '.new' constructor name." |
| correctionMessage: "Try removing the '.new'." |
| state: |
| stable: "2.15" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a reference to an unnamed |
| constructor uses `.new`. The only place where `.new` is required is in a |
| constructor tear-off. |
| |
| #### Example |
| |
| The following code produces this diagnostic because `.new` is being used |
| to refer to the unnamed constructor where it isn't required: |
| |
| ```dart |
| var o = Object.[!new!](); |
| ``` |
| |
| #### Common fixes |
| |
| Remove the unnecessary `.new`: |
| |
| ```dart |
| var o = Object(); |
| ``` |
| deprecatedDetails: |- |
| **PREFER** using the default unnamed Constructor over `.new`. |
| |
| Given a class `C`, the named unnamed constructor `C.new` refers to the same |
| constructor as the unnamed `C`. As such it adds nothing but visual noise to |
| invocations and should be avoided (unless being used to identify a constructor |
| tear-off). |
| |
| **BAD:** |
| ```dart |
| class A { |
| A.new(); // LINT |
| } |
| |
| var a = A.new(); // LINT |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| A.ok(); |
| } |
| |
| var a = A(); |
| var aa = A.ok(); |
| var makeA = A.new; |
| ``` |
| unnecessary_final_with_type: |
| sharedName: unnecessary_final |
| problemMessage: "Local variables should not be marked as 'final'." |
| correctionMessage: "Remove the 'final'." |
| state: |
| stable: "2.7" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a local variable is marked as |
| being `final`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the local variable `c` |
| is marked as being `final`: |
| |
| ```dart |
| void f(int a, int b) { |
| [!final!] c = a + b; |
| print(c); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the variable doesn't have a type annotation, then replace the `final` |
| with `var`: |
| |
| ```dart |
| void f(int a, int b) { |
| var c = a + b; |
| print(c); |
| } |
| ``` |
| |
| If the variable has a type annotation, then remove the `final` |
| modifier: |
| |
| ```dart |
| void f(int a, int b) { |
| int c = a + b; |
| print(c); |
| } |
| ``` |
| deprecatedDetails: |- |
| Use `var`, not `final`, when declaring local variables. |
| |
| Per [Effective Dart](https://dart.dev/effective-dart/usage#do-follow-a-consistent-rule-for-var-and-final-on-local-variables), |
| there are two styles in wide use. This rule enforces the `var` style. |
| For the alternative style that prefers `final`, enable `prefer_final_locals` |
| and `prefer_final_in_for_each` instead. |
| |
| For fields, `final` is always recommended; see the rule `prefer_final_fields`. |
| |
| **BAD:** |
| ```dart |
| void badMethod() { |
| final label = 'Final or var?'; |
| for (final char in ['v', 'a', 'r']) { |
| print(char); |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void goodMethod() { |
| var label = 'Final or var?'; |
| for (var char in ['v', 'a', 'r']) { |
| print(char); |
| } |
| } |
| ``` |
| unnecessary_final_without_type: |
| sharedName: unnecessary_final |
| problemMessage: "Local variables should not be marked as 'final'." |
| correctionMessage: "Replace 'final' with 'var'." |
| hasPublishedDocs: false |
| unnecessary_getters_setters: |
| problemMessage: "Unnecessary use of getter and setter to wrap a field." |
| correctionMessage: "Try removing the getter and setter and renaming the field." |
| state: |
| stable: "2.0" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a getter and setter pair |
| returns and sets the value of a field without any additional processing. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the getter/setter pair |
| named `c` only expose the field named `_c`: |
| |
| ```dart |
| class C { |
| int? _c; |
| |
| int? get [!c!] => _c; |
| |
| set c(int? v) => _c = v; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Make the field public and remove the getter and setter: |
| |
| ```dart |
| class C { |
| int? c; |
| } |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/usage#dont-wrap-a-field-in-a-getter-and-setter-unnecessarily): |
| |
| **AVOID** wrapping fields in getters and setters just to be "safe". |
| |
| In Java and C#, it's common to hide all fields behind getters and setters (or |
| properties in C#), even if the implementation just forwards to the field. That |
| way, if you ever need to do more work in those members, you can do it without needing |
| to touch the callsites. This is because calling a getter method is different |
| than accessing a field in Java, and accessing a property isn't binary-compatible |
| with accessing a raw field in C#. |
| |
| Dart doesn't have this limitation. Fields and getters/setters are completely |
| indistinguishable. You can expose a field in a class and later wrap it in a |
| getter and setter without having to touch any code that uses that field. |
| |
| **BAD:** |
| ```dart |
| class Box { |
| var _contents; |
| get contents => _contents; |
| set contents(value) { |
| _contents = value; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Box { |
| var contents; |
| } |
| ``` |
| unnecessary_ignore: |
| sharedName: unnecessary_ignore |
| problemMessage: "The diagnostic '{0}' isn't produced at this location so it doesn't need to be ignored." |
| correctionMessage: "Try removing the ignore comment." |
| state: |
| experimental: "3.8" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an ignore is specified to |
| ignore a diagnostic that isn't produced. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the |
| `unused_local_variable` diagnostic isn't reported at the ignored location: |
| |
| ```dart |
| // ignore: [!unused_local_variable!] |
| void f() {} |
| ``` |
| |
| #### Common fixes |
| |
| Remove the ignore comment: |
| |
| ```dart |
| void f() {} |
| ``` |
| deprecatedDetails: |- |
| **DON'T** specify an ignore for a diagnostic that is not produced. |
| unnecessary_ignore_file: |
| sharedName: unnecessary_ignore |
| problemMessage: "The diagnostic '{0}' isn't produced in this file so it doesn't need to be ignored." |
| correctionMessage: "Try removing the ignore comment." |
| hasPublishedDocs: false |
| unnecessary_ignore_name: |
| sharedName: unnecessary_ignore |
| problemMessage: "The diagnostic '{0}' isn't produced at this location so it doesn't need to be ignored." |
| correctionMessage: "Try removing the name from the list." |
| hasPublishedDocs: false |
| unnecessary_ignore_name_file: |
| sharedName: unnecessary_ignore |
| problemMessage: "The diagnostic '{0}' isn't produced in this file so it doesn't need to be ignored." |
| correctionMessage: "Try removing the name from the list." |
| hasPublishedDocs: false |
| unnecessary_lambdas: |
| problemMessage: "Closure should be a tearoff." |
| correctionMessage: "Try using a tearoff rather than a closure." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a closure (lambda) could be |
| replaced by a tear-off. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the closure passed to |
| `forEach` contains only an invocation of the function `print` with the |
| parameter of the closure: |
| |
| ```dart |
| void f(List<String> strings) { |
| strings.forEach([!(string) { |
| print(string); |
| }!]); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Replace the closure with a tear-off of the function or method being |
| invoked with the closure: |
| |
| ```dart |
| void f(List<String> strings) { |
| strings.forEach(print); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** create a lambda when a tear-off will do. |
| |
| **BAD:** |
| ```dart |
| names.forEach((name) { |
| print(name); |
| }); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| names.forEach(print); |
| ``` |
| unnecessary_late: |
| problemMessage: "Unnecessary 'late' modifier." |
| correctionMessage: "Try removing the 'late'." |
| state: |
| stable: "2.16" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a top-level variable or static |
| field with an initializer is marked as `late`. Top-level variables and |
| static fields are implicitly late, so they don't need to be explicitly |
| marked. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the static field `c` |
| has the modifier `late` even though it has an initializer: |
| |
| ```dart |
| class C { |
| static [!late!] String c = ''; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Remove the keyword `late`: |
| |
| ```dart |
| class C { |
| static String c = ''; |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** not specify the `late` modifier for top-level and static variables |
| when the declaration contains an initializer. |
| |
| Top-level and static variables with initializers are already evaluated lazily |
| as if they are marked `late`. |
| |
| **BAD:** |
| ```dart |
| late String badTopLevel = ''; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| String goodTopLevel = ''; |
| ``` |
| |
| **BAD:** |
| ```dart |
| class BadExample { |
| static late String badStatic = ''; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class GoodExample { |
| late String goodStatic; |
| } |
| ``` |
| unnecessary_library_directive: |
| problemMessage: "Library directives without comments or annotations should be avoided." |
| correctionMessage: "Try deleting the library directive." |
| state: |
| stable: "2.19" |
| categories: [brevity] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **DO** use library directives if you want to document a library and/or annotate |
| a library. |
| |
| **BAD:** |
| ```dart |
| library; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| /// This library does important things |
| library; |
| ``` |
| |
| ```dart |
| @TestOn('js') |
| library; |
| ``` |
| |
| NOTE: Due to limitations with this lint, libraries with parts will not be |
| flagged for unnecessary library directives. |
| unnecessary_library_name: |
| problemMessage: "Library names are not necessary." |
| correctionMessage: "Remove the library name." |
| state: |
| stable: "3.4" |
| categories: [brevity, languageFeatureUsage, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `library` directive specifies |
| a name. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the `library` |
| directive includes a name: |
| |
| ```dart |
| library [!some.name!]; |
| |
| class C {} |
| ``` |
| |
| #### Common fixes |
| |
| Remove the name from the `library` directive: |
| |
| ```dart |
| library; |
| |
| class C {} |
| ``` |
| |
| If the library has any parts, then any `part of` declarations that use |
| the library name should be updated to use the URI of the library instead. |
| deprecatedDetails: |- |
| **DON'T** have a library name in a `library` declaration. |
| |
| Library names are not necessary. |
| |
| A library does not need a library declaration, but one can be added to attach |
| library documentation and library metadata to. A declaration of `library;` is |
| sufficient for those uses. |
| |
| The only *use* of a library name is for a `part` file to refer back to its |
| owning library, but part files should prefer to use a string URI to refer back |
| to the library file, not a library name. |
| |
| If a library name is added to a library declaration, it introduces the risk of |
| name *conflicts*. It's a compile-time error if two libraries in the same program |
| have the same library name. To avoid that, library names tend to be long, |
| including the package name and path, just to avoid accidental name clashes. That |
| makes such library names hard to read, and not even useful as documentation. |
| |
| **BAD:** |
| ```dart |
| /// This library has a long name. |
| library magnificator.src.helper.bananas; |
| ``` |
| |
| ```dart |
| library utils; // Not as verbose, but risks conflicts. |
| ``` |
| |
| **GOOD:** |
| ```dart |
| /// This library is awesome. |
| library; |
| |
| part "apart.dart"; // contains: `part of "good_library.dart";` |
| ``` |
| unnecessary_new: |
| problemMessage: "Unnecessary 'new' keyword." |
| correctionMessage: "Try removing the 'new' keyword." |
| state: |
| stable: "2.0" |
| categories: [brevity, languageFeatureUsage, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the keyword `new` is used to |
| invoke a constructor. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the keyword `new` is |
| used to invoke the unnamed constructor from `Object`: |
| |
| ```dart |
| var o = [!new!] Object(); |
| ``` |
| |
| #### Common fixes |
| |
| Remove the keyword `new`: |
| |
| ```dart |
| var o = Object(); |
| ``` |
| deprecatedDetails: |- |
| **AVOID** new keyword to create instances. |
| |
| **BAD:** |
| ```dart |
| class A { A(); } |
| m(){ |
| final a = new A(); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { A(); } |
| m(){ |
| final a = A(); |
| } |
| ``` |
| unnecessary_null_aware_assignments: |
| problemMessage: "Unnecessary assignment of 'null'." |
| correctionMessage: "Try removing the assignment." |
| state: |
| stable: "2.0" |
| categories: [brevity, effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the right-hand side of a |
| null-aware assignment is the `null` literal. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the null aware |
| operator is being used to assign `null` to `s` when `s` is already `null`: |
| |
| ```dart |
| void f(String? s) { |
| [!s ??= null!]; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If a non-null value should be assigned to the left-hand operand, then |
| change the right-hand side: |
| |
| ```dart |
| void f(String? s) { |
| s ??= ''; |
| } |
| ``` |
| |
| If there is no non-null value to assign to the left-hand operand, then |
| remove the assignment: |
| |
| ```dart |
| void f(String? s) { |
| } |
| ``` |
| deprecatedDetails: |- |
| **AVOID** `null` in `null`-aware assignment. |
| |
| Using `null` on the right-hand side of a `null`-aware assignment effectively |
| makes the assignment redundant. |
| |
| **BAD:** |
| ```dart |
| var x; |
| x ??= null; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var x; |
| x ??= 1; |
| ``` |
| unnecessary_null_aware_operator_on_extension_on_nullable: |
| problemMessage: "Unnecessary use of a null-aware operator to invoke an extension method on a nullable type." |
| correctionMessage: "Try removing the '?'." |
| state: |
| stable: "2.18" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a null-aware operator is used |
| to invoke an extension method on an extension whose type is nullable. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the extension method |
| `m` is invoked using `?.` when it doesn't need to be: |
| |
| ```dart |
| extension E on int? { |
| int m() => 1; |
| } |
| |
| int? f(int? i) => i[!?.!]m(); |
| ``` |
| |
| #### Common fixes |
| |
| If it isn't a requirement not invoke the method when the receiver is |
| `null`, then remove the question mark from the invocation: |
| |
| ```dart |
| extension E on int? { |
| int m() => 1; |
| } |
| |
| int? f(int? i) => i.m(); |
| ``` |
| deprecatedDetails: |- |
| Avoid null aware operators for members defined in an extension on a nullable |
| type. |
| |
| **BAD:** |
| |
| ```dart |
| extension E on int? { |
| int m() => 1; |
| } |
| f(int? i) => i?.m(); |
| ``` |
| |
| **GOOD:** |
| |
| ```dart |
| extension E on int? { |
| int m() => 1; |
| } |
| f(int? i) => i.m(); |
| ``` |
| unnecessary_null_checks: |
| problemMessage: "Unnecessary use of a null check ('!')." |
| correctionMessage: "Try removing the null check." |
| state: |
| experimental: "2.12" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a null check operator (`!`) is |
| used in a context where a nullable value is acceptable. |
| |
| #### Example |
| |
| The following code produces this diagnostic because a null check is being |
| used even though `null` is a valid value to return: |
| |
| ```dart |
| int? f(int? i) { |
| return i[!!!]; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Remove the null check operator: |
| |
| ```dart |
| int? f(int? i) { |
| return i; |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** apply a `null` check where a nullable value is accepted. |
| |
| **BAD:** |
| ```dart |
| f(int? i) {} |
| m() { |
| int? j; |
| f(j!); |
| } |
| |
| ``` |
| |
| **GOOD:** |
| ```dart |
| f(int? i) {} |
| m() { |
| int? j; |
| f(j); |
| } |
| ``` |
| unnecessary_null_in_if_null_operators: |
| problemMessage: "Unnecessary use of '??' with 'null'." |
| correctionMessage: "Try removing the '??' operator and the 'null' operand." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the right operand of the `??` |
| operator is the literal `null`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the right-hand operand |
| of the `??` operator is `null`: |
| |
| ```dart |
| String? f(String? s) => s ?? [!null!]; |
| ``` |
| |
| #### Common fixes |
| |
| If a non-null value should be used for the right-hand operand, then |
| change the right-hand side: |
| |
| ```dart |
| String f(String? s) => s ?? ''; |
| ``` |
| |
| If there is no non-null value to use for the right-hand operand, then |
| remove the operator and the right-hand operand: |
| |
| ```dart |
| String? f(String? s) => s; |
| ``` |
| deprecatedDetails: |- |
| **AVOID** using `null` as an operand in `??` operators. |
| |
| Using `null` in an `if null` operator is redundant, regardless of which side |
| `null` is used on. |
| |
| **BAD:** |
| ```dart |
| var x = a ?? null; |
| var y = null ?? 1; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var x = a ?? 1; |
| ``` |
| unnecessary_nullable_for_final_variable_declarations: |
| problemMessage: "Type could be non-nullable." |
| correctionMessage: "Try changing the type to be non-nullable." |
| state: |
| stable: "2.10" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a final field or variable has a |
| nullable type but is initialized to a non-nullable value. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the final variable `i` |
| has a nullable type (`int?`), but can never be `null`: |
| |
| ```dart |
| final int? [!i!] = 1; |
| ``` |
| |
| #### Common fixes |
| |
| Make the type non-nullable: |
| |
| ```dart |
| final int i = 1; |
| ``` |
| deprecatedDetails: |- |
| Use a non-nullable type for a final variable initialized with a non-nullable |
| value. |
| |
| **BAD:** |
| ```dart |
| final int? i = 1; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| final int i = 1; |
| ``` |
| unnecessary_overrides: |
| problemMessage: "Unnecessary override." |
| correctionMessage: "Try adding behavior in the overriding member or removing the override." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an instance member overrides an |
| inherited member but only invokes the overridden member with exactly the |
| same arguments. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the method `D.m` |
| doesn't do anything other than invoke the overridden method: |
| |
| ```dart |
| class C { |
| int m(int x) => x; |
| } |
| |
| class D extends C { |
| @override |
| int [!m!](int x) => super.m(x); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the method should do something more than what the overridden method |
| does, then implement the missing functionality: |
| |
| ```dart |
| class C { |
| int m(int x) => x; |
| } |
| |
| class D extends C { |
| @override |
| int m(int x) => super.m(x) + 1; |
| } |
| ``` |
| |
| If the overridden method should be modified by changing the return type or |
| one or more of the parameter types, making one of the parameters |
| `covariant`, having a documentation comment, or by having additional |
| annotations, then update the code: |
| |
| ```dart |
| import 'package:meta/meta.dart'; |
| |
| class C { |
| int m(int x) => x; |
| } |
| |
| class D extends C { |
| @mustCallSuper |
| @override |
| int m(int x) => super.m(x); |
| } |
| ``` |
| |
| If the overriding method doesn't change or enhance the semantics of the |
| code, then remove it: |
| |
| ```dart |
| class C { |
| int m(int x) => x; |
| } |
| |
| class D extends C {} |
| ``` |
| deprecatedDetails: |- |
| **DON'T** override a method to do a super method invocation with same parameters. |
| |
| **BAD:** |
| ```dart |
| class A extends B { |
| @override |
| void foo() { |
| super.foo(); |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A extends B { |
| @override |
| void foo() { |
| doSomethingElse(); |
| } |
| } |
| ``` |
| |
| It's valid to override a member in the following cases: |
| |
| * if a type (return type or a parameter type) is not the exactly the same as the |
| super member, |
| * if the `covariant` keyword is added to one of the parameters, |
| * if documentation comments are present on the member, |
| * if the member has annotations other than `@override`, |
| * if the member is not annotated with `@protected`, and the super member is. |
| |
| `noSuchMethod` is a special method and is not checked by this rule. |
| unnecessary_parenthesis: |
| problemMessage: "Unnecessary use of parentheses." |
| correctionMessage: "Try removing the parentheses." |
| state: |
| stable: "2.0" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when parentheses are used where they |
| do not affect the semantics of the code. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the parentheses around |
| the binary expression are not necessary: |
| |
| ```dart |
| int f(int a, int b) => [!(a + b)!]; |
| ``` |
| |
| #### Common fixes |
| |
| Remove the unnecessary parentheses: |
| |
| ```dart |
| int f(int a, int b) => a + b; |
| ``` |
| deprecatedDetails: |- |
| **AVOID** using parentheses when not needed. |
| |
| **BAD:** |
| ```dart |
| a = (b); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| a = b; |
| ``` |
| |
| Parentheses are considered unnecessary if they do not change the meaning of the |
| code and they do not improve the readability of the code. The goal is not to |
| force all developers to maintain the expression precedence table in their heads, |
| which is why the second condition is included. Examples of this condition |
| include: |
| |
| * cascade expressions - it is sometimes not clear what the target of a cascade |
| expression is, especially with assignments, or nested cascades. For example, |
| the expression `a.b = (c..d)`. |
| * expressions with whitespace between tokens - it can look very strange to see |
| an expression like `!await foo` which is valid and equivalent to |
| `!(await foo)`. |
| * logical expressions - parentheses can improve the readability of the implicit |
| grouping defined by precedence. For example, the expression |
| `(a && b) || c && d`. |
| unnecessary_raw_strings: |
| problemMessage: "Unnecessary use of a raw string." |
| correctionMessage: "Try using a normal string." |
| state: |
| stable: "2.8" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a string literal is marked as |
| being raw (is prefixed with an `r`), but making the string raw doesn't |
| change the value of the string. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the string literal |
| will have the same value without the `r` as it does with the `r`: |
| |
| ```dart |
| var s = [!r'abc'!]; |
| ``` |
| |
| #### Common fixes |
| |
| Remove the `r` in front of the string literal: |
| |
| ```dart |
| var s = 'abc'; |
| ``` |
| deprecatedDetails: |- |
| Use raw string only when needed. |
| |
| **BAD:** |
| ```dart |
| var s1 = r'a'; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var s1 = 'a'; |
| var s2 = r'$a'; |
| var s3 = r'\a'; |
| ``` |
| unnecessary_statements: |
| problemMessage: "Unnecessary statement." |
| correctionMessage: "Try completing the statement or breaking it up." |
| state: |
| stable: "2.0" |
| categories: [brevity, unintentional] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an expression statement has no |
| clear effect. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the addition of the |
| returned values from the two invocations has no clear effect: |
| |
| ```dart |
| void f(int Function() first, int Function() second) { |
| [!first() + second()!]; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the expression doesn't need to be computed, then remove it: |
| |
| ```dart |
| void f(int Function() first, int Function() second) { |
| } |
| ``` |
| |
| If the value of the expression is needed, then make use of it, possibly |
| assigning it to a local variable first: |
| |
| ```dart |
| void f(int Function() first, int Function() second) { |
| print(first() + second()); |
| } |
| ``` |
| |
| If portions of the expression need to be executed, then remove the |
| unnecessary portions: |
| |
| ```dart |
| void f(int Function() first, int Function() second) { |
| first(); |
| second(); |
| } |
| ``` |
| deprecatedDetails: |- |
| **AVOID** using unnecessary statements. |
| |
| Statements which have no clear effect are usually unnecessary, or should be |
| broken up. |
| |
| For example, |
| |
| **BAD:** |
| ```dart |
| myvar; |
| list.clear; |
| 1 + 2; |
| methodOne() + methodTwo(); |
| foo ? bar : baz; |
| ``` |
| |
| Though the added methods have a clear effect, the addition itself does not |
| unless there is some magical overload of the + operator. |
| |
| Usually code like this indicates an incomplete thought, and is a bug. |
| |
| **GOOD:** |
| ```dart |
| some.method(); |
| const SomeClass(); |
| methodOne(); |
| methodTwo(); |
| foo ? bar() : baz(); |
| return myvar; |
| ``` |
| unnecessary_string_escapes: |
| problemMessage: "Unnecessary escape in string literal." |
| correctionMessage: "Remove the '\\' escape." |
| state: |
| stable: "2.8" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when characters in a string are |
| escaped when escaping them is unnecessary. |
| |
| #### Example |
| |
| The following code produces this diagnostic because single quotes don't |
| need to be escaped inside strings delimited by double quotes: |
| |
| ```dart |
| var s = "Don[!\!]'t use a backslash here."; |
| ``` |
| |
| #### Common fixes |
| |
| Remove the unnecessary backslashes: |
| |
| ```dart |
| var s = "Don't use a backslash here."; |
| ``` |
| deprecatedDetails: |- |
| Remove unnecessary backslashes in strings. |
| |
| **BAD:** |
| ```dart |
| 'this string contains 2 \"double quotes\" '; |
| "this string contains 2 \'single quotes\' "; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| 'this string contains 2 "double quotes" '; |
| "this string contains 2 'single quotes' "; |
| ``` |
| unnecessary_string_interpolations: |
| problemMessage: "Unnecessary use of string interpolation." |
| correctionMessage: "Try replacing the string literal with the variable name." |
| state: |
| stable: "2.8" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a string literal contains a |
| single interpolation of a `String`-valued variable and no other |
| characters. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the string literal |
| contains a single interpolation and doesn't contain any character outside |
| the interpolation: |
| |
| ```dart |
| String f(String s) => [!'$s'!]; |
| ``` |
| |
| #### Common fixes |
| |
| Replace the string literal with the content of the interpolation: |
| |
| ```dart |
| String f(String s) => s; |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use string interpolation if there's only a string expression in it. |
| |
| **BAD:** |
| ```dart |
| String message; |
| String o = '$message'; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| String message; |
| String o = message; |
| ``` |
| unnecessary_this: |
| problemMessage: "Unnecessary 'this.' qualifier." |
| correctionMessage: "Try removing 'this.'." |
| state: |
| stable: "2.0" |
| categories: [brevity, effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the keyword `this` is used to |
| access a member that isn't shadowed. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the use of `this` to |
| access the field `_f` isn't necessary: |
| |
| ```dart |
| class C { |
| int _f = 2; |
| |
| int get f => [!this!]._f; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Remove the `this.`: |
| |
| ```dart |
| class C { |
| int _f = 2; |
| |
| int get f => _f; |
| } |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-this-when-not-needed-to-avoid-shadowing): |
| |
| **DON'T** use `this` when not needed to avoid shadowing. |
| |
| **BAD:** |
| ```dart |
| class Box { |
| int value; |
| void update(int newValue) { |
| this.value = newValue; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Box { |
| int value; |
| void update(int newValue) { |
| value = newValue; |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Box { |
| int value; |
| void update(int value) { |
| this.value = value; |
| } |
| } |
| ``` |
| unnecessary_to_list_in_spreads: |
| problemMessage: "Unnecessary use of 'toList' in a spread." |
| correctionMessage: "Try removing the invocation of 'toList'." |
| state: |
| stable: "2.18" |
| categories: [brevity] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when `toList` is used to convert an |
| `Iterable` to a `List` just before a spread operator is applied to the |
| list. The spread operator can be applied to any `Iterable`, so the |
| conversion isn't necessary. |
| |
| #### Example |
| |
| The following code produces this diagnostic because `toList` is invoked on |
| the result of `map`, which is an `Iterable` that the spread operator could |
| be applied to directly: |
| |
| ```dart |
| List<String> toLowercase(List<String> strings) { |
| return [ |
| ...strings.map((String s) => s.toLowerCase()).[!toList!](), |
| ]; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Remove the invocation of `toList`: |
| |
| ```dart |
| List<String> toLowercase(List<String> strings) { |
| return [ |
| ...strings.map((String s) => s.toLowerCase()), |
| ]; |
| } |
| ``` |
| deprecatedDetails: |- |
| Unnecessary `toList()` in spreads. |
| |
| **BAD:** |
| ```dart |
| children: <Widget>[ |
| ...['foo', 'bar', 'baz'].map((String s) => Text(s)).toList(), |
| ] |
| ``` |
| |
| **GOOD:** |
| ```dart |
| children: <Widget>[ |
| ...['foo', 'bar', 'baz'].map((String s) => Text(s)), |
| ] |
| ``` |
| unnecessary_unawaited: |
| problemMessage: "Unnecessary use of 'unawaited'." |
| correctionMessage: "Try removing the use of 'unawaited', as the unawaited element is annotated with '@awaitNotRequired'." |
| state: |
| stable: "3.9" |
| categories: [brevity, unintentional, unusedCode] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when `unawaited` is used to mark a |
| call to a function, method, or operator, or a reference to a field, |
| getter, or top-level variable as safely not being awaited, but the called |
| member is also annotated with `@awaitNotRequired`. This annotation itself |
| signals that wrapping with `unawaited` is unnecessary at any call site. |
| |
| #### Example |
| |
| The following code produces this diagnostic because `unawaited` is invoked |
| on a call to a function that's annotated with `@awaitNotRequired`: |
| |
| ```dart |
| import 'dart:async'; |
| import 'package:meta/meta.dart'; |
| |
| @awaitNotRequired |
| Future<bool> log(String message) async => true; |
| |
| void f() { |
| [!unawaited!](log('Message.')); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Remove the invocation of `unawaited`: |
| |
| ```dart |
| import 'package:meta/meta.dart'; |
| |
| @awaitNotRequired |
| Future<bool> log(String message) async => true; |
| |
| void f() { |
| log('Message.'); |
| } |
| ``` |
| deprecatedDetails: |- |
| A call to a function, method, or operator, or a reference to a field, |
| getter, or top-level variable which is annotated with `@awaitNotRequired` |
| does not need to be wrapped in a call to `unawaited()`. |
| |
| **BAD:** |
| ```dart |
| @awaitNotRequired |
| Future<LogMessage> log(String message) { ... } |
| |
| void f() { |
| unawaited(log('Message.')); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| @awaitNotRequired |
| Future<LogMessage> log(String message) { ... } |
| |
| void f() { |
| log('Message.'); |
| } |
| ``` |
| unnecessary_underscores: |
| problemMessage: "Unnecessary use of multiple underscores." |
| correctionMessage: "Try using '_'." |
| state: |
| experimental: "3.7" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an unused variable is named |
| with multiple underscores (for example `__`). A single `_` wildcard variable |
| can be used instead. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the `__` parameter is unused: |
| |
| ```dart |
| void function(int [!__!]) { } |
| ``` |
| |
| #### Common fixes |
| |
| Replace the name with a single underscore: |
| |
| ```dart |
| void function(int _) { } |
| ``` |
| deprecatedDetails: |- |
| **AVOID** using multiple underscores when a single wildcard will do. |
| |
| **BAD:** |
| ```dart |
| void function(int __) { } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void function(int _) { } |
| ``` |
| |
| |
| unreachable_from_main: |
| problemMessage: "Unreachable member '{0}' in an executable library." |
| correctionMessage: "Try referencing the member or removing it." |
| state: |
| stable: "2.19" |
| categories: [unusedCode] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Any member declared in an executable library should be used directly inside that |
| library. An executable library is a library that contains a `main` top-level |
| function or that contains a top-level function annotated with |
| `@pragma('vm:entry-point')`). Executable libraries are not usually imported |
| and it's better to avoid defining unused members. |
| |
| This rule assumes that an executable library isn't imported by other libraries |
| except to execute its `main` function. |
| |
| **BAD:** |
| |
| ```dart |
| main() {} |
| void f() {} |
| ``` |
| |
| **GOOD:** |
| |
| ```dart |
| main() { |
| f(); |
| } |
| void f() {} |
| ``` |
| unrelated_type_equality_checks_in_expression: |
| sharedName: unrelated_type_equality_checks |
| problemMessage: "The type of the right operand ('{0}') isn't a subtype or a supertype of the left operand ('{1}')." |
| correctionMessage: "Try changing one or both of the operands." |
| state: |
| stable: "2.0" |
| categories: [unintentional] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when two objects are being compared |
| and neither of the static types of the two objects is a subtype of the |
| other. |
| |
| Such a comparison will usually return `false` and might not reflect the |
| programmer's intent. |
| |
| There can be false positives. For example, a class named `Point` might |
| have subclasses named `CartesianPoint` and `PolarPoint`, neither of which |
| is a subtype of the other, but it might still be appropriate to test the |
| equality of instances. |
| |
| As a concrete case, the classes `Int64` and `Int32` from `package:fixnum` |
| allow comparing instances to an `int` provided the `int` is on the |
| right-hand side. This case is specifically allowed by the diagnostic, but |
| other such cases are not. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the string `s` is |
| being compared to the integer `1`: |
| |
| ```dart |
| bool f(String s) { |
| return s [!==!] 1; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Replace one of the operands with something compatible with the other |
| operand: |
| |
| ```dart |
| bool f(String s) { |
| return s.length == 1; |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** Compare references of unrelated types for equality. |
| |
| Comparing references of a type where neither is a subtype of the other most |
| likely will return `false` and might not reflect programmer's intent. |
| |
| `Int64` and `Int32` from `package:fixnum` allow comparing to `int` provided |
| the `int` is on the right hand side. The lint allows this as a special case. |
| |
| **BAD:** |
| ```dart |
| void someFunction() { |
| var x = '1'; |
| if (x == 1) print('someFunction'); // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void someFunction1() { |
| String x = '1'; |
| if (x == 1) print('someFunction1'); // LINT |
| } |
| ``` |
| |
| **BAD:** |
| ```dart |
| void someFunction13(DerivedClass2 instance) { |
| var other = DerivedClass3(); |
| |
| if (other == instance) print('someFunction13'); // LINT |
| } |
| |
| class ClassBase {} |
| |
| class DerivedClass1 extends ClassBase {} |
| |
| abstract class Mixin {} |
| |
| class DerivedClass2 extends ClassBase with Mixin {} |
| |
| class DerivedClass3 extends ClassBase implements Mixin {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction2() { |
| var x = '1'; |
| var y = '2'; |
| if (x == y) print(someFunction2); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction3() { |
| for (var i = 0; i < 10; i++) { |
| if (i == 0) print(someFunction3); // OK |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction4() { |
| var x = '1'; |
| if (x == null) print(someFunction4); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction7() { |
| List someList; |
| |
| if (someList.length == 0) print('someFunction7'); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction8(ClassBase instance) { |
| DerivedClass1 other; |
| |
| if (other == instance) print('someFunction8'); // OK |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction10(unknown) { |
| var what = unknown - 1; |
| for (var index = 0; index < unknown; index++) { |
| if (what == index) print('someFunction10'); // OK |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void someFunction11(Mixin instance) { |
| var other = DerivedClass2(); |
| |
| if (other == instance) print('someFunction11'); // OK |
| if (other != instance) print('!someFunction11'); // OK |
| } |
| |
| class ClassBase {} |
| |
| abstract class Mixin {} |
| |
| class DerivedClass2 extends ClassBase with Mixin {} |
| ``` |
| unrelated_type_equality_checks_in_pattern: |
| sharedName: unrelated_type_equality_checks |
| problemMessage: "The type of the operand ('{0}') isn't a subtype or a supertype of the value being matched ('{1}')." |
| correctionMessage: "Try changing one or both of the operands." |
| hasPublishedDocs: true |
| unsafe_html_attribute: |
| sharedName: unsafe_html |
| problemMessage: "Assigning to the attribute '{0}' is unsafe." |
| correctionMessage: "Try finding a different way to implement the page." |
| state: |
| stable: "2.4" |
| removed: "3.7" |
| categories: [errorProne] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **NOTE:** This lint is deprecated and will be removed in a future release. |
| Remove all inclusions of this lint from your analysis options. |
| |
| **AVOID** |
| |
| * assigning directly to the `href` field of an AnchorElement |
| * assigning directly to the `src` field of an EmbedElement, IFrameElement, or |
| ScriptElement |
| * assigning directly to the `srcdoc` field of an IFrameElement |
| * calling the `createFragment` method of Element |
| * calling the `open` method of Window |
| * calling the `setInnerHtml` method of Element |
| * calling the `Element.html` constructor |
| * calling the `DocumentFragment.html` constructor |
| |
| |
| **BAD:** |
| ```dart |
| var script = ScriptElement()..src = 'foo.js'; |
| ``` |
| |
| This rule has been removed. |
| unsafe_html_constructor: |
| sharedName: unsafe_html |
| problemMessage: "Invoking the constructor '{0}' is unsafe." |
| correctionMessage: "Try finding a different way to implement the page." |
| hasPublishedDocs: false |
| unsafe_html_method: |
| sharedName: unsafe_html |
| problemMessage: "Invoking the method '{0}' is unsafe." |
| correctionMessage: "Try finding a different way to implement the page." |
| hasPublishedDocs: false |
| unsafe_variance: |
| problemMessage: "This type is unsafe: a type parameter occurs in a non-covariant position." |
| correctionMessage: "Try using a more general type that doesn't contain any type parameters in such a position." |
| state: |
| experimental: "3.7" |
| categories: [errorProne] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when an instance member has a result |
| type which is [contravariant or invariant](https://dart.dev/resources/glossary#variance) |
| in a type parameter of the enclosing declaration. The result type of a |
| variable is its type, and the result type of a getter or method is its |
| return type. This lint warns against such members because they are likely |
| to cause a failing type check at run time, with no static warning or error |
| at the call site. |
| |
| #### Example |
| |
| The following code produces this diagnostic because `X` occurs |
| as a parameter type in the type of `f`, which is a |
| contravariant occurrence of this type parameter: |
| |
| ```dart |
| class C<X> { |
| bool Function([!X!]) f; |
| C(this.f); |
| } |
| ``` |
| |
| This is unsafe: If `c` has static type `C<num>` and run-time type `C<int>` |
| then `c.f` will throw. Hence, every invocation `c.f(a)` will also throw, |
| even in the case where `a` has a correct type as an argument to `c.f`. |
| |
| #### Common fixes |
| |
| If the linted member is or can be private then you may be able |
| to enforce that it is never accessed on any other receiver than `this`. |
| This is sufficient to ensure that that the run-time type error does not |
| occur. For example: |
| |
| ```dart |
| class C<X> { |
| // NB: Ensure manually that `_f` is only accessed on `this`. |
| // ignore: unsafe_variance |
| bool Function(X) _f; |
| |
| C(this._f); |
| |
| // We can write a forwarding method to allow clients to call `_f`. |
| bool f(X x) => _f(x); |
| } |
| ``` |
| |
| You can eliminate the unsafe variance by using a more general type for |
| the linted member. In this case you may need to check the run-time type |
| and perform a downcast at call sites. |
| |
| ```dart |
| class C<X> { |
| bool Function(Never) f; |
| C(this.f); |
| } |
| ``` |
| |
| If `c` has static type `C<num>` then you may test the type. For example, |
| `c.f is bool Function(num)`. You may safely call it with an argument of |
| type `num` if it has that type. |
| |
| You can also eliminate the unsafe variance by using a much more general |
| type like `Function`, which is essentially the type `dynamic` for |
| functions. |
| |
| ```dart |
| class C<X> { |
| Function f; |
| C(this.f); |
| } |
| ``` |
| |
| This will make `c.f(a)` dynamically safe: It will throw if and only if the |
| argument `a` does not have the type required by the function. This is |
| better than the original version because it will not throw because of a |
| mismatched static type. It only throws when it _must_ throw for soundness |
| reasons. |
| deprecatedDetails: |- |
| An instance variable whose type contains a type parameter of the |
| enclosing class, mixin, or enum in a non-covariant position is |
| likely to cause run-time failures due to failing type |
| checks. For example, in `class C<X> {...}`, an instance variable |
| of the form `void Function(X) myVariable;` may cause this kind |
| of run-time failure. |
| |
| The same is true for a getter or method whose return type has a |
| non-covariant occurrence of a type parameter of the enclosing |
| declaration. |
| |
| This lint flags this kind of member declaration. |
| |
| **BAD:** |
| ```dart |
| class C<X> { |
| final bool Function([!X!]) fun; // LINT |
| C(this.fun); |
| } |
| |
| void main() { |
| C<num> c = C<int>((i) => i.isEven); |
| c.fun(10); // Throws. |
| } |
| ``` |
| |
| The problem is that `X` occurs as a parameter type in the type |
| of `fun`. |
| |
| One way to reduce the potential for run-time type errors is to |
| ensure that the non-covariant member `fun` is _only_ used on |
| `this`. We cannot strictly enforce this, but we can make it |
| private and add a forwarding method `fun` such that we can check |
| locally in the same library that this constraint is satisfied: |
| |
| **BETTER:** |
| ```dart |
| class C<X> { |
| // ignore: unsafe_variance |
| final bool Function(X) _fun; |
| bool fun(X x) => _fun(x); |
| C(this._fun); |
| } |
| |
| void main() { |
| C<num> c = C<int>((i) => i.isEven); |
| c.fun(10); // Succeeds. |
| } |
| ``` |
| |
| A fully safe approach requires a feature that Dart does not yet |
| have, namely statically checked variance. With that, we could |
| specify that the type parameter `X` is invariant (`inout X`). |
| |
| It is possible to emulate invariance without support for statically |
| checked variance. This puts some restrictions on the creation of |
| subtypes, but faithfully provides the typing that `inout` would |
| give: |
| |
| **GOOD:** |
| ```dart |
| typedef Inv<X> = X Function(X); |
| typedef C<X> = _C<X, Inv<X>>; |
| |
| class _C<X, Invariance extends Inv<X>> { |
| // ignore: unsafe_variance |
| final bool Function(X) fun; // Safe! |
| _C(this.fun); |
| } |
| |
| void main() { |
| C<int> c = C<int>((i) => i.isEven); |
| c.fun(10); // Succeeds. |
| } |
| ``` |
| |
| With this approach, `C<int>` is not a subtype of `C<num>`, so |
| `c` must have a different declared type. |
| |
| Another possibility is to declare the variable to have a safe |
| but more general type. It is then safe to use the variable |
| itself, but every invocation will have to be checked at run |
| time: |
| |
| **HONEST:** |
| ```dart |
| class C<X> { |
| final bool Function(Never) fun; |
| C(this.fun); |
| } |
| |
| void main() { |
| C<num> c = C<int>((int i) => i.isEven); |
| var cfun = c.fun; // Local variable, enables promotion. |
| if (cfun is bool Function(int)) cfun(10); // Succeeds. |
| if (cfun is bool Function(bool)) cfun(true); // Not called. |
| } |
| ``` |
| use_build_context_synchronously_async_use: |
| sharedName: use_build_context_synchronously |
| problemMessage: "Don't use 'BuildContext's across async gaps." |
| correctionMessage: "Try rewriting the code to not use the 'BuildContext', or guard the use with a 'mounted' check." |
| state: |
| experimental: "2.13" |
| stable: "3.2" |
| categories: [errorProne, flutter] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `BuildContext` is referenced |
| by a `StatefulWidget` after an asynchronous gap without first checking the |
| `mounted` property. |
| |
| Storing a `BuildContext` for later use can lead to difficult-to-diagnose |
| crashes. Asynchronous gaps implicitly store a `BuildContext`, making them |
| easy to overlook for diagnosis. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the `context` is |
| passed to a constructor after the `await`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| class MyWidget extends Widget { |
| void onButtonTapped(BuildContext context) async { |
| await Future.delayed(const Duration(seconds: 1)); |
| Navigator.of([!context!]).pop(); |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If you can remove the asynchronous gap, do so: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| class MyWidget extends Widget { |
| void onButtonTapped(BuildContext context) { |
| Navigator.of(context).pop(); |
| } |
| } |
| ``` |
| |
| If you can't remove the asynchronous gap, then use `mounted` to guard the |
| use of the `context`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| class MyWidget extends Widget { |
| void onButtonTapped(BuildContext context) async { |
| await Future.delayed(const Duration(seconds: 1)); |
| if (context.mounted) { |
| Navigator.of(context).pop(); |
| } |
| } |
| } |
| ``` |
| deprecatedDetails: |- |
| **DON'T** use `BuildContext` across asynchronous gaps. |
| |
| Storing `BuildContext` for later usage can easily lead to difficult-to-diagnose |
| crashes. Asynchronous gaps are implicitly storing `BuildContext` and are some of |
| the easiest to overlook when writing code. |
| |
| When a `BuildContext` is used, a `mounted` property must be checked after an |
| asynchronous gap, depending on how the `BuildContext` is accessed: |
| |
| * When using a `State`'s `context` property, the `State`'s `mounted` property |
| must be checked. |
| * For other `BuildContext` instances (like a local variable or function |
| argument), the `BuildContext`'s `mounted` property must be checked. |
| |
| **BAD:** |
| ```dart |
| void onButtonTapped(BuildContext context) async { |
| await Future.delayed(const Duration(seconds: 1)); |
| Navigator.of(context).pop(); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void onButtonTapped(BuildContext context) { |
| Navigator.of(context).pop(); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| void onButtonTapped(BuildContext context) async { |
| await Future.delayed(const Duration(seconds: 1)); |
| |
| if (!context.mounted) return; |
| Navigator.of(context).pop(); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| abstract class MyState extends State<MyWidget> { |
| void foo() async { |
| await Future.delayed(const Duration(seconds: 1)); |
| if (!mounted) return; // Checks `this.mounted`, not `context.mounted`. |
| Navigator.of(context).pop(); |
| } |
| } |
| ``` |
| use_build_context_synchronously_wrong_mounted: |
| sharedName: use_build_context_synchronously |
| problemMessage: "Don't use 'BuildContext's across async gaps, guarded by an unrelated 'mounted' check." |
| correctionMessage: "Guard a 'State.context' use with a 'mounted' check on the State, and other BuildContext use with a 'mounted' check on the BuildContext." |
| hasPublishedDocs: true |
| use_colored_box: |
| problemMessage: "Use a 'ColoredBox' rather than a 'Container' with only a 'Color'." |
| correctionMessage: "Try replacing the 'Container' with a 'ColoredBox'." |
| state: |
| stable: "2.17" |
| categories: [flutter, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `Container` is created that |
| only sets the color. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the only attribute of |
| the container that is set is the `color`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget build() { |
| return [!Container!]( |
| color: Colors.red, |
| child: const Text('hello'), |
| ); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Replace the `Container` with a `ColoredBox`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget build() { |
| return ColoredBox( |
| color: Colors.red, |
| child: const Text('hello'), |
| ); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** use `ColoredBox` when `Container` has only a `Color`. |
| |
| A `Container` is a heavier Widget than a `ColoredBox`, and as bonus, |
| `ColoredBox` has a `const` constructor. |
| |
| **BAD:** |
| ```dart |
| Widget buildArea() { |
| return Container( |
| color: Colors.blue, |
| child: const Text('hello'), |
| ); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Widget buildArea() { |
| return const ColoredBox( |
| color: Colors.blue, |
| child: Text('hello'), |
| ); |
| } |
| ``` |
| use_decorated_box: |
| problemMessage: "Use 'DecoratedBox' rather than a 'Container' with only a 'Decoration'." |
| correctionMessage: "Try replacing the 'Container' with a 'DecoratedBox'." |
| state: |
| stable: "2.16" |
| categories: [flutter, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `Container` is created that |
| only sets the decoration. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the only attribute of |
| the container that is set is the `decoration`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget buildArea() { |
| return [!Container!]( |
| decoration: const BoxDecoration( |
| color: Colors.red, |
| borderRadius: BorderRadius.all( |
| Radius.circular(5), |
| ), |
| ), |
| child: const Text('...'), |
| ); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Replace the `Container` with a `DecoratedBox`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Widget buildArea() { |
| return DecoratedBox( |
| decoration: const BoxDecoration( |
| color: Colors.red, |
| borderRadius: BorderRadius.all( |
| Radius.circular(5), |
| ), |
| ), |
| child: const Text('...'), |
| ); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** use `DecoratedBox` when `Container` has only a `Decoration`. |
| |
| A `Container` is a heavier Widget than a `DecoratedBox`, and as bonus, |
| `DecoratedBox` has a `const` constructor. |
| |
| **BAD:** |
| ```dart |
| Widget buildArea() { |
| return Container( |
| decoration: const BoxDecoration( |
| color: Colors.blue, |
| borderRadius: BorderRadius.all( |
| Radius.circular(5), |
| ), |
| ), |
| child: const Text('...'), |
| ); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Widget buildArea() { |
| return const DecoratedBox( |
| decoration: BoxDecoration( |
| color: Colors.blue, |
| borderRadius: BorderRadius.all( |
| Radius.circular(5), |
| ), |
| ), |
| child: Text('...'), |
| ); |
| } |
| ``` |
| use_enums: |
| problemMessage: "Class should be an enum." |
| correctionMessage: "Try using an enum rather than a class." |
| state: |
| stable: "2.17" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Classes that look like enumerations should be declared as `enum`s. |
| |
| **DO** use enums where appropriate. |
| |
| Candidates for enums are classes that: |
| |
| * are concrete, |
| * are private or have only private generative constructors, |
| * have two or more static const fields with the same type as the class, |
| * have generative constructors that are only invoked at the top-level of the |
| initialization expression of these static fields, |
| * do not define `hashCode`, `==`, `values` or `index`, |
| * do not extend any class other than `Object`, and |
| * have no subclasses declared in the defining library. |
| |
| To learn more about creating and using these enums, check out |
| [Declaring enhanced enums](https://dart.dev/language/enums#declaring-enhanced-enums). |
| |
| **BAD:** |
| ```dart |
| class LogPriority { |
| static const error = LogPriority._(1, 'Error'); |
| static const warning = LogPriority._(2, 'Warning'); |
| static const log = LogPriority._unknown('Log'); |
| |
| final String prefix; |
| final int priority; |
| const LogPriority._(this.priority, this.prefix); |
| const LogPriority._unknown(String prefix) : this._(-1, prefix); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| enum LogPriority { |
| error(1, 'Error'), |
| warning(2, 'Warning'), |
| log.unknown('Log'); |
| |
| final String prefix; |
| final int priority; |
| const LogPriority(this.priority, this.prefix); |
| const LogPriority.unknown(String prefix) : this(-1, prefix); |
| } |
| ``` |
| use_full_hex_values_for_flutter_colors: |
| problemMessage: "Instances of 'Color' should be created using an 8-digit hexadecimal integer (such as '0xFFFFFFFF')." |
| state: |
| stable: "2.2" |
| categories: [flutter, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the argument to the constructor |
| of the `Color` class is a literal integer that isn't represented as an |
| 8-digit hexadecimal integer. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the argument (`1`) |
| isn't represented as an 8-digit hexadecimal integer: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Color c = Color([!1!]); |
| ``` |
| |
| #### Common fixes |
| |
| Convert the representation to be an 8-digit hexadecimal integer: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| Color c = Color(0x00000001); |
| ``` |
| deprecatedDetails: |- |
| **PREFER** an 8-digit hexadecimal integer (for example, 0xFFFFFFFF) to |
| instantiate a Color. Colors have four 8-bit channels, which adds up to 32 bits, |
| so Colors are described using a 32-bit integer. |
| |
| **BAD:** |
| ```dart |
| Color(1); |
| Color(0x000001); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Color(0x00000001); |
| ``` |
| use_function_type_syntax_for_parameters: |
| problemMessage: "Use the generic function type syntax to declare the parameter '{0}'." |
| correctionMessage: "Try using the generic function type syntax." |
| state: |
| stable: "2.1" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the older style function-valued |
| parameter syntax is used. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the function-valued |
| parameter `f` is declared using an older style syntax: |
| |
| ```dart |
| void g([!bool f(String s)!]) {} |
| ``` |
| |
| #### Common fixes |
| |
| Use the generic function type syntax to declare the parameter: |
| |
| ```dart |
| void g(bool Function(String) f) {} |
| ``` |
| deprecatedDetails: |- |
| Use generic function type syntax for parameters. |
| |
| **BAD:** |
| ```dart |
| Iterable<T> where(bool predicate(T element)) {} |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Iterable<T> where(bool Function(T) predicate) {} |
| ``` |
| use_if_null_to_convert_nulls_to_bools: |
| problemMessage: "Use an if-null operator to convert a 'null' to a 'bool'." |
| correctionMessage: "Try using an if-null operator." |
| state: |
| stable: "2.13" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a nullable `bool`-valued |
| expression is compared (using `==` or `!=`) to a boolean literal. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the nullable boolean |
| variable `b` is compared to `true`: |
| |
| ```dart |
| void f(bool? b) { |
| if ([!b == true!]) { |
| // Treats `null` as `false`. |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Rewrite the condition to use `??` instead: |
| |
| ```dart |
| void f(bool? b) { |
| if (b ?? false) { |
| // Treats `null` as `false`. |
| } |
| } |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/usage#prefer-using--to-convert-null-to-a-boolean-value): |
| |
| Use `??` operators to convert `null`s to `bool`s. |
| |
| **BAD:** |
| ```dart |
| if (nullableBool == true) { |
| } |
| if (nullableBool != false) { |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| if (nullableBool ?? false) { |
| } |
| if (nullableBool ?? true) { |
| } |
| ``` |
| use_is_even_rather_than_modulo: |
| problemMessage: "Use '{0}' rather than '% 2'." |
| correctionMessage: "Try using '{0}'." |
| state: |
| stable: "2.9" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| **PREFER** the use of intValue.isOdd/isEven to check for evenness. |
| |
| **BAD:** |
| ```dart |
| bool isEven = 1 % 2 == 0; |
| bool isOdd = 13 % 2 == 1; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| bool isEven = 1.isEven; |
| bool isOdd = 13.isOdd; |
| ``` |
| use_key_in_widget_constructors: |
| problemMessage: "Constructors for public widgets should have a named 'key' parameter." |
| correctionMessage: "Try adding a named parameter to the constructor." |
| state: |
| stable: "2.8" |
| categories: [flutter, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a constructor in a subclass of |
| `Widget` that isn't private to its library doesn't have a parameter named |
| `key`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the constructor for |
| the class `MyWidget` doesn't have a parameter named `key`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| class MyWidget extends StatelessWidget { |
| [!MyWidget!]({required int height}); |
| } |
| ``` |
| |
| The following code produces this diagnostic because the default |
| constructor for the class `MyWidget` doesn't have a parameter named `key`: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| class [!MyWidget!] extends StatelessWidget {} |
| ``` |
| |
| #### Common fixes |
| |
| Add a parameter named `key` to the constructor, explicitly declaring the |
| constructor if necessary: |
| |
| ```dart |
| import 'package:flutter/material.dart'; |
| |
| class MyWidget extends StatelessWidget { |
| MyWidget({super.key, required int height}); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** use key in widget constructors. |
| |
| It's a good practice to expose the ability to provide a key when creating public |
| widgets. |
| |
| **BAD:** |
| ```dart |
| class MyPublicWidget extends StatelessWidget { |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class MyPublicWidget extends StatelessWidget { |
| MyPublicWidget({super.key}); |
| } |
| ``` |
| use_late_for_private_fields_and_variables: |
| problemMessage: "Use 'late' for private members with a non-nullable type." |
| correctionMessage: "Try making adding the modifier 'late'." |
| state: |
| experimental: "2.10" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a private field or variable is |
| marked as being nullable, but every reference assumes that the variable is |
| never `null`. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the private top-level |
| variable `_i` is nullable, but every reference assumes that it will not be |
| `null`: |
| |
| ```dart |
| void f() { |
| _i!.abs(); |
| } |
| |
| int? [!_i!]; |
| ``` |
| |
| #### Common fixes |
| |
| Mark the variable or field as being both non-nullable and `late` to |
| indicate that it will always be assigned a non-null: |
| |
| ```dart |
| void f() { |
| _i.abs(); |
| } |
| |
| late int _i; |
| ``` |
| deprecatedDetails: |- |
| Use `late` for private members with non-nullable types that are always expected |
| to be non-null. Thus it's clear that the field is not expected to be `null` |
| and it avoids null checks. |
| |
| **BAD:** |
| ```dart |
| int? _i; |
| m() { |
| _i!.abs(); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| late int _i; |
| m() { |
| _i.abs(); |
| } |
| ``` |
| |
| **OK:** |
| ```dart |
| int? _i; |
| m() { |
| _i?.abs(); |
| _i = null; |
| } |
| ``` |
| use_named_constants: |
| problemMessage: "Use the constant '{0}' rather than a constructor returning the same object." |
| correctionMessage: "Try using '{0}'." |
| state: |
| stable: "2.13" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a constant is created with the |
| same value as a known `const` variable. |
| |
| #### Example |
| |
| The following code produces this diagnostic because there is a known |
| `const` field (`Duration.zero`) whose value is the same as what the |
| constructor invocation will evaluate to: |
| |
| ```dart |
| Duration d = [!const Duration(seconds: 0)!]; |
| ``` |
| |
| #### Common fixes |
| |
| Replace the constructor invocation with a reference to the known `const` |
| variable: |
| |
| ```dart |
| Duration d = Duration.zero; |
| ``` |
| deprecatedDetails: |- |
| Where possible, use already defined const values. |
| |
| **BAD:** |
| ```dart |
| const Duration(seconds: 0); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| Duration.zero; |
| ``` |
| use_null_aware_elements: |
| problemMessage: "Use the null-aware marker '?' rather than a null check via an 'if'." |
| correctionMessage: "Try using '?'." |
| state: |
| stable: "3.8" |
| categories: [brevity, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a null check is used instead |
| of a null-aware marker inside of a collection literal. |
| |
| #### Example |
| |
| The following code produces this diagnostic because a null check is used |
| to decide whether `x` should be inserted into the list, while the |
| null-aware marker '?' would be less brittle and less verbose. |
| |
| ```dart |
| f(int? x) => [[!if!] (x != null) x]; |
| ``` |
| |
| #### Common fixes |
| |
| Replace the null-check with the null-aware marker '?': |
| |
| ```dart |
| f(int? x) => [?x]; |
| ``` |
| deprecatedDetails: |- |
| Where possible, use null-aware elements in collection literals. |
| |
| **BAD:** |
| ```dart |
| f(String? key) => {if (key != null) key: "value"}; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| f(String? key) => {?key: "value"}; |
| ``` |
| use_raw_strings: |
| problemMessage: "Use a raw string to avoid using escapes." |
| correctionMessage: "Try making the string a raw string and removing the escapes." |
| state: |
| stable: "2.8" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a string literal containing |
| escapes, and no interpolations, could be marked as being raw in order to |
| avoid the need for the escapes. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the string contains |
| escaped characters that wouldn't need to be escaped if the string is |
| made a raw string: |
| |
| ```dart |
| var s = [!'A string with only \\ and \$'!]; |
| ``` |
| |
| #### Common fixes |
| |
| Mark the string as being raw and remove the unnecessary backslashes: |
| |
| ```dart |
| var s = r'A string with only \ and $'; |
| ``` |
| deprecatedDetails: |- |
| A raw string can be used to avoid escaping only backslashes and dollars. |
| |
| **BAD:** |
| ```dart |
| var s = 'A string with only \\ and \$'; |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var s = r'A string with only \ and $'; |
| ``` |
| use_rethrow_when_possible: |
| problemMessage: "Use 'rethrow' to rethrow a caught exception." |
| correctionMessage: "Try replacing the 'throw' with a 'rethrow'." |
| state: |
| stable: "2.0" |
| categories: [brevity, effectiveDart] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a caught exception is thrown |
| using a `throw` expression rather than a `rethrow` statement. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the caught exception |
| `e` is thrown using a `throw` expression: |
| |
| ```dart |
| void f() { |
| try { |
| // ... |
| } catch (e) { |
| [!throw e!]; |
| } |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use `rethrow` instead of `throw`: |
| |
| ```dart |
| void f() { |
| try { |
| // ... |
| } catch (e) { |
| rethrow; |
| } |
| } |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/usage#do-use-rethrow-to-rethrow-a-caught-exception): |
| |
| **DO** use rethrow to rethrow a caught exception. |
| |
| As Dart provides rethrow as a feature, it should be used to improve terseness |
| and readability. |
| |
| **BAD:** |
| ```dart |
| try { |
| somethingRisky(); |
| } catch(e) { |
| if (!canHandle(e)) throw e; |
| handle(e); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| try { |
| somethingRisky(); |
| } catch(e) { |
| if (!canHandle(e)) rethrow; |
| handle(e); |
| } |
| ``` |
| use_setters_to_change_properties: |
| problemMessage: "The method is used to change a property." |
| correctionMessage: "Try converting the method to a setter." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a method is used to set the |
| value of a field, or a function is used to set the value of a top-level |
| variable, and nothing else. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the method `setF` is |
| used to set the value of the field `_f` and does no other work: |
| |
| ```dart |
| class C { |
| int _f = 0; |
| |
| void [!setF!](int value) => _f = value; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Convert the method to a setter: |
| |
| ```dart |
| class C { |
| int _f = 0; |
| |
| set f(int value) => _f = value; |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** use a setter for operations that conceptually change a property. |
| |
| **BAD:** |
| ```dart |
| rectangle.setWidth(3); |
| button.setVisible(false); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| rectangle.width = 3; |
| button.visible = false; |
| ``` |
| use_string_buffers: |
| problemMessage: "Use a string buffer rather than '+' to compose strings." |
| correctionMessage: "Try writing the parts of a string to a string buffer." |
| state: |
| stable: "2.0" |
| categories: [nonPerformant] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when values are concatenated to a |
| string inside a loop without using a `StringBuffer` to do the |
| concatenation. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the string `result` is |
| computed by repeated concatenation within the `for` loop: |
| |
| ```dart |
| String f() { |
| var result = ''; |
| for (int i = 0; i < 10; i++) { |
| [!result += 'a'!]; |
| } |
| return result; |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use a `StringBuffer` to compute the result: |
| |
| ```dart |
| String f() { |
| var buffer = StringBuffer(); |
| for (int i = 0; i < 10; i++) { |
| buffer.write('a'); |
| } |
| return buffer.toString(); |
| } |
| ``` |
| deprecatedDetails: |- |
| **DO** use string buffers to compose strings. |
| |
| In most cases, using a string buffer is preferred for composing strings due to |
| its improved performance. |
| |
| **BAD:** |
| ```dart |
| String foo() { |
| final buffer = ''; |
| for (int i = 0; i < 10; i++) { |
| buffer += 'a'; // LINT |
| } |
| return buffer; |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| String foo() { |
| final buffer = StringBuffer(); |
| for (int i = 0; i < 10; i++) { |
| buffer.write('a'); |
| } |
| return buffer.toString(); |
| } |
| ``` |
| use_string_in_part_of_directives: |
| problemMessage: "The part-of directive uses a library name." |
| correctionMessage: "Try converting the directive to use the URI of the library." |
| state: |
| stable: "2.19" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a `part of` directive uses a |
| library name to refer to the library that the part is a part of. |
| |
| #### Example |
| |
| Given a file named `lib.dart` that contains the following: |
| |
| ```dart |
| %uri="lib/lib.dart" |
| library lib; |
| |
| part 'test.dart'; |
| ``` |
| |
| The following code produces this diagnostic because the `part of` |
| directive uses the name of the library rather than the URI of the library |
| it's part of: |
| |
| ```dart |
| [!part of lib;!] |
| ``` |
| |
| #### Common fixes |
| |
| Use a URI to reference the library: |
| |
| ```dart |
| part of 'lib.dart'; |
| ``` |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/usage#do-use-strings-in-part-of-directives): |
| |
| **DO** use strings in `part of` directives. |
| |
| **BAD:** |
| |
| ```dart |
| part of my_library; |
| ``` |
| |
| **GOOD:** |
| |
| ```dart |
| part of '../../my_library.dart'; |
| ``` |
| use_super_parameters_multiple: |
| sharedName: use_super_parameters |
| problemMessage: "Parameters '{0}' could be super parameters." |
| correctionMessage: "Trying converting '{0}' to super parameters." |
| state: |
| experimental: "2.17" |
| categories: [brevity] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a parameter to a constructor is |
| passed to a super constructor without being referenced or modified and a |
| `super` parameter isn't used. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the parameters of the |
| constructor for `B` are only used as arguments to the super constructor: |
| |
| ```dart |
| class A { |
| A({int? x, int? y}); |
| } |
| class B extends A { |
| [!B!]({int? x, int? y}) : super(x: x, y: y); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| Use a `super` parameter to pass the arguments: |
| |
| ```dart |
| class A { |
| A({int? x, int? y}); |
| } |
| class B extends A { |
| B({super.x, super.y}); |
| } |
| ``` |
| deprecatedDetails: |- |
| "Forwarding constructor"s, that do nothing except forward parameters to their |
| superclass constructors should take advantage of super-initializer parameters |
| rather than repeating the names of parameters when passing them to the |
| superclass constructors. This makes the code more concise and easier to read |
| and maintain. |
| |
| **DO** use super-initializer parameters where possible. |
| |
| **BAD:** |
| ```dart |
| class A { |
| A({int? x, int? y}); |
| } |
| class B extends A { |
| B({int? x, int? y}) : super(x: x, y: y); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class A { |
| A({int? x, int? y}); |
| } |
| class B extends A { |
| B({super.x, super.y}); |
| } |
| ``` |
| use_super_parameters_single: |
| sharedName: use_super_parameters |
| problemMessage: "Parameter '{0}' could be a super parameter." |
| correctionMessage: "Trying converting '{0}' to a super parameter." |
| hasPublishedDocs: true |
| use_test_throws_matchers: |
| problemMessage: "Use the 'throwsA' matcher instead of using 'fail' when there is no exception thrown." |
| correctionMessage: "Try removing the try-catch and using 'throwsA' to expect an exception." |
| state: |
| stable: "2.14" |
| categories: [style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| Use the `throwsA` matcher instead of try-catch with `fail()`. |
| |
| **BAD:** |
| |
| ```dart |
| // sync code |
| try { |
| someSyncFunctionThatThrows(); |
| fail('expected Error'); |
| } on Error catch (error) { |
| expect(error.message, contains('some message')); |
| } |
| |
| // async code |
| try { |
| await someAsyncFunctionThatThrows(); |
| fail('expected Error'); |
| } on Error catch (error) { |
| expect(error.message, contains('some message')); |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| // sync code |
| expect( |
| () => someSyncFunctionThatThrows(), |
| throwsA(isA<Error>().having((Error error) => error.message, 'message', contains('some message'))), |
| ); |
| |
| // async code |
| await expectLater( |
| () => someAsyncFunctionThatThrows(), |
| throwsA(isA<Error>().having((Error error) => error.message, 'message', contains('some message'))), |
| ); |
| ``` |
| use_to_and_as_if_applicable: |
| problemMessage: "Start the name of the method with 'to' or 'as'." |
| correctionMessage: "Try renaming the method to use either 'to' or 'as'." |
| state: |
| stable: "2.0" |
| categories: [effectiveDart, style] |
| hasPublishedDocs: false |
| deprecatedDetails: |- |
| From [Effective Dart](https://dart.dev/effective-dart/design#prefer-naming-a-method-to___-if-it-copies-the-objects-state-to-a-new-object): |
| |
| **PREFER** naming a method `to___()` if it copies the object's state to a new |
| object. |
| |
| **PREFER** naming a method `as___()` if it returns a different representation |
| backed by the original object. |
| |
| **BAD:** |
| ```dart |
| class Bar { |
| Foo myMethod() { |
| return Foo.from(this); |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Bar { |
| Foo toFoo() { |
| return Foo.from(this); |
| } |
| } |
| ``` |
| |
| **GOOD:** |
| ```dart |
| class Bar { |
| Foo asFoo() { |
| return Foo.from(this); |
| } |
| } |
| ``` |
| use_truncating_division: |
| problemMessage: "Use truncating division." |
| correctionMessage: "Try using truncating division, '~/', instead of regular division ('/') followed by 'toInt()'." |
| state: |
| stable: "3.6" |
| categories: [languageFeatureUsage] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the result of dividing two |
| numbers is converted to an integer using `toInt`. |
| |
| Dart has a built-in integer division operator that is both more efficient |
| and more concise. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the result of dividing |
| `x` and `y` is converted to an integer using `toInt`: |
| |
| ```dart |
| int divide(int x, int y) => [!(x / y).toInt()!]; |
| ``` |
| |
| #### Common fixes |
| |
| Use the integer division operator (`~/`): |
| |
| ```dart |
| int divide(int x, int y) => x ~/ y; |
| ``` |
| deprecatedDetails: |- |
| **DO** use truncating division, '~/', instead of regular division ('/') followed |
| by 'toInt()'. |
| |
| Dart features a "truncating division" operator which is the same operation as |
| division followed by truncation, but which is more concise and expressive, and |
| may be more performant on some platforms, for certain inputs. |
| |
| **BAD:** |
| ```dart |
| var x = (2 / 3).toInt(); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| var x = 2 ~/ 3; |
| ``` |
| valid_regexps: |
| problemMessage: "Invalid regular expression syntax." |
| correctionMessage: "Try correcting the regular expression." |
| state: |
| stable: "2.0" |
| categories: [unintentional] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when the string passed to the |
| default constructor of the class `RegExp` doesn't contain a valid regular |
| expression. |
| |
| A regular expression created with invalid syntax will throw a |
| `FormatException` at runtime. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the regular expression |
| isn't valid: |
| |
| ```dart |
| var r = RegExp([!r'('!]); |
| ``` |
| |
| #### Common fixes |
| |
| Fix the regular expression: |
| |
| ```dart |
| var r = RegExp(r'\('); |
| ``` |
| deprecatedDetails: |- |
| **DO** use valid regular expression syntax when creating regular expression |
| instances. |
| |
| Regular expressions created with invalid syntax will throw a `FormatException` |
| at runtime so should be avoided. |
| |
| **BAD:** |
| ```dart |
| print(RegExp(r'(').hasMatch('foo()')); |
| ``` |
| |
| **GOOD:** |
| ```dart |
| print(RegExp(r'\(').hasMatch('foo()')); |
| ``` |
| void_checks: |
| problemMessage: "Assignment to a variable of type 'void'." |
| correctionMessage: "Try removing the assignment or changing the type of the variable." |
| state: |
| stable: "2.0" |
| categories: [style] |
| hasPublishedDocs: true |
| documentation: |- |
| #### Description |
| |
| The analyzer produces this diagnostic when a value is assigned to a |
| variable of type `void`. |
| |
| It isn't possible to access the value of such a variable, so the |
| assignment has no value. |
| |
| #### Example |
| |
| The following code produces this diagnostic because the field `value` has |
| the type `void`, but a value is being assigned to it: |
| |
| ```dart |
| class A<T> { |
| T? value; |
| } |
| |
| void f(A<void> a) { |
| [!a.value = 1!]; |
| } |
| ``` |
| |
| The following code produces this diagnostic because the type of the |
| parameter `p` in the method `m` is `void`, but a value is being assigned |
| to it in the invocation: |
| |
| ```dart |
| class A<T> { |
| void m(T p) { } |
| } |
| |
| void f(A<void> a) { |
| a.m([!1!]); |
| } |
| ``` |
| |
| #### Common fixes |
| |
| If the type of the variable is incorrect, then change the type of the |
| variable: |
| |
| ```dart |
| class A<T> { |
| T? value; |
| } |
| |
| void f(A<int> a) { |
| a.value = 1; |
| } |
| ``` |
| |
| If the type of the variable is correct, then remove the assignment: |
| |
| ```dart |
| class A<T> { |
| T? value; |
| } |
| |
| void f(A<void> a) {} |
| ``` |
| deprecatedDetails: |- |
| **DON'T** assign to `void`. |
| |
| **BAD:** |
| ```dart |
| class A<T> { |
| T value; |
| void test(T arg) { } |
| } |
| |
| void main() { |
| A<void> a = A<void>(); |
| a.value = 1; // LINT |
| a.test(1); // LINT |
| } |
| ``` |