Contents

Linter rules

Contents keyboard_arrow_down keyboard_arrow_up

Use the Dart linter to identify possible problems in your Dart code. You can use the linter through your IDE or with the dart analyze command. For information on how to enable and disable individual linter rules, see individual rules sections of the analyzer documentation.

This page lists all the linter rules, with details such as when you might want to use each rule, what code patterns trigger it, and how you might fix your code.

Predefined rule sets

To avoid the need to individually select compatible linter rules, consider starting with a linter rule set, which the following packages provide:

lints
Contains two rule sets curated by the Dart team. We recommend using at least the core rule set, which is used when scoring packages uploaded to pub.dev. Or, better yet, use the recommended rule set, a superset of core that identifies additional issues and enforces style and format. If you’re writing Flutter code, use the rule set in the flutter_lints package, which builds on lints.
flutter_lints
Contains the flutter rule set, which the Flutter team encourages you to use in Flutter apps, packages, and plugins. This rule set is a superset of the recommended set, which is itself a superset of the core set that partially determines the score of packages uploaded to pub.dev.

To learn how to use a specific rule set, see the documentation for enabling and disabling linter rules.

Rule types

Each rule is in one of the following groups:

Errors
Possible errors or mistakes in your code.
Style
Matters of style, largely derived from the Dart style guide.
Pub
Possible issues with pub package setup.

Maturity levels

Each rule also has a maturity level:

Stable
These rules are safe to use and are verified as functional with the latest versions of the Dart language. All rules are considered stable unless they’re marked as experimental or deprecated.
Experimental
These rules are still under evaluation and might never be stabilized. Use these with caution and report any issues you come across.
Deprecated
These rules are no longer suggested for use and might be removed in a future linter release.

Quick fixes

Some rules can be fixed automatically using quick fixes. A quick fix is an automated edit targeted at fixing the issue reported by the linter rule.

If the rule has a quick fix, it can be applied using dart fix or using your editor with Dart support. To learn more, see Quick fixes for analysis issues.

Error rules

These rules identify possible errors and other mistakes in your code.

always_use_package_imports

Avoid relative imports for files in lib/.

This rule is available as of Dart 2.10.0.

This rule has a quick fix available.

Incompatible rules: prefer_relative_imports

Details

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:

import 'baz.dart';

import 'src/bag.dart'

import '../lib/baz.dart';

...

GOOD:

import 'package:foo/bar.dart';

import 'package:foo/baz.dart';

import 'package:foo/src/baz.dart';
...

avoid_dynamic_calls

Avoid method calls or property accesses on a “dynamic” target.

This rule is available as of Dart 2.12.0.

Details

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 “NullError” 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.

BAD:

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:

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

Avoid empty else statements.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

AVOID empty else statements.

BAD:

if (x > y)
  print("1");
else ;
  print("2");

avoid_print

Avoid print calls in production code.

This rule is available as of Dart 2.5.0.

Rule sets: flutter

This rule has a quick fix available.

Details

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:

void f(int x) {
  print('debug: $x');
  ...
}

GOOD:

void f(int x) {
  debugPrint('debug: $x');
  ...
}

GOOD:

void f(int x) {
  log('log: $x');
  ...
}

GOOD:

void f(int x) {
  if (kDebugMode) {
      print('debug: $x');
  }
  ...
}

avoid_relative_lib_imports

Avoid relative imports for files in lib/.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

import 'package:foo/bar.dart';

import '../lib/baz.dart';

...

GOOD:

import 'package:foo/bar.dart';

import 'baz.dart';

...

avoid_returning_null_for_future

Avoid returning null for Future.

This rule is currently deprecated and available as of Dart 2.1.1.

This rule has a quick fix available.

Details

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_slow_async_io

Avoid slow async dart:io methods.

This rule is available as of Dart 2.0.0.

Details

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:

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:

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

Avoid .toString() in production code since results may be minified.

This rule is available as of Dart 2.12.0.

Details

DO avoid calls to .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:

void bar(Object other) {
  if (other.runtimeType.toString() == 'Bar') {
    doThing();
  }
}

Object baz(Thing myThing) {
  return getThingFromDatabase(key: myThing.runtimeType.toString());
}

GOOD:

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

Avoid types as parameter names.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

AVOID using a parameter name that is the same as an existing type.

BAD:

m(f(int));

GOOD:

m(f(int v));

avoid_web_libraries_in_flutter

Avoid using web-only libraries outside Flutter web plugin packages.

This rule is available as of Dart 2.6.0.

Rule sets: flutter

Details

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

cancel_subscriptions

Cancel instances of dart.async.StreamSubscription.

This rule is available as of Dart 2.0.0.

Details

DO invoke cancel on instances of dart.async.StreamSubscription.

Cancelling instances of StreamSubscription prevents memory leaks and unexpected behavior.

BAD:

class A {
  StreamSubscription _subscriptionA; // LINT
  void init(Stream stream) {
    _subscriptionA = stream.listen((_) {});
  }
}

BAD:

void someFunction() {
  StreamSubscription _subscriptionF; // LINT
}

GOOD:

class B {
  StreamSubscription _subscriptionB; // OK
  void init(Stream stream) {
    _subscriptionB = stream.listen((_) {});
  }

  void dispose(filename) {
    _subscriptionB.cancel();
  }
}

GOOD:

void someFunctionOK() {
  StreamSubscription _subscriptionB; // OK
  _subscriptionB.cancel();
}

close_sinks

Close instances of dart.core.Sink.

This rule is available as of Dart 2.0.0.

Details

DO invoke close on instances of dart.core.Sink.

Closing instances of Sink prevents memory leaks and unexpected behavior.

BAD:

class A {
  IOSink _sinkA;
  void init(filename) {
    _sinkA = File(filename).openWrite(); // LINT
  }
}

BAD:

void someFunction() {
  IOSink _sinkF; // LINT
}

GOOD:

class B {
  IOSink _sinkB;
  void init(filename) {
    _sinkB = File(filename).openWrite(); // OK
  }

  void dispose(filename) {
    _sinkB.close();
  }
}

GOOD:

void someFunctionOK() {
  IOSink _sinkFOK; // OK
  _sinkFOK.close();
}

collection_methods_unrelated_type

Invocation of various collection methods with arguments of unrelated types.

This rule is available as of Dart 2.19.0.

Details

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:

void someFunction() {
  var list = <int>[];
  if (list.contains('1')) print('someFunction'); // LINT
}

BAD:

void someFunction() {
  var set = <int>{};
  set.remove('1'); // LINT
}

GOOD:

void someFunction() {
  var list = <int>[];
  if (list.contains(1)) print('someFunction'); // OK
}

GOOD:

void someFunction() {
  var set = <int>{};
  set.remove(1); // OK
}

comment_references

Only reference in scope identifiers in doc comments.

This rule is available as of Dart 2.0.0.

Details

DO reference only in scope identifiers in doc comments.

If you surround things like variable, method, or type names in square brackets, then dart doc will look up the name and link to its docs. For this all to work, ensure that all identifiers in docs wrapped in brackets are in scope.

For example, assuming outOfScopeId is out of scope:

BAD:

/// Return true if [value] is larger than [outOfScopeId].
bool isOutOfRange(int value) { ... }

GOOD:

/// Return 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 either

  • a single identifier where the identifier is any identifier in scope for the comment (see the spec for what is in scope in doc comments),
  • two identifiers separated by a period where the first identifier is the name of a class that is in scope and the second is the name of a member declared in the class,
  • a single identifier followed by a pair of parentheses where the identifier is the name of a class that is in scope (used to refer to the unnamed constructor for the class), or
  • two identifiers separated by a period and followed by a pair of parentheses where the first identifier is the name of a class that is in scope and the second is the name of a named constructor (not strictly necessary, but allowed for consistency).

control_flow_in_finally

Avoid control flow in finally blocks.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

Details

AVOID control flow leaving finally blocks.

Using control flow in finally blocks will inevitably cause unexpected behavior that is hard to debug.

BAD:

class BadReturn {
  double nonCompliantMethod() {
    try {
      return 1 / 0;
    } catch (e) {
      print(e);
    } finally {
      return 1.0; // LINT
    }
  }
}

BAD:

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:

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:

class Ok {
  double compliantMethod() {
    var i = 5;
    try {
      i = 1 / 0;
    } catch (e) {
      print(e); // OK
    }
    return i;
  }
}

deprecated_member_use_from_same_package

Avoid using deprecated elements from within the package in which they are declared.

This rule is available as of Dart 3.0.0.

Details

Elements which are annotated with @deprecated should not be referenced from within the package in which they are declared.

AVOID using deprecated elements.

BAD:

// 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:

// 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;
}

diagnostic_describe_all_properties

DO reference all public properties in debug methods.

This rule is available as of Dart 2.3.0.

This rule has a quick fix available.

Details

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 Widgets or collections of Widgets

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:

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:

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));
  }
}

discarded_futures

Don’t invoke asynchronous functions in non-async blocks.

This rule is available as of Dart 2.18.0.

This rule has a quick fix available.

Details

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:

void recreateDir(String path) {
  deleteDir(path);
  createDir(path);
}

Future<void> deleteDir(String path) async {}

Future<void> createDir(String path) async {}

GOOD:

Future<void> recreateDir(String path) async {
  await deleteDir(path);
  await createDir(path);
}

Future<void> deleteDir(String path) async {}

Future<void> createDir(String path) async {}

empty_statements

Avoid empty statements.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

AVOID empty statements.

Empty statements almost always indicate a bug.

For example,

BAD:

if (complicated.expression.foo());
  bar();

Formatted with dart format the bug becomes obvious:

if (complicated.expression.foo()) ;
bar();

Better to avoid the empty statement altogether.

GOOD:

if (complicated.expression.foo())
  bar();

hash_and_equals

Always override hashCode if overriding ==.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

class Bad {
  final int value;
  Bad(this.value);

  @override
  bool operator ==(Object other) => other is Bad && other.value == value;
}

GOOD:

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;
}

implicit_reopen

Don’t implicitly reopen classes.

This rule is currently experimental and available as of Dart 3.0.0.

This rule has a quick fix available.

Details

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 annotation in package:meta.

BAD:

interface class I {}

class C extends I {} // LINT

GOOD:

interface class I {}

final class C extends I {}
interface class I {}

final class C extends I {}
import 'package:meta/meta.dart';

interface class I {}

@reopen
class C extends I {}

invalid_case_patterns

Use case expressions that are valid in Dart 3.0.

This rule is currently experimental and available as of Dart 3.0.0.

This rule has a quick fix available.

Details

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:

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:

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:

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:

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:

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 _:

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:

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:

case [1, 2]:
case {'k': 'v'}:
case {1, 2}:
case Point(1, 2):

GOOD:

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:

switch (n) {
  case 1 + 2: ...
}

It can be fixed by changing it to:

GOOD:

const three = 1 + 2;

switch (n) {
  case three: ...
}

invariant_booleans

Conditions should not unconditionally evaluate to true or to false.

This rule has been removed as of the latest Dart releases.

Details

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:

// foo can't be both equal and not equal to bar in the same expression
if(foo == bar && something && foo != bar) {...}

BAD:

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:

void compute(bool foo) {
  if (foo) {
    return;
  }
  doSomething();
  // foo is always false here
  if (foo){...}
  ...
}

GOOD:

void nestedOK() {
  if (foo == bar) {
    foo = baz;
    if (foo != bar) {...}
  }
}

GOOD:

void nestedOk2() {
  if (foo == bar) {
    return;
  }

  foo = baz;
  if (foo == bar) {...} // OK
}

GOOD:

void nestedOk5() {
  if (foo != null) {
    if (bar != null) {
      return;
    }
  }

  if (bar != null) {...} // OK
}

iterable_contains_unrelated_type

Invocation of Iterable.contains with references of unrelated types.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

Details

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:

void someFunction() {
  var list = <int>[];
  if (list.contains('1')) print('someFunction'); // LINT
}

BAD:

void someFunction3() {
  List<int> list = <int>[];
  if (list.contains('1')) print('someFunction3'); // LINT
}

BAD:

void someFunction8() {
  List<DerivedClass2> list = <DerivedClass2>[];
  DerivedClass3 instance;
  if (list.contains(instance)) print('someFunction8'); // LINT
}

BAD:

abstract class SomeIterable<E> implements Iterable<E> {}

abstract class MyClass implements SomeIterable<int> {
  bool badMethod(String thing) => this.contains(thing); // LINT
}

GOOD:

void someFunction10() {
  var list = [];
  if (list.contains(1)) print('someFunction10'); // OK
}

GOOD:

void someFunction1() {
  var list = <int>[];
  if (list.contains(1)) print('someFunction1'); // OK
}

GOOD:

void someFunction4() {
  List<int> list = <int>[];
  if (list.contains(1)) print('someFunction4'); // OK
}

GOOD:

void someFunction5() {
  List<ClassBase> list = <ClassBase>[];
  DerivedClass1 instance;
  if (list.contains(instance)) print('someFunction5'); // OK
}

abstract class ClassBase {}

class DerivedClass1 extends ClassBase {}

GOOD:

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:

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 {}

list_remove_unrelated_type

Invocation of remove with references of unrelated types.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

Details

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:

void someFunction() {
  var list = <int>[];
  if (list.remove('1')) print('someFunction'); // LINT
}

BAD:

void someFunction3() {
  List<int> list = <int>[];
  if (list.remove('1')) print('someFunction3'); // LINT
}

BAD:

void someFunction8() {
  List<DerivedClass2> list = <DerivedClass2>[];
  DerivedClass3 instance;
  if (list.remove(instance)) print('someFunction8'); // LINT
}

BAD:

abstract class SomeList<E> implements List<E> {}

abstract class MyClass implements SomeList<int> {
  bool badMethod(String thing) => this.remove(thing); // LINT
}

GOOD:

void someFunction10() {
  var list = [];
  if (list.remove(1)) print('someFunction10'); // OK
}

GOOD:

void someFunction1() {
  var list = <int>[];
  if (list.remove(1)) print('someFunction1'); // OK
}

GOOD:

void someFunction4() {
  List<int> list = <int>[];
  if (list.remove(1)) print('someFunction4'); // OK
}

GOOD:

void someFunction5() {
  List<ClassBase> list = <ClassBase>[];
  DerivedClass1 instance;
  if (list.remove(instance)) print('someFunction5'); // OK
}

abstract class ClassBase {}

class DerivedClass1 extends ClassBase {}

GOOD:

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:

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

Boolean expression composed only with literals.

This rule is available as of Dart 2.0.0.

Details

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:

void bad() {
  if (true) {} // LINT
}

BAD:

void bad() {
  if (true && 1 != 0) {} // LINT
}

BAD:

void bad() {
  if (1 != 0 && true) {} // LINT
}

BAD:

void bad() {
  if (1 < 0 && true) {} // LINT
}

BAD:

void bad() {
  if (true && false) {} // LINT
}

BAD:

void bad() {
  if (1 != 0) {} // LINT
}

BAD:

void bad() {
  if (true && 1 != 0 || 3 < 4) {} // LINT
}

BAD:

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:

void good() {
  while (true) {
    // Do stuff.
  }
}

no_adjacent_strings_in_list

Don’t use adjacent strings in list.

This rule is available as of Dart 2.0.0.

Details

DON’T use adjacent strings in a list.

This can indicate a forgotten comma.

BAD:

List<String> list = <String>[
  'a'
  'b',
  'c',
];

GOOD:

List<String> list = <String>[
  'a' +
  'b',
  'c',
];

no_duplicate_case_values

Don’t use more than one case with same value.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

DON’T use more than one case with same value.

This is usually a typo or changed value of constant.

BAD:

const int A = 1;
switch (v) {
  case 1:
  case 2:
  case A:
  case 2:
}

GOOD:

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_logic_in_create_state

Don’t put any logic in createState.

This rule is available as of Dart 2.8.1.

Rule sets: flutter

Details

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:

MyState global;

class MyStateful extends StatefulWidget {
  @override
  MyState createState() {
    global = MyState();
    return global;
  } 
}
class MyStateful extends StatefulWidget {
  @override
  MyState createState() => MyState()..field = 42;
}
class MyStateful extends StatefulWidget {
  @override
  MyState createState() => MyState(42);
}

GOOD:

class MyStateful extends StatefulWidget {
  @override
  MyState createState() {
    return MyState();
  }
}

prefer_relative_imports

Prefer relative imports for files in lib/.

This rule is available as of Dart 2.6.0.

This rule has a quick fix available.

Incompatible rules: always_use_package_imports

Details

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:

import 'package:my_package/bar.dart';

GOOD:

import 'bar.dart';

prefer_void_to_null

Don’t use the Null type, unless you are positive that you don’t want void.

This rule is available as of Dart 2.1.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

DON’T use the type Null where void would work.

BAD:

Null f() {}
Future<Null> f() {}
Stream<Null> f() {}
f(Null x) {}

GOOD:

void f() {}
Future<void> f() {}
Stream<void> f() {}
f(void x) {}

Some exceptions include formulating special function types:

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:

<Null>[];
<int, Null>{};

test_types_in_equals

Test type arguments in operator ==(Object other).

This rule is available as of Dart 2.0.0.

Details

DO test type arguments in operator ==(Object other).

Not testing types might result in null pointer exceptions which will be unexpected for consumers of your class.

BAD:

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:

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

Avoid throw in finally block.

This rule is available as of Dart 2.0.0.

Details

AVOID throwing exceptions in finally blocks.

Throwing exceptions in finally blocks will inevitably cause unexpected behavior that is hard to debug.

BAD:

class BadThrow {
  double nonCompliantMethod() {
    try {
      print('hello world! ${1 / 0}');
    } catch (e) {
      print(e);
    } finally {
      throw 'Find the hidden error :P'; // LINT
    }
  }
}

GOOD:

class Ok {
  double compliantMethod() {
    var i = 5;
    try {
      i = 1 / 0;
    } catch (e) {
      print(e); // OK
    }
    return i;
  }
}

unnecessary_statements

Avoid using unnecessary statements.

This rule is available as of Dart 2.0.0.

Details

AVOID using unnecessary statements.

Statements which have no clear effect are usually unnecessary, or should be broken up.

For example,

BAD:

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:

some.method();
const SomeClass();
methodOne();
methodTwo();
foo ? bar() : baz();
return myvar;

unrelated_type_equality_checks

Equality operator == invocation with references of unrelated types.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

Details

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:

void someFunction() {
  var x = '1';
  if (x == 1) print('someFunction'); // LINT
}

BAD:

void someFunction1() {
  String x = '1';
  if (x == 1) print('someFunction1'); // LINT
}

BAD:

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:

void someFunction2() {
  var x = '1';
  var y = '2';
  if (x == y) print(someFunction2); // OK
}

GOOD:

void someFunction3() {
  for (var i = 0; i < 10; i++) {
    if (i == 0) print(someFunction3); // OK
  }
}

GOOD:

void someFunction4() {
  var x = '1';
  if (x == null) print(someFunction4); // OK
}

GOOD:

void someFunction7() {
  List someList;

  if (someList.length == 0) print('someFunction7'); // OK
}

GOOD:

void someFunction8(ClassBase instance) {
  DerivedClass1 other;

  if (other == instance) print('someFunction8'); // OK
}

GOOD:

void someFunction10(unknown) {
  var what = unknown - 1;
  for (var index = 0; index < unknown; index++) {
    if (what == index) print('someFunction10'); // OK
  }
}

GOOD:

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 {}

unsafe_html

Avoid unsafe HTML APIs.

This rule is available as of Dart 2.4.0.

Details

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:

var script = ScriptElement()..src = 'foo.js';

use_build_context_synchronously

Do not use BuildContexts across async gaps.

This rule is currently experimental and available as of Dart 2.13.0.

Rule sets: flutter

Details

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, its mounted property must be checked after an asynchronous gap.

BAD:

void onButtonTapped(BuildContext context) async {
  await Future.delayed(const Duration(seconds: 1));
  Navigator.of(context).pop();
}

GOOD:

void onButtonTapped(BuildContext context) {
  Navigator.of(context).pop();
}

GOOD:

void onButtonTapped() async {
  await Future.delayed(const Duration(seconds: 1));

  if (!context.mounted) return;
  Navigator.of(context).pop();
}

use_key_in_widget_constructors

Use key in widget constructors.

This rule is available as of Dart 2.8.1.

Rule sets: flutter

This rule has a quick fix available.

Details

DO use key in widget constructors.

It’s a good practice to expose the ability to provide a key when creating public widgets.

BAD:

class MyPublicWidget extends StatelessWidget {
}

GOOD:

class MyPublicWidget extends StatelessWidget {
  MyPublicWidget({super.key});
}

valid_regexps

Use valid regular expression syntax.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

Details

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:

print(RegExp(r'(').hasMatch('foo()'));

GOOD:

print(RegExp(r'\(').hasMatch('foo()'));

Style rules

These rules identify opportunities for style improvements, largely derived from the Dart style guide.

always_declare_return_types

Declare method return types.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

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:

main() { }

_bar() => _Foo();

class _Foo {
  _foo() => 42;
}

GOOD:

void main() { }

_Foo _bar() => _Foo();

class _Foo {
  int _foo() => 42;
}

typedef predicate = bool Function(Object o);

always_put_control_body_on_new_line

Separate the control structure expression from its statement.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

From the style guide for the flutter repo:

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:

if (notReady) return;

if (notReady)
  return;
else print('ok')

while (condition) i += 1;

GOOD:

if (notReady)
  return;

if (notReady)
  return;
else
  print('ok')

while (condition)
  i += 1;

Note that this rule can conflict with the Dart formatter, and should not be enabled when the Dart formatter is used.

always_put_required_named_parameters_first

Put required named parameters first.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

DO specify required on named parameter before other named parameters.

BAD:

m({b, c, required a}) ;

GOOD:

m({required a, b, c}) ;

BAD:

m({b, c, @required a}) ;

GOOD:

m({@required a, b, c}) ;

always_require_non_null_named_parameters

Specify @required on named parameters without defaults.

This rule is currently deprecated and available as of Dart 2.0.0.

This rule has a quick fix available.

Details

DO specify @required on named parameters without a default value on which an assert(param != null) is done.

BAD:

m1({a}) {
  assert(a != null);
}

GOOD:

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

Specify type annotations.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Incompatible rules: avoid_types_on_closure_parameters, omit_local_variable_types

Details

From the style guide for the flutter repo:

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:

var foo = 10;
final bar = Bar();
const quux = 20;

GOOD:

int foo = 10;
final Bar bar = Bar();
String baz = 'hello';
const int quux = 20;

NOTE: Using the the @optionalTypeArgs annotation in the meta package, API authors can special-case type variables whose type needs to by 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:

import 'package:meta/meta.dart';

@optionalTypeArgs
class Key<T> {
 ...
}

main() {
  Key s = Key(); // OK!
}

annotate_overrides

Annotate overridden members.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

DO annotate overridden methods and fields.

This practice improves code readability and helps protect against unintentionally overriding superclass members.

BAD:

class Cat {
  int get lives => 9;
}

class Lucky extends Cat {
  final int lives = 14;
}

GOOD:

abstract class Dog {
  String get breed;
  void bark() {}
}

class Husky extends Dog {
  @override
  final String breed = 'Husky';
  @override
  void bark() {}
}

avoid_annotating_with_dynamic

Avoid annotating with dynamic when not required.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

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:

dynamic lookUpOrDefault(String name, Map map, dynamic defaultValue) {
  var value = map[name];
  if (value != null) return value;
  return defaultValue;
}

GOOD:

lookUpOrDefault(String name, Map map, defaultValue) {
  var value = map[name];
  if (value != null) return value;
  return defaultValue;
}

avoid_as

Avoid using as.

This rule has been removed as of the latest Dart releases.

Details

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:

(pm as Person).firstName = 'Seth';

GOOD:

if (pm is Person)
  pm.firstName = 'Seth';

but certainly not

BAD:

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:

HasScrollDirection scrollable = renderObject as dynamic;

avoid_bool_literals_in_conditional_expressions

Avoid bool literals in conditional expressions.

This rule is available as of Dart 2.0.0.

Details

AVOID bool literals in conditional expressions.

BAD:

condition ? true : boolExpression
condition ? false : boolExpression
condition ? boolExpression : true
condition ? boolExpression : false

GOOD:

condition || boolExpression
!condition && boolExpression
!condition || boolExpression
condition && boolExpression

avoid_catches_without_on_clauses

Avoid catches without on clauses.

This rule is available as of Dart 2.0.0.

Details

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:

try {
 somethingRisky()
}
catch(e) {
  doSomething(e);
}

GOOD:

try {
 somethingRisky()
}
on Exception catch(e) {
  doSomething(e);
}

avoid_catching_errors

Don’t explicitly catch Error or types that implement it.

This rule is available as of Dart 2.0.0.

Details

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:

try {
  somethingRisky();
} on Error catch(e) {
  doSomething(e);
}

GOOD:

try {
  somethingRisky();
} on Exception catch(e) {
  doSomething(e);
}

avoid_classes_with_only_static_members

Avoid defining a class that contains only static members.

This rule is available as of Dart 2.0.0.

Details

From Effective Dart:

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:

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:

DateTime mostRecent(List<DateTime> dates) {
  return dates.reduce((a, b) => a.isAfter(b) ? a : b);
}

const _favoriteMammal = 'weasel';

avoid_double_and_int_checks

Avoid double and int checks.

This rule is available as of Dart 2.0.0.

Details

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:

f(num x) {
  if (x is double) {
    ...
  } else if (x is int) {
    ...
  }
}

GOOD:

f(dynamic x) {
  if (x is num) {
    ...
  } else {
    ...
  }
}

avoid_equals_and_hash_code_on_mutable_classes

Avoid overloading operator == and hashCode on classes not marked @immutable.

This rule is available as of Dart 2.6.0.

Details

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. See https://dart.dev/guides/language/effective-dart/design#avoid-defining-custom-equality-for-mutable-classes for more information.

BAD:

class B {
  String key;
  const B(this.key);
  @override
  operator ==(other) => other is B && other.key == key;
  @override
  int get hashCode => key.hashCode;
}

GOOD:

@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:

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

Avoid escaping inner quotes by converting surrounding quotes.

This rule is available as of Dart 2.8.1.

This rule has a quick fix available.

Details

Avoid escaping inner quotes by converting surrounding quotes.

BAD:

var s = 'It\'s not fun';

GOOD:

var s = "It's not fun";

avoid_field_initializers_in_const_classes

Avoid field initializers in const classes.

This rule is available as of Dart 2.0.0.

Details

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:

class A {
  final a = const [];
  const A();
}

GOOD:

class A {
  get a => const [];
  const A();
}

avoid_final_parameters

Avoid final for parameter declarations.

This rule is available as of Dart 2.16.0.

Incompatible rules: prefer_final_parameters

Details

AVOID declaring parameters as final.

Declaring parameters as final can lead to unnecessarily verbose code, especially when using the “parameter_assignments” rule.

BAD:

void goodParameter(final String label) { // LINT
  print(label);
}

GOOD:

void badParameter(String label) { // OK
  print(label);
}

BAD:

void goodExpression(final int value) => print(value); // LINT

GOOD:

void badExpression(int value) => print(value); // OK

BAD:

[1, 4, 6, 8].forEach((final value) => print(value + 2)); // LINT

GOOD:

[1, 4, 6, 8].forEach((value) => print(value + 2)); // OK

avoid_function_literals_in_foreach_calls

Avoid using forEach with a function literal.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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 awaits, while the closure body of a forEach cannot.

BAD:

people.forEach((person) {
  ...
});

GOOD:

for (var person in people) {
  ...
}

avoid_implementing_value_types

Don’t implement classes that override ==.

This rule is available as of Dart 2.1.0.

Details

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:

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:

class CustomSize implements Size {
  final int inBytes;
  const CustomSize(this.inBytes);

  int get inKilobytes => inBytes ~/ 1000;
}

BAD:

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:

class ExtendedSize extends Size {
  ExtendedSize(int inBytes) : super(inBytes);

  int get inKilobytes => inBytes ~/ 1000;
}

GOOD::

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

Don’t explicitly initialize variables to null.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

From Effective Dart:

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:

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:

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

Avoid JavaScript rounded ints.

This rule is available as of Dart 2.0.0.

Details

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:

int value = 9007199254740995;

GOOD:

BigInt value = BigInt.parse('9007199254740995');

avoid_multiple_declarations_per_line

Don’t declare multiple variables on a single line.

This rule is available as of Dart 2.13.0.

Details

DON’T declare multiple variables on a single line.

BAD:

String? foo, bar, baz;

GOOD:

String? foo;
String? bar;
String? baz;

avoid_null_checks_in_equality_operators

Don’t check for null in custom == operators.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

class Person {
  final String? name;

  @override
  operator ==(Object? other) =>
      other != null && other is Person && name == other.name;
}

GOOD:

class Person {
  final String? name;

  @override
  operator ==(Object? other) => other is Person && name == other.name;
}

avoid_positional_boolean_parameters

Avoid positional boolean parameters.

This rule is available as of Dart 2.0.0.

Details

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:

Task(true);
Task(false);
ListBox(false, true, true);
Button(false);

GOOD:

Task.oneShot();
Task.repeating();
ListBox(scroll: true, showScrollbars: true);
Button(ButtonState.enabled);

avoid_private_typedef_functions

Avoid private typedef functions.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

AVOID private typedef functions used only once. Prefer inline function syntax.

BAD:

typedef void _F();
m(_F f);

GOOD:

m(void Function() f);

avoid_redundant_argument_values

Avoid redundant argument values.

This rule is available as of Dart 2.8.1.

This rule has a quick fix available.

Details

DON’T pass an argument that matches the corresponding parameter’s default value.

BAD:

void f({bool valWithDefault = true, bool? val}) {
  ...
}

void main() {
  f(valWithDefault: true);
}

GOOD:

void f({bool valWithDefault = true, bool? val}) {
  ...
}

void main() {
  f(valWithDefault: false);
  f();
}

avoid_renaming_method_parameters

Don’t rename parameters of overridden methods.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

abstract class A {
  m(a);
}

abstract class B extends A {
  m(b);
}

GOOD:

abstract class A {
  m(a);
}

abstract class B extends A {
  m(a);
}

avoid_return_types_on_setters

Avoid return types on setters.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

AVOID return types on setters.

As setters do not return a value, declaring the return type of one is redundant.

BAD:

void set speed(int ms);

GOOD:

set speed(int ms);

avoid_returning_null

Avoid returning null from members whose return type is bool, double, int, or num.

This rule is currently deprecated and available as of Dart 2.0.0.

Details

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:

bool getBool() => null;
num getNum() => null;
int getInt() => null;
double getDouble() => null;

GOOD:

bool getBool() => false;
num getNum() => -1;
int getInt() => -1;
double getDouble() => -1.0;

avoid_returning_null_for_void

Avoid returning null for void.

This rule is available as of Dart 2.1.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

void f1() {
  return null;
}
Future<void> f2() async {
  return null;
}

GOOD:

void f1() {
  return;
}
Future<void> f2() async {
  return;
}

avoid_returning_this

Avoid returning this from methods just to enable a fluent interface.

This rule is available as of Dart 2.0.0.

Details

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:

var buffer = StringBuffer()
  .write('one')
  .write('two')
  .write('three');

GOOD:

var buffer = StringBuffer()
  ..write('one')
  ..write('two')
  ..write('three');

avoid_setters_without_getters

Avoid setters without getters.

This rule is available as of Dart 2.0.0.

Details

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:

class Bad {
  int l, r;

  set length(int newLength) {
    r = l + newLength;
  }
}

GOOD:

class Good {
  int l, r;

  int get length => r - l;

  set length(int newLength) {
    r = l + newLength;
  }
}

avoid_shadowing_type_parameters

Avoid shadowing type parameters.

This rule is available as of Dart 2.1.1.

Rule sets: core, recommended, flutter

Details

AVOID shadowing type parameters.

BAD:

class A<T> {
  void fn<T>() {}
}

GOOD:

class A<T> {
  void fn<U>() {}
}

avoid_single_cascade_in_expression_statements

Avoid single cascade in expression statements.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

AVOID single cascade in expression statements.

BAD:

o..m();

GOOD:

o.m();

avoid_types_on_closure_parameters

Avoid annotating types for function expression parameters.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Incompatible rules: always_specify_types

Details

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:

var names = people.map((Person person) => person.name);

GOOD:

var names = people.map((person) => person.name);

avoid_unnecessary_containers

Avoid unnecessary containers.

This rule is available as of Dart 2.7.0.

Rule sets: flutter

This rule has a quick fix available.

Details

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:

Widget buildRow() {
  return Container(
      child: Row(
        children: <Widget>[
          const MyLogo(),
          const Expanded(
            child: Text('...'),
          ),
        ],
      )
  );
}

GOOD:

Widget buildRow() {
  return Row(
    children: <Widget>[
      const MyLogo(),
      const Expanded(
        child: Text('...'),
      ),
    ],
  );
}

avoid_unused_constructor_parameters

Avoid defining unused parameters in constructors.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

AVOID defining unused parameters in constructors.

BAD:

class BadOne {
  BadOne(int unusedParameter, [String unusedPositional]);
}

class BadTwo {
  int c;

  BadTwo(int a, int b, int x) {
    c = a + b;
  }
}

avoid_void_async

Avoid async functions that return void.

This rule is available as of Dart 2.1.0.

This rule has a quick fix available.

Details

DO mark async functions as returning Future.

When declaring an async method or function which does not return a value, declare that it returns Future<void> and not just void.

BAD:

void f() async {}
void f2() async => null;

GOOD:

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:

Future<void> f() async {}

void main() async {
  await f();
}

await_only_futures

Await only futures.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

main() async {
  print(await 23);
}

GOOD:

main() async {
  await null; // If a delay is really intended.
  print(23);
}

camel_case_extensions

Name extensions using UpperCamelCase.

This rule is available as of Dart 2.6.0.

Rule sets: core, recommended, flutter

Details

From the style guide:

DO name extensions using UpperCamelCase.

Extensions should capitalize the first letter of each word (including the first word), and use no separators.

GOOD:

extension MyFancyList<T> on List<T> { 
  // ... 
}

extension SmartIterable<T> on Iterable<T> {
  // ...
}

camel_case_types

Name types using UpperCamelCase.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

Details

From the style guide:

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:

class SliderMenu {
  // ...
}

class HttpRequest {
  // ...
}

typedef num Adder(num x, num y);

cascade_invocations

Cascade consecutive method invocations on the same reference.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

DO Use the cascading style when successively invoking methods on the same reference.

BAD:

SomeClass someReference = SomeClass();
someReference.firstMethod();
someReference.secondMethod();

BAD:

SomeClass someReference = SomeClass();
...
someReference.firstMethod();
someReference.aProperty = value;
someReference.secondMethod();

GOOD:

SomeClass someReference = SomeClass()
    ..firstMethod()
    ..aProperty = value
    ..secondMethod();

GOOD:

SomeClass someReference = SomeClass();
...
someReference
    ..firstMethod()
    ..aProperty = value
    ..secondMethod();

cast_nullable_to_non_nullable

Don’t cast a nullable value to a non nullable type.

This rule is available as of Dart 2.12.0.

Details

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:

class A {}
class B extends A {}

A? a;
var v = a as B;
var v = a as A;

GOOD:

class A {}
class B extends A {}

A? a;
var v = a! as B;
var v = a!;

combinators_ordering

Sort combinator names alphabetically.

This rule is available as of Dart 2.19.0.

This rule has a quick fix available.

Details

DO sort combinator names alphabetically.

BAD:

import 'a.dart' show B, A hide D, C;
export 'a.dart' show B, A hide D, C;

GOOD:

import 'a.dart' show A, B hide C, D;
export 'a.dart' show A, B hide C, D;

conditional_uri_does_not_exist

Missing conditional import.

This rule is available as of Dart 2.16.0.

Details

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:

import 'file_that_does_exist.dart'
  if (condition) 'file_that_does_not_exist.dart';

GOOD:

import 'file_that_does_exist.dart'
  if (condition) 'file_that_also_does_exist.dart';

constant_identifier_names

Prefer using lowerCamelCase for constant names.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

Details

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:

const PI = 3.14;
const kDefaultTimeout = 1000;
final URL_SCHEME = RegExp('^([a-z]+):');

class Dice {
  static final NUMBER_GENERATOR = Random();
}

GOOD:

const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');

class Dice {
  static final numberGenerator = Random();
}

curly_braces_in_flow_control_structures

DO use curly braces for all flow control structures.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

DO use curly braces for all flow control structures.

Doing so avoids the dangling else problem.

BAD:

if (overflowChars != other.overflowChars)
  return overflowChars < other.overflowChars;

GOOD:

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 and the then body all fit in one line. In that case, you may leave off the braces if you prefer:

GOOD:

if (arg == null) return defaultValue;

If the body wraps to the next line, though, use braces:

GOOD:

if (overflowChars != other.overflowChars) {
  return overflowChars < other.overflowChars;
}

dangling_library_doc_comments

Attach library doc comments to library directives.

This rule is available as of Dart 2.19.0.

This rule has a quick fix available.

Details

Attach library doc comments (with ///) to library directives, rather than leaving them dangling near the top of a library.

BAD:

/// This is a great library.
import 'package:math';
/// This is a great library.

class C {}

GOOD:

/// 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.

deprecated_consistency

Missing deprecated annotation.

This rule is available as of Dart 2.13.0.

Details

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:

@deprecated
class A {
  A();
}

class B {
  B({this.field});
  @deprecated
  Object field;
}

GOOD:

@deprecated
class A {
  @deprecated
  A();
}

class B {
  B({@deprecated this.field});
  @deprecated
  Object field;
}

class C extends B {
  C({@deprecated super.field});
}

directives_ordering

Adhere to Effective Dart Guide directives sorting conventions.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

DO follow the directive ordering conventions in Effective Dart:

DO place dart: imports before other imports.

BAD:

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'dart:async';  // LINT
import 'dart:html';  // LINT

BAD:

import 'dart:html';  // OK
import 'package:bar/bar.dart';

import 'dart:async';  // LINT
import 'package:foo/foo.dart';

GOOD:

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:

import 'a.dart';
import 'b.dart';

import 'package:bar/bar.dart';  // LINT
import 'package:foo/foo.dart';  // LINT

BAD:

import 'package:bar/bar.dart';  // OK
import 'a.dart';

import 'package:foo/foo.dart';  // LINT
import 'b.dart';

GOOD:

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:

import 'src/error.dart';
export 'src/error.dart'; // LINT
import 'src/string_source.dart';

GOOD:

import 'src/error.dart';
import 'src/string_source.dart';

export 'src/error.dart'; // OK

DO sort sections alphabetically.

BAD:

import 'package:foo/bar.dart'; // OK
import 'package:bar/bar.dart'; // LINT

import 'a/b.dart'; // OK
import 'a.dart'; // LINT

GOOD:

import 'package:bar/bar.dart'; // OK
import 'package:foo/bar.dart'; // OK

import 'a.dart'; // OK
import 'a/b.dart'; // OK

do_not_use_environment

Do not use environment declared variables.

This rule is available as of Dart 2.9.0.

Details

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:

const loggingLevel =
  bool.hasEnvironment('logging') ? String.fromEnvironment('logging') : null;

empty_catches

Avoid empty catch blocks.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

try {
  ...
} catch(exception) { }

GOOD:

try {
  ...
} catch(e) {
  // ignored, really.
}

// Alternatively:
try {
  ...
} catch(_) { }

// Better still:
try {
  ...
} catch(e) {
  doSomething(e);
}

empty_constructor_bodies

Use ; instead of {} for empty constructor bodies.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

From the style guide:

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:

class Point {
  int x, y;
  Point(this.x, this.y) {}
}

GOOD:

class Point {
  int x, y;
  Point(this.x, this.y);
}

enable_null_safety

Do use sound null safety.

This rule has been removed as of the latest Dart releases.

Details

DO use sound null safety, by not specifying a dart version lower than 2.12.

BAD:

// @dart=2.8
a() {
}

GOOD:

b() {
}

eol_at_end_of_file

Put a single newline at end of file.

This rule is available as of Dart 2.14.0.

This rule has a quick fix available.

Details

DO put a single newline at the end of non-empty files.

BAD:

a {
}

GOOD:

b {
}
    <-- newline

exhaustive_cases

Define case clauses for all constants in enum-like classes.

This rule is available as of Dart 2.9.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

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:

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

Name source files using lowercase_with_underscores.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

Details

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

Use Flutter TODO format: // TODO(username): message, https://URL-to-issue.

This rule is available as of Dart 2.1.0.

Details

DO use Flutter TODO format.

From the Flutter docs:

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:

// TODO(username): message.
// TODO(username): message, https://URL-to-issue.

implementation_imports

Don’t import implementation files from another package.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

Details

From the the pub package layout doc:

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:

// In 'road_runner'
import 'package:acme/src/internals.dart';

implicit_call_tearoffs

Explicitly tear-off call methods when using an object as a Function.

This rule is available as of Dart 2.19.0.

This rule has a quick fix available.

Details

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:

class Callable {
  void call() {}
}
void callIt(void Function() f) {
  f();
}

callIt(Callable());

GOOD:

class Callable {
  void call() {}
}
void callIt(void Function() f) {
  f();
}

callIt(Callable().call);

join_return_with_assignment

Join return statement with assignment when possible.

This rule is available as of Dart 2.0.0.

Details

DO join return statement with assignment when possible.

BAD:

class A {
  B _lazyInstance;
  static B get instance {
    _lazyInstance ??= B(); // LINT
    return _lazyInstance;
  }
}

GOOD:

class A {
  B _lazyInstance;
  static B get instance => _lazyInstance ??= B();
}

leading_newlines_in_multiline_strings

Start multiline strings with a newline.

This rule is available as of Dart 2.8.1.

This rule has a quick fix available.

Details

Multiline strings are easier to read when they start with a newline (a newline starting a multiline string is ignored).

BAD:

var s1 = '''{
  "a": 1,
  "b": 2
}''';

GOOD:

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

Attach library annotations to library directives.

This rule is available as of Dart 2.19.0.

This rule has a quick fix available.

Details

Attach library annotations to library directives, rather than some other library-level element.

BAD:

@TestOn('browser')

import 'package:test/test.dart';

void main() {}

GOOD:

@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

Name libraries using lowercase_with_underscores.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

Details

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:

library peg-parser;

GOOD:

library peg_parser;

The lint file_names can be used to enforce the same kind of naming on the file.

library_prefixes

Use lowercase_with_underscores when specifying a library prefix.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

Details

DO use lowercase_with_underscores when specifying a library prefix.

BAD:

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:

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

Avoid using private types in public APIs.

This rule is available as of Dart 2.14.0.

Rule sets: recommended, flutter

Details

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:

f(_Private p) { ... }
class _Private {}

GOOD:

f(String s) { ... }

lines_longer_than_80_chars

Avoid lines longer than 80 characters.

This rule is available as of Dart 2.0.0.

Details

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.

matching_super_parameters

Use matching super parameter names.

This rule is currently experimental and not yet available in a stable SDK.

Details

DO use super parameter names that match their corresponding super constructor’s parameter names.

BAD:

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:

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_whitespace_between_adjacent_strings

Missing whitespace between adjacent strings.

This rule is available as of Dart 2.8.1.

Details

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:

var s =
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed'
  'do eiusmod tempor incididunt ut labore et dolore magna';

GOOD:

var s =
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed '
  'do eiusmod tempor incididunt ut labore et dolore magna';

no_default_cases

No default cases.

This rule is currently experimental and available as of Dart 2.9.0.

Details

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:

  switch (testEnum) {
    case TestEnum.A:
      return '123';
    case TestEnum.B:
      return 'abc';
    default:
      return null;
  }

GOOD:

  switch (testEnum) {
    case TestEnum.A:
      return '123';
    case TestEnum.B:
      return 'abc';
  }
  // Default here.
  return null;

no_leading_underscores_for_library_prefixes

Avoid leading underscores for library prefixes.

This rule is available as of Dart 2.16.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

import 'dart:core' as _core;

GOOD:

import 'dart:core' as core;

no_leading_underscores_for_local_identifiers

Avoid leading underscores for local identifiers.

This rule is available as of Dart 2.16.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

void print(String _name) {
  var _size = _name.length;
  ...
}

GOOD:

void print(String name) {
  var size = name.length;
  ...
}

OK:

[1,2,3].map((_) => print('Hello'));

no_literal_bool_comparisons

Don’t compare booleans to boolean literals.

This rule is currently experimental and not yet available in a stable SDK.

This rule has a quick fix available.

Details

From Effective Dart:

DON’T use true or false in equality operations.

This lint applies only if the expression is of a non-nullable bool type.

BAD:

if (someBool == true) {
}
while (someBool == false) {
}

GOOD:

if (someBool) {
}
while (!someBool) {
}

no_runtimeType_toString

Avoid calling toString() on runtimeType.

This rule is available as of Dart 2.8.1.

Details

Calling toString on a runtime type is a non-trivial operation that can negatively impact performance. It’s better to avoid it.

BAD:

class A {
  String toString() => '$runtimeType()';
}

GOOD:

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 assertion
  • in throw expressions
  • in catch clauses
  • in mixin declaration
  • in abstract class

non_constant_identifier_names

Name non-constant identifiers using lowerCamelCase.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

var item;

HttpRequest httpRequest;

align(clearItems) {
  // ...
}

noop_primitive_operations

Noop primitive operations.

This rule is available as of Dart 2.14.0.

This rule has a quick fix available.

Details

Some operations on primitive types are idempotent and can be removed.

BAD:

doubleValue.toDouble();

intValue.toInt();
intValue.round();
intValue.ceil();
intValue.floor();
intValue.truncate();

string.toString();
string = 'hello\n'
    'world\n'
    ''; // useless empty string

'string with ${x.toString()}';

null_check_on_nullable_type_parameter

Don’t use null check on a potentially nullable type parameter.

This rule is available as of Dart 2.12.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

T run<T>(T callback()) {
  T? result;
   (() { result = callback(); })();
  return result!;
}

GOOD:

T run<T>(T callback()) {
  T? result;
   (() { result = callback(); })();
  return result as T;
}

null_closures

Do not pass null as an argument where a closure is expected.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

[1, 3, 5].firstWhere((e) => e.isOdd, orElse: null);

GOOD:

[1, 3, 5].firstWhere((e) => e.isOdd, orElse: () => null);

omit_local_variable_types

Omit type annotations for local variables.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Incompatible rules: always_specify_types

Details

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:

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:

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:

Widget build(BuildContext context) {
  Widget result = Text('You won!');
  if (applyPadding) {
    result = Padding(padding: EdgeInsets.all(8.0), child: result);
  }
  return result;
}

one_member_abstracts

Avoid defining a one-member abstract class when a simple function will do.

This rule is available as of Dart 2.0.0.

Details

From the style guide:

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:

abstract class Predicate {
  bool test(item);
}

GOOD:

typedef Predicate = bool Function(item);

only_throw_errors

Only throw instances of classes extending either Exception or Error.

This rule is available as of Dart 2.0.0.

Details

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:

void throwString() {
  throw 'hello world!'; // LINT
}

GOOD:

void throwArgumentError() {
  Error error = ArgumentError('oh!');
  throw error; // OK
}

overridden_fields

Don’t override fields.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

Details

DON’T override fields.

Overriding fields is almost always done unintentionally. Regardless, it is a bad practice to do so.

BAD:

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:

class Base {
  Object field = 'lorem';

  Object something = 'change';
}

class Ok extends Base {
  Object newField; // OK

  final Object newFinal = 'ignore'; // OK
}

GOOD:

abstract class BaseLoggingHandler {
  Base transformer;
}

class LogPrintHandler implements BaseLoggingHandler {
  @override
  Derived transformer; // OK
}

package_api_docs

Provide doc comments for all public APIs.

This rule is available as of Dart 2.0.0.

Details

DO provide doc comments for all public APIs.

As described in the pub package layout doc, 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:

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:

class Bar {
  void bar();
}

GOOD:

/// 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.

package_prefixed_library_names

Prefix library names with the package name and a dot-separated path.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

Details

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:

// 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

Don’t reassign references to parameters of functions or methods.

This rule is available as of Dart 2.0.0.

Details

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:

void badFunction(int parameter) { // LINT
  parameter = 4;
}

BAD:

void badFunction(int required, {int optional: 42}) { // LINT
  optional ??= 8;
}

BAD:

void badFunctionPositional(int required, [int optional = 42]) { // LINT
  optional ??= 8;
}

BAD:

class A {
  void badMethod(int parameter) { // LINT
    parameter = 4;
  }
}

GOOD:

void ok(String parameter) {
  print(parameter);
}

GOOD:

void actuallyGood(int required, {int optional}) { // OK
  optional ??= ...;
}

GOOD:

void actuallyGoodPositional(int required, [int optional]) { // OK
  optional ??= ...;
}

GOOD:

class A {
  void ok(String parameter) {
    print(parameter);
  }
}

prefer_adjacent_string_concatenation

Use adjacent strings to concatenate string literals.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

DO use adjacent strings to concatenate string literals.

BAD:

raiseAlarm(
    'ERROR: Parts of the spaceship are on fire. Other ' +
    'parts are overrun by martians. Unclear which are which.');

GOOD:

raiseAlarm(
    'ERROR: Parts of the spaceship are on fire. Other '
    'parts are overrun by martians. Unclear which are which.');

prefer_asserts_in_initializer_lists

Prefer putting asserts in initializer lists.

This rule is available as of Dart 2.0.0.

Details

DO put asserts in initializer lists.

BAD:

class A {
  A(int a) {
    assert(a != 0);
  }
}

GOOD:

class A {
  A(int a) : assert(a != 0);
}

prefer_asserts_with_message

Prefer asserts with message.

This rule is available as of Dart 2.3.0.

Details

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:

f(a) {
  assert(a != null);
}

class A {
  A(a) : assert(a != null);
}

GOOD:

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

Prefer using a boolean as the assert condition.

This rule has been removed as of the latest Dart releases.

Details

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:

assert(() {
  f();
  return true;
});

GOOD:

assert(() {
  f();
  return true;
}());

prefer_collection_literals

Use collection literals when possible.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

DO use collection literals when possible.

BAD:

var addresses = Map<String, String>();
var uniqueNames = Set<String>();
var ids = LinkedHashSet<int>();
var coordinates = LinkedHashMap<int, int>();

GOOD:

var addresses = <String, String>{};
var uniqueNames = <String>{};
var ids = <int>{};
var coordinates = <int, int>{};

EXCEPTIONS:

There are cases with LinkedHashSet or LinkedHashMap where a literal constructor will trigger a type error so those will be excluded from the lint.

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

Prefer using ??= over testing for null.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

String get fullName {
  if (_fullName == null) {
    _fullName = getFullUserName(this);
  }
  return _fullName;
}

GOOD:

String get fullName {
  return _fullName ??= getFullUserName(this);
}

prefer_const_constructors

Prefer const with constant constructors.

This rule is available as of Dart 2.0.0.

Rule sets: flutter

This rule has a quick fix available.

Details

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:

class A {
  const A();
}

void accessA() {
  A a = new A();
}

GOOD:

class A {
  const A();
}

void accessA() {
  A a = const A();
}

GOOD:

class A {
  final int x;

  const A(this.x);
}

A foo(int x) => new A(x);

prefer_const_constructors_in_immutables

Prefer declaring const constructors on @immutable classes.

This rule is available as of Dart 2.0.0.

Rule sets: flutter

This rule has a quick fix available.

Details

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:

@immutable
class A {
  final a;
  A(this.a);
}

GOOD:

@immutable
class A {
  final a;
  const A(this.a);
}

prefer_const_declarations

Prefer const over final for declarations.

This rule is available as of Dart 2.0.0.

Rule sets: flutter

This rule has a quick fix available.

Details

PREFER using const for const declarations.

Const declarations are more hot-reload friendly and allow to use const constructors if an instantiation references this declaration.

BAD:

final o = const <int>[];

class A {
  static final o = const <int>[];
}

GOOD:

const o = <int>[];

class A {
  static const o = <int>[];
}

prefer_const_literals_to_create_immutables

Prefer const literals as parameters of constructors on @immutable classes.

This rule is available as of Dart 2.0.0.

Rule sets: flutter

This rule has a quick fix available.

Details

PREFER using const for instantiating list, map and set literals used as parameters in immutable class instantiations.

BAD:

@immutable
class A {
  A(this.v);
  final v;
}

A a1 = new A([1]);
A a2 = new A({});

GOOD:

A a1 = new A(const [1]);
A a2 = new A(const {});

prefer_constructors_over_static_methods

Prefer defining constructors instead of static methods to create instances.

This rule is available as of Dart 2.0.0.

Details

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:

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:

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

Use contains for List and String instances.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

if (lunchBox.indexOf('sandwich') == -1) return 'so hungry...';

GOOD:

if (!lunchBox.contains('sandwich')) return 'so hungry...';

prefer_double_quotes

Prefer double quotes where they won’t require escape sequences.

This rule is available as of Dart 2.4.0.

This rule has a quick fix available.

Incompatible rules: prefer_single_quotes

Details

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, its 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:

useStrings(
    'should be double quote',
    r'should be double quote',
    r'''should be double quotes''')

GOOD:

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

Use = to separate a named parameter from its default value.

This rule has been removed as of the latest Dart releases.

Rule sets: recommended, flutter

Details

From the style guide:

DO use = to separate a named parameter from its default value.

BAD:

m({a: 1})

GOOD:

m({a = 1})

prefer_expression_function_bodies

Use => for short members whose body is a single return statement.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

CONSIDER using => for short members whose body is a single return statement.

BAD:

get width {
  return right - left;
}

BAD:

bool ready(num time) {
  return minTime == null || minTime <= time;
}

BAD:

containsValue(String value) {
  return getValues().contains(value);
}

GOOD:

get width => right - left;

GOOD:

bool ready(num time) => minTime == null || minTime <= time;

GOOD:

containsValue(String value) => getValues().contains(value);

prefer_final_fields

Private field could be final.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

class BadImmutable {
  var _label = 'hola mundo! BadImmutable'; // LINT
  var label = 'hola mundo! BadImmutable'; // OK
}

BAD:

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:

class GoodImmutable {
  final label = 'hola mundo! BadImmutable', bla = 5; // OK
  final _label = 'hola mundo! BadImmutable', _bla = 5; // OK
}

GOOD:

class GoodMutable {
  var _label = 'hola mundo! GoodMutable';

  void changeLabel() {
    _label = 'hello world! GoodMutable';
  }
}

BAD:

class AssignedInAllConstructors {
  var _label; // LINT
  AssignedInAllConstructors(this._label);
  AssignedInAllConstructors.withDefault() : _label = 'Hello';
}

GOOD:

class NotAssignedInAllConstructors {
  var _label; // OK
  NotAssignedInAllConstructors();
  NotAssignedInAllConstructors.withDefault() : _label = 'Hello';
}

prefer_final_in_for_each

Prefer final in for-each loop variable if reference is not reassigned.

This rule is available as of Dart 2.1.1.

This rule has a quick fix available.

Details

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:

for (var element in elements) { // LINT
  print('Element: $element');
}

GOOD:

for (final element in elements) {
  print('Element: $element');
}

GOOD:

for (var element in elements) {
  element = element + element;
  print('Element: $element');
}

prefer_final_locals

Prefer final for variable declarations if they are not reassigned.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Incompatible rules: unnecessary_final

Details

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:

void badMethod() {
  var label = 'hola mundo! badMethod'; // LINT
  print(label);
}

GOOD:

void goodMethod() {
  final label = 'hola mundo! goodMethod';
  print(label);
}

GOOD:

void mutableCase() {
  var label = 'hola mundo! mutableCase';
  print(label);
  label = 'hello world';
  print(label);
}

prefer_final_parameters

Prefer final for parameter declarations if they are not reassigned.

This rule is available as of Dart 2.14.0.

This rule has a quick fix available.

Incompatible rules: unnecessary_final, avoid_final_parameters

Details

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:

void badParameter(String label) { // LINT
  print(label);
}

GOOD:

void goodParameter(final String label) { // OK
  print(label);
}

BAD:

void badExpression(int value) => print(value); // LINT

GOOD:

void goodExpression(final int value) => print(value); // OK

BAD:

[1, 4, 6, 8].forEach((value) => print(value + 2)); // LINT

GOOD:

[1, 4, 6, 8].forEach((final value) => print(value + 2)); // OK

GOOD:

void mutableParameter(String label) { // OK
  print(label);
  label = 'Hello Linter!';
  print(label);
}

prefer_for_elements_to_map_fromIterable

Prefer ‘for’ elements when building maps from iterables.

This rule is available as of Dart 2.3.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

Map<String, WidgetBuilder>.fromIterable(
  kAllGalleryDemos,
  key: (demo) => '${demo.routeName}',
  value: (demo) => demo.buildRoute,
);

GOOD:

return {
  for (var demo in kAllGalleryDemos)
    '${demo.routeName}': demo.buildRoute,
};

GOOD:

// 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

Use forEach to only apply a function to all the elements.

This rule is available as of Dart 2.0.0.

Details

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:

for (final key in map.keys.toList()) {
  map.remove(key);
}

GOOD:

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.

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

Use a function declaration to bind a function to a name.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

void main() {
  var localFunction = () {
    ...
  };
}

GOOD:

void main() {
  localFunction() {
    ...
  }
}

prefer_generic_function_type_aliases

Prefer generic function type aliases.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

typedef void F();

GOOD:

typedef F = void Function();

prefer_if_elements_to_conditional_expressions

Prefer if elements to conditional expressions where possible.

This rule is available as of Dart 2.3.0.

This rule has a quick fix available.

Details

When building collections, it is preferable to use if elements rather than conditionals.

BAD:

var list = ['a', 'b', condition ? 'c' : null].where((e) => e != null).toList();

GOOD:

var list = ['a', 'b', if (condition) 'c'];

prefer_if_null_operators

Prefer using if null operators.

This rule is available as of Dart 2.4.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

PREFER using if null operators instead of null checks in conditional expressions.

BAD:

v = a == null ? b : a;

GOOD:

v = a ?? b;

prefer_initializing_formals

Use initializing formals when possible.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

DO use initializing formals when possible.

Using initializing formals when possible makes your code more terse.

BAD:

class Point {
  num x, y;
  Point(num x, num y) {
    this.x = x;
    this.y = y;
  }
}

GOOD:

class Point {
  num x, y;
  Point(this.x, this.y);
}

BAD:

class Point {
  num x, y;
  Point({num x, num y}) {
    this.x = x;
    this.y = y;
  }
}

GOOD:

class Point {
  num x, y;
  Point({this.x, 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:

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?).

class Bid {
 final int? amount;
 Bid(int this.amount);
 Bid.pass() : amount = null;
}

prefer_inlined_adds

Inline list item declarations where possible.

This rule is available as of Dart 2.3.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

Declare elements in list literals inline, rather than using add and addAll methods where possible.

BAD:

var l = ['a']..add('b')..add('c');
var l2 = ['a']..addAll(['b', 'c']);

GOOD:

var l = ['a', 'b', 'c'];
var l2 = ['a', 'b', 'c'];

prefer_int_literals

Prefer int literals over double literals.

This rule is available as of Dart 2.1.0.

This rule has a quick fix available.

Details

DO use int literals rather than the corresponding double literal.

BAD:

const double myDouble = 8.0;
final anotherDouble = myDouble + 7.0e2;
main() {
  someMethod(6.0);
}

GOOD:

const double myDouble = 8;
final anotherDouble = myDouble + 700;
main() {
  someMethod(6);
}

prefer_interpolation_to_compose_strings

Use interpolation to compose strings and values.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

'Hello, ' + person.name + ' from ' + person.city + '.';

GOOD:

'Hello, ${person.name} from ${person.city}.'

prefer_is_empty

Use isEmpty for Iterables and Maps.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

if (lunchBox.length == 0) return 'so hungry...';
if (words.length != 0) return words.join(' ');

GOOD:

if (lunchBox.isEmpty) return 'so hungry...';
if (words.isNotEmpty) return words.join(' ');

prefer_is_not_empty

Use isNotEmpty for Iterables and Maps.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

if (!sources.isEmpty) {
  process(sources);
}

GOOD:

if (todo.isNotEmpty) {
  sendResults(request, todo.isEmpty);
}

prefer_is_not_operator

Prefer is! operator.

This rule is available as of Dart 2.7.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

When checking if an object is not of a specified type, it is preferable to use the ‘is!’ operator.

BAD:

if (!(foo is Foo)) {
  ...
}

GOOD:

if (foo is! Foo) {
  ...
}

prefer_iterable_whereType

Prefer to use whereType on iterable.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

PREFER iterable.whereType<T>() over iterable.where((e) => e is T).

BAD:

iterable.where((e) => e is MyClass);

GOOD:

iterable.whereType<MyClass>();

prefer_mixin

Prefer using mixins.

This rule is available as of Dart 2.1.0.

Details

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:

class A {}
class B extends Object with A {}

OK:

mixin M {}
class C with M {}

prefer_null_aware_method_calls

Prefer null aware method calls.

This rule is available as of Dart 2.14.0.

Details

Instead of checking nullability of a function/method f before calling it you can use f?.call().

BAD:

if (f != null) f!();

GOOD:

f?.call();

prefer_null_aware_operators

Prefer using null aware operators.

This rule is available as of Dart 2.2.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

PREFER using null aware operators instead of null checks in conditional expressions.

BAD:

v = a == null ? null : a.b;

GOOD:

v = a?.b;

prefer_single_quotes

Only use double quotes for strings containing single quotes.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Incompatible rules: prefer_double_quotes

Details

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, its 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:

useStrings(
    "should be single quote",
    r"should be single quote",
    r"""should be single quotes""")

GOOD:

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

Use spread collections when possible.

This rule is available as of Dart 2.3.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

Widget build(BuildContext context) {
  return CupertinoPageScaffold(
    child: ListView(
      children: [
        Tab2Header(),
      ]..addAll(buildTab2Conversation()),
    ),
  );
}
var ints = [1, 2, 3];
print(['a']..addAll(ints.map((i) => i.toString()))..addAll(['c']));
var things;
var l = ['a']..addAll(things ?? const []);

GOOD:

Widget build(BuildContext context) {
  return CupertinoPageScaffold(
    child: ListView(
      children: [
        Tab2Header(),
        ...buildTab2Conversation(),
      ],
    ),
  );
}
var ints = [1, 2, 3];
print(['a', ...ints.map((i) => i.toString()), 'c');
var things;
var l = ['a', ...?things];

prefer_typing_uninitialized_variables

Prefer typing uninitialized variables and fields.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

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:

class BadClass {
  static var bar; // LINT
  var foo; // LINT

  void method() {
    var bar; // LINT
    bar = 5;
    print(bar);
  }
}

BAD:

void aFunction() {
  var bar; // LINT
  bar = 5;
  ...
}

GOOD:

class GoodClass {
  static var bar = 7;
  var foo = 42;
  int baz; // OK

  void method() {
    int baz;
    var bar = 5;
    ...
  }
}

provide_deprecation_message

Provide a deprecation message, via @Deprecated(“message”).

This rule is available as of Dart 2.2.0.

Rule sets: core, recommended, flutter

Details

DO specify a deprecation message (with migration instructions and/or a removal schedule) in the Deprecation constructor.

BAD:

@deprecated
void oldFunction(arg1, arg2) {}

GOOD:

@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

Document all public members.

This rule is available as of Dart 2.0.0.

Details

DO document all public members.

All non-overriding public members should be documented with /// doc-style comments.

BAD:

class Bad {
  void meh() { }
}

GOOD:

/// 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:

/// 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

Property getter recursively returns itself.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

Details

DON’T create recursive getters.

Recursive getters are getters which return themselves as a value. This is usually a typo.

BAD:

int get field => field; // LINT

BAD:

int get otherField {
  return otherField; // LINT
}

GOOD:

int get field => _field;

require_trailing_commas

Use trailing commas for all function calls and declarations.

This rule is available as of Dart 2.14.0.

This rule has a quick fix available.

Details

DO use trailing commas for all function calls and declarations unless the function call or definition, from the start of the function name up to the closing parenthesis, fits in a single line.

BAD:

void run() {
  method('does not fit on one line',
      'test test test test test test test test test test test');
}

GOOD:

void run() {
  method(
    'does not fit on one line',
    'test test test test test test test test test test test',
  );
}

EXCEPTION: If the final parameter/argument is positional (vs named) and is either a function literal implemented using curly braces, a literal map, a literal set or a literal array. This exception only applies if the final parameter does not fit entirely on one line.

NOTE: This lint rule assumes dart format has been run over the code and may produce false positives until that has happened.

sized_box_for_whitespace

SizedBox for whitespace.

This rule is available as of Dart 2.9.0.

Rule sets: flutter

This rule has a quick fix available.

Details

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:

Widget buildRow() {
  return Row(
    children: <Widget>[
      const MyLogo(),
      Container(width: 4),
      const Expanded(
        child: Text('...'),
      ),
    ],
  );
}

GOOD:

Widget buildRow() {
  return Row(
    children: const <Widget>[
      MyLogo(),
      SizedBox(width: 4),
      Expanded(
        child: Text('...'),
      ),
    ],
  );
}

sized_box_shrink_expand

Use SizedBox shrink and expand named constructors.

This rule is available as of Dart 2.16.0.

Details

Use SizedBox.shrink(...) and SizedBox.expand(...) constructors appropriately.

The SizedBox.shrink(...) and SizedBox.expand(...) constructors should be used instead of the more general SizedBox(...) constructor when the named constructors capture the intent of the code more succinctly.

Examples

BAD:

Widget buildLogo() {
  return SizedBox(
    height: 0,
    width: 0,
    child: const MyLogo(),
  );
}
Widget buildLogo() {
  return SizedBox(
    height: double.infinity,
    width: double.infinity,
    child: const MyLogo(),
  );
}

GOOD:

Widget buildLogo() {
  return SizedBox.shrink(
    child: const MyLogo(),
  );
}
Widget buildLogo() {
  return SizedBox.expand(
    child: const MyLogo(),
  );
}

slash_for_doc_comments

Prefer using /// for doc comments.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

From the style guide:

PREFER using /// for doc comments.

Although Dart supports two syntaxes of doc comments (/// and /**), we prefer using /// for doc comments.

GOOD:

/// 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

Sort child properties last in widget instance creations.

This rule is available as of Dart 2.4.0.

Rule sets: flutter

This rule has a quick fix available.

Details

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:

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:

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

Sort constructor declarations before other members.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

DO sort constructor declarations before other members.

BAD:

abstract class Visitor {
  double value;
  visitSomething(Something s);
  Visitor();
}

GOOD:

abstract class Animation<T> {
  const Animation(this.value);
  double value;
  void addListener(VoidCallback listener);
}

sort_unnamed_constructors_first

Sort unnamed constructor declarations first.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

DO sort unnamed constructor declarations first, before named ones.

BAD:

class _PriorityItem {
  factory _PriorityItem.forName(bool isStatic, String name, _MemberKind kind) => ...
  _PriorityItem(this.isStatic, this.kind, this.isPrivate);
  ...
}

GOOD:

abstract class CancelableFuture<T> implements Future<T>  {
  factory CancelableFuture(computation()) => ...
  factory CancelableFuture.delayed(Duration duration, [computation()]) => ...
  ...
}

super_goes_last

Place the super call last in a constructor initialization list.

This rule has been removed as of the latest Dart releases.

Details

From the style guide:

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:

View(Style style, List children)
    : super(style),
      _children = children {

GOOD:

View(Style style, List children)
    : _children = children,
      super(style) {

tighten_type_of_initializing_formals

Tighten type of initializing formal.

This rule is available as of Dart 2.12.0.

Details

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:

class A {
  A.c1(this.p) : assert(p != null);
  A.c2(this.p);
  final String? p;
}

GOOD:

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

Type annotate public APIs.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

From Effective Dart:

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:

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:

Future<bool> install(PackageId id, String destination) {
  // ...
}

With types, all of this is clarified.

type_init_formals

Don’t type annotate initializing formals.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

From the style guide:

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:

class Point {
  int x, y;
  Point(int this.x, int this.y);
}

GOOD:

class Point {
  int x, y;
  Point(this.x, this.y);
}

BAD:

class A {
  int a;
  A(this.a);
}

class B extends A {
  B(int super.a);
}

GOOD:

class A {
  int a;
  A(this.a);
}

class B extends A {
  B(super.a);
}

type_literal_in_constant_pattern

Don’t use constant patterns with type literals.

This rule is available as of Dart 3.0.0.

This rule has a quick fix available.

Details

If you meant to test if the object has type Foo, instead write Foo _.

BAD:

void f(Object? x) {
  if (x case num) {
    print('int or double');
  }
}

GOOD:

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:

void f(Object? x) {
  if (x case int) {
    print('int');
  }
}

GOOD:

void f(Object? x) {
  if (x case const (int)) {
    print('int');
  }
}

unawaited_futures

Future results in async function bodies must be awaited or marked unawaited using dart:async.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

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:

void main() async {
  doSomething(); // Likely a bug.
}

GOOD:

Future doSomething() => ...;

void main() async {
  await doSomething();

  unawaited(doSomething()); // Explicitly-ignored fire-and-forget.
}

unnecessary_await_in_return

Unnecessary await keyword in return.

This rule is available as of Dart 2.1.1.

Details

Avoid returning an awaited expression when the expression type is assignable to the function’s return type.

BAD:

Future<int> future;
Future<int> f1() async => await future;
Future<int> f2() async {
  return await future;
}

GOOD:

Future<int> future;
Future<int> f1() => future;
Future<int> f2() {
  return future;
}

unnecessary_brace_in_string_interps

Avoid using braces in interpolation when not needed.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

print("Hi, ${name}!");

GOOD:

print("Hi, $name!");

unnecessary_breaks

Don’t use explicit breaks when a break is implied.

This rule is available as of Dart 3.0.0.

This rule has a quick fix available.

Details

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 breaks at the end of non-empty switch case statements are unnecessary.

BAD:

switch (1) {
  case 1:
    print("one");
    break;
  case 2:
    print("two");
    break;
}

GOOD:

switch (1) {
  case 1:
    print("one");
  case 2:
    print("two");
}
switch (1) {
  case 1:
  case 2:
    print("one or two");
}
switch (1) {
  case 1:
    break;
  case 2:
    print("just two");
}

NOTE: This lint only reports unnecessary breaks in libraries with a language version of 3.0 or greater. Explicit breaks are still required in Dart 2.19 and below.

unnecessary_const

Avoid const keyword.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

AVOID repeating const keyword in a const context.

BAD:

class A { const A(); }
m(){
  const a = const A();
  final b = const [const A()];
}

GOOD:

class A { const A(); }
m(){
  const a = A();
  final b = const [A()];
}

unnecessary_constructor_name

Unnecessary .new constructor name.

This rule is available as of Dart 2.15.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

class A {
  A.new(); // LINT
}

var a = A.new(); // LINT

GOOD:

class A {
  A.ok();
}

var a = A();
var aa = A.ok();
var makeA = A.new;

unnecessary_final

Don’t use final for local variables.

This rule is available as of Dart 2.7.0.

This rule has a quick fix available.

Incompatible rules: prefer_final_locals, prefer_final_parameters

Details

Use var, not final, when declaring local variables.

Per Effective Dart, 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:

void badMethod() {
  final label = 'Final or var?';
  for (final char in ['v', 'a', 'r']) {
    print(char);
  }
}

GOOD:

void goodMethod() {
  var label = 'Final or var?';
  for (var char in ['v', 'a', 'r']) {
    print(char);
  }
}

unnecessary_getters_setters

Avoid wrapping fields in getters and setters just to be “safe”.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

From the style guide:

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:

class Box {
  var _contents;
  get contents => _contents;
  set contents(value) {
    _contents = value;
  }
}

GOOD:

class Box {
  var contents;
}

unnecessary_lambdas

Don’t create a lambda when a tear-off will do.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

DON’T create a lambda when a tear-off will do.

BAD:

names.forEach((name) {
  print(name);
});

GOOD:

names.forEach(print);

unnecessary_late

Don’t specify the late modifier when it is not needed.

This rule is available as of Dart 2.16.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

late String badTopLevel = '';

GOOD:

String goodTopLevel = '';

BAD:

class BadExample {
  static late String badStatic = '';
}

GOOD:

class GoodExample {
  late String goodStatic;
}

unnecessary_library_directive

Avoid library directives unless they have documentation comments or annotations.

This rule is available as of Dart 2.19.0.

This rule has a quick fix available.

Details

DO use library directives if you want to document a library and/or annotate a library.

BAD:

library;

GOOD:

/// This library does important things
library;
@TestOn('js')
library;

NOTE: Due to limitations with this lint, libraries with parts will not be flagged for unnecessary library directives.

unnecessary_new

Unnecessary new keyword.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

AVOID new keyword to create instances.

BAD:

class A { A(); }
m(){
  final a = new A();
}

GOOD:

class A { A(); }
m(){
  final a = A();
}

unnecessary_null_aware_assignments

Avoid null in null-aware assignment.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

AVOID null in null-aware assignment.

Using null on the right-hand side of a null-aware assignment effectively makes the assignment redundant.

BAD:

var x;
x ??= null;

GOOD:

var x;
x ??= 1;

unnecessary_null_aware_operator_on_extension_on_nullable

Unnecessary null aware operator on extension on a nullable type.

This rule is available as of Dart 2.18.0.

Details

Avoid null aware operators for members defined in an extension on a nullable type.

BAD:

extension E on int? {
  int m() => 1;
}
f(int? i) => i?.m();

GOOD:

extension E on int? {
  int m() => 1;
}
f(int? i) => i.m();

unnecessary_null_checks

Unnecessary null checks.

This rule is currently experimental and available as of Dart 2.12.0.

This rule has a quick fix available.

Details

DON’T apply a null check when a nullable value is accepted.

BAD:

f(int? i) {}
m() {
  int? j;
  f(j!);
}

GOOD:

f(int? i) {}
m() {
  int? j;
  f(j);
}

unnecessary_null_in_if_null_operators

Avoid using null in if null operators.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

AVOID using null as an operand in if null operators.

Using null in an if null operator is redundant, regardless of which side null is used on.

BAD:

var x = a ?? null;
var y = null ?? 1;

GOOD:

var x = a ?? 1;

unnecessary_nullable_for_final_variable_declarations

Use a non-nullable type for a final variable initialized with a non-nullable value.

This rule is available as of Dart 2.10.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

Use a non-nullable type for a final variable initialized with a non-nullable value.

BAD:

final int? i = 1;

GOOD:

final int i = 1;

unnecessary_overrides

Don’t override a method to do a super method invocation with the same parameters.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

This rule has a quick fix available.

Details

DON’T override a method to do a super method invocation with same parameters.

BAD:

class A extends B {
  @override
  void foo() {
    super.foo();
  }
}

GOOD:

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

Unnecessary parentheses can be removed.

This rule is available as of Dart 2.0.0.

This rule has a quick fix available.

Details

AVOID using parentheses when not needed.

BAD:

a = (b);

GOOD:

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

Unnecessary raw string.

This rule is available as of Dart 2.8.1.

This rule has a quick fix available.

Details

Use raw string only when needed.

BAD:

var s1 = r'a';

GOOD:

var s1 = 'a';
var s2 = r'$a';
var s3 = r'\a';

unnecessary_string_escapes

Remove unnecessary backslashes in strings.

This rule is available as of Dart 2.8.1.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

Remove unnecessary backslashes in strings.

BAD:

'this string contains 2 \"double quotes\" ';
"this string contains 2 \'single quotes\' ";

GOOD:

'this string contains 2 "double quotes" ';
"this string contains 2 'single quotes' ";

unnecessary_string_interpolations

Unnecessary string interpolation.

This rule is available as of Dart 2.8.1.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

DON’T use string interpolation if there’s only a string expression in it.

BAD:

String message;
String o = '$message';

GOOD:

String message;
String o = message;

unnecessary_this

Don’t access members with this unless avoiding shadowing.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

From the style guide:

DON’T use this when not needed to avoid shadowing.

BAD:

class Box {
  var value;
  void update(new_value) {
    this.value = new_value;
  }
}

GOOD:

class Box {
  var value;
  void update(new_value) {
    value = new_value;
  }
}

GOOD:

class Box {
  var value;
  void update(value) {
    this.value = value;
  }
}

unnecessary_to_list_in_spreads

Unnecessary toList() in spreads.

This rule is available as of Dart 2.18.0.

Details

Unnecessary toList() in spreads.

BAD:

children: <Widget>[
  ...['foo', 'bar', 'baz'].map((String s) => Text(s)).toList(),
]

GOOD:

children: <Widget>[
  ...['foo', 'bar', 'baz'].map((String s) => Text(s)),
]

unreachable_from_main

Unreachable top-level members in executable libraries.

This rule is currently experimental and available as of Dart 2.19.0.

Details

Top-level members in an executable library should be used directly inside this 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 files except to execute its main function.

BAD:

main() {}
void f() {}

GOOD:

main() {
  f();
}
void f() {}

use_colored_box

Use ColoredBox.

This rule is available as of Dart 2.17.0.

Details

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:

Widget buildArea() {
  return Container(
    color: Colors.blue,
    child: const Text('hello'),
  );
}

GOOD:

Widget buildArea() {
  return const ColoredBox(
    color: Colors.blue,
    child: Text('hello'),
  );
}

use_decorated_box

Use DecoratedBox.

This rule is available as of Dart 2.16.0.

This rule has a quick fix available.

Details

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:

Widget buildArea() {
  return Container(
    decoration: const BoxDecoration(
      color: Colors.blue,
      borderRadius: BorderRadius.all(
        Radius.circular(5),
      ),
    ),
    child: const Text('...'),
  );
}

GOOD:

Widget buildArea() {
  return const DecoratedBox(
    decoration: BoxDecoration(
      color: Colors.blue,
      borderRadius: BorderRadius.all(
        Radius.circular(5),
      ),
    ),
    child: Text('...'),
  );
}

use_enums

Use enums rather than classes that behave like enums.

This rule is available as of Dart 2.17.0.

This rule has a quick fix available.

Details

Classes that look like enumerations should be declared as enums.

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.

BAD:

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:

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

Prefer an 8-digit hexadecimal integer(0xFFFFFFFF) to instantiate Color.

This rule is available as of Dart 2.2.0.

Rule sets: flutter

This rule has a quick fix available.

Details

PREFER an 8-digit hexadecimal integer(0xFFFFFFFF) to instantiate Color. Colors have four 8-bit channels, which adds up to 32 bits, so Colors are described using a 32 bit integer.

BAD:

Color(1);
Color(0x000001);

GOOD:

Color(0x00000001);

use_function_type_syntax_for_parameters

Use generic function type syntax for parameters.

This rule is available as of Dart 2.1.1.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

Use generic function type syntax for parameters.

BAD:

Iterable<T> where(bool predicate(T element)) {}

GOOD:

Iterable<T> where(bool Function(T) predicate) {}

use_if_null_to_convert_nulls_to_bools

Use if-null operators to convert nulls to bools.

This rule is available as of Dart 2.13.0.

Details

From Effective Dart:

Use if-null operators to convert nulls to bools.

BAD:

if (nullableBool == true) {
}
if (nullableBool != false) {
}

GOOD:

if (nullableBool ?? false) {
}
if (nullableBool ?? true) {
}

use_is_even_rather_than_modulo

Prefer intValue.isOdd/isEven instead of checking the result of % 2.

This rule is available as of Dart 2.9.0.

Details

PREFER the use of intValue.isOdd/isEven to check for evenness.

BAD:

bool isEven = 1 % 2 == 0;
bool isOdd = 13 % 2 == 1;

GOOD:

bool isEven = 1.isEven;
bool isOdd = 13.isOdd;

use_late_for_private_fields_and_variables

Use late for private members with a non-nullable type.

This rule is currently experimental and available as of Dart 2.10.0.

Details

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:

int? _i;
m() {
  _i!.abs();
}

GOOD:

late int _i;
m() {
  _i.abs();
}

OK:

int? _i;
m() {
  _i?.abs();
  _i = null;
}

use_named_constants

Use predefined named constants.

This rule is available as of Dart 2.13.0.

Details

Where possible, use already defined const values.

BAD:

const Duration(seconds: 0);

GOOD:

Duration.zero;

use_raw_strings

Use raw string to avoid escapes.

This rule is available as of Dart 2.8.1.

This rule has a quick fix available.

Details

A raw string can be used to avoid escaping only backslashes and dollars.

BAD:

var s = 'A string with only \\ and \$';

GOOD:

var s = r'A string with only \ and $';

use_rethrow_when_possible

Use rethrow to rethrow a caught exception.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

This rule has a quick fix available.

Details

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:

try {
  somethingRisky();
} catch(e) {
  if (!canHandle(e)) throw e;
  handle(e);
}

GOOD:

try {
  somethingRisky();
} catch(e) {
  if (!canHandle(e)) rethrow;
  handle(e);
}

use_setters_to_change_properties

Use a setter for operations that conceptually change a property.

This rule is available as of Dart 2.0.0.

Details

DO use a setter for operations that conceptually change a property.

BAD:

rectangle.setWidth(3);
button.setVisible(false);

GOOD:

rectangle.width = 3;
button.visible = false;

use_string_buffers

Use string buffers to compose strings.

This rule is available as of Dart 2.0.0.

Details

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:

String foo() {
  final buffer = '';
  for (int i = 0; i < 10; i++) {
    buffer += 'a'; // LINT
  }
  return buffer;
}

GOOD:

String foo() {
  final buffer = StringBuffer();
  for (int i = 0; i < 10; i++) {
    buffer.write('a');
  }
  return buffer.toString();
}

use_string_in_part_of_directives

Use string in part of directives.

This rule is available as of Dart 2.19.0.

Details

From Effective Dart:

DO use strings in part of directives.

BAD:

part of my_library;

GOOD:

part of '../../my_library.dart';

use_super_parameters

Use super-initializer parameters where possible.

This rule is currently experimental and available as of Dart 2.17.0.

This rule has a quick fix available.

Details

“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:

class A {
  A({int? x, int? y});
}
class B extends A {
  B({int? x, int? y}) : super(x: x, y: y);
}

GOOD:

class A {
  A({int? x, int? y});
}
class B extends A {
  B({super.x, super.y});
}

use_test_throws_matchers

Use throwsA matcher instead of fail().

This rule is available as of Dart 2.14.0.

Details

Use the throwsA matcher instead of try-catch with fail().

BAD:

// 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:

// 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

Start the name of the method with to/_to or as/_as if applicable.

This rule is available as of Dart 2.0.0.

Details

From the Effective Dart:

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:

class Bar {
  Foo myMethod() {
    return Foo.from(this);
  }
}

GOOD:

class Bar {
  Foo toFoo() {
    return Foo.from(this);
  }
}

GOOD:

class Bar {
  Foo asFoo() {
    return Foo.from(this);
  }
}

void_checks

Don’t assign to void.

This rule is available as of Dart 2.0.0.

Rule sets: core, recommended, flutter

Details

DON’T assign to void.

BAD:

class A<T> {
  T value;
  void test(T arg) { }
}

void main() {
  A<void> a = A<void>();
  a.value = 1; // LINT
  a.test(1); // LINT
}

Pub rules

These rules identify possible issues around pub package setup.

depend_on_referenced_packages

Depend on referenced packages.

This rule is available as of Dart 2.14.0.

Rule sets: core, recommended, flutter

Details

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:

import 'package:a/a.dart';
dependencies:

GOOD:

import 'package:a/a.dart';
dependencies:
  a: ^1.0.0

package_names

Use lowercase_with_underscores for package names.

This rule is available as of Dart 2.0.0.

Rule sets: recommended, flutter

Details

From the Pubspec format description:

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.

secure_pubspec_urls

Use secure urls in pubspec.yaml.

This rule is available as of Dart 2.16.0.

Details

DO Use secure urls in pubspec.yaml.

Use https instead of http or git:.

BAD:

repository: http://github.com/dart-lang/example
git:
  url: git://github.com/dart-lang/example/example.git

GOOD:

repository: https://github.com/dart-lang/example

sort_pub_dependencies

Sort pub dependencies alphabetically.

This rule is available as of Dart 2.1.0.

Details

DO sort pub dependencies alphabetically (A to Z) in pubspec.yaml.

Sorting list of pub dependencies makes maintenance easier.