Contents

Linter rules

Contents

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.
pedantic (deprecated)
The deprecated set of rules previously used to match the rules used for all Google-internal Dart code. Consider migrating to one of the rule sets in the lints or flutter_lints packages. See Migrating from pedantic for more information on switching.

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.

Error rules

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

always_use_package_imports

Avoid relative imports for files in lib/.

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 withing the lib/ directory.

This is the opposite of ‘prefer_relative_imports’. Might be used with ‘avoid_relative_lib_imports’ to avoid relative imports of files within lib/ directory outside of it. (for example test/)

GOOD:

import 'package:foo/bar.dart';

import 'package:foo/baz.dart';

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

BAD:

import 'baz.dart';

import 'src/bag.dart'

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

...

avoid_dynamic_calls

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

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.

Rule sets: core, recommended, flutter

Details

AVOID empty else statements.

BAD:

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

avoid_print

Avoid print calls in production code.

Rule sets: flutter

Details

DO avoid print calls in production code.

BAD:

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

avoid_relative_lib_imports

Avoid relative imports for files in lib/.

Rule sets: core, recommended, flutter, pedantic

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.

GOOD:

import 'package:foo/bar.dart';

import 'baz.dart';

...

BAD:

import 'package:foo/bar.dart';

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

...

avoid_returning_null_for_future

Avoid returning null for Future.

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.

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.

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.

Rule sets: core, recommended, flutter, pedantic

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.

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.

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.

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

comment_references

Only reference in scope identifiers in doc comments.

Details

DO reference only in scope identifiers in doc comments.

If you surround things like variable, method, or type names in square brackets, then dartdoc 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,

GOOD:

/// Return the larger of [a] or [b].
int max_int(int a, int b) { ... }

On the other hand, assuming outOfScopeId is out of scope:

BAD:

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

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.

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.

GOOD:

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

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

diagnostic_describe_all_properties

DO reference all public properties in debug methods.

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

empty_statements

Avoid empty statements.

Rule sets: recommended, flutter

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

Rule sets: core, recommended, flutter

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

invariant_booleans

Conditions should not unconditionally evaluate to true or to false.

This rule is currently experimental.

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.

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.

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.

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 prefered to the equivalent for (;;).

GOOD:

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

no_adjacent_strings_in_list

Don’t use adjacent strings in list.

Details

DON’T use adjacent strings in list.

This can be sign of forgotten comma.

GOOD:

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

BAD:

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

no_duplicate_case_values

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

Rule sets: core, recommended, flutter, pedantic

Details

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

This is usually a typo or changed value of constant.

GOOD:

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

BAD:

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

no_logic_in_create_state

Don’t put any logic in createState.

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

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 withing the lib/ directory.

GOOD:

import 'bar.dart';

BAD:

import 'package:my_package/bar.dart';

prefer_void_to_null

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

Rule sets: recommended, flutter

Details

DO NOT 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).

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.

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

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

throw_in_finally

Avoid throw in finally block.

Details

AVOID throwing exceptions in finally blocks.

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

GOOD:

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

BAD:

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

unnecessary_statements

Avoid using unnecessary statements.

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.

Rule sets: core, recommended, flutter, pedantic

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.

Rule sets: pedantic

Details

AVOID

  • assigning directly to the href field of an AnchorElement
  • assigning directly to the src field of an EmbedElement, IFrameElement, ImageElement, 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.

Details

DO NOT 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 from a StatefulWidget, the mounted property must be checked after an asynchronous gap.

GOOD:

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

BAD:

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

GOOD:

class _MyWidgetState extends State<MyWidget> {
  ...

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

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

use_key_in_widget_constructors

Use key in widget constructors.

Rule sets: flutter

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({Key? key}) : super(key: key);
}

valid_regexps

Use valid regular expression syntax.

Rule sets: core, recommended, flutter, pedantic

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.

Rule sets: pedantic

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.

Details

From the flutter style guide:

DO separate the control structure expression from its statement.

Don’t put the statement part of an if, for, while, do on the same line as the expression, even if it is short. Doing so makes it unclear that there is relevant code there. This is especially important for early returns.

GOOD:

if (notReady)
  return;

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

while (condition)
  i += 1;

BAD:

if (notReady) return;

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

while (condition) i += 1;

always_put_required_named_parameters_first

Put required named parameters first.

Details

DO specify required on named parameter before other named parameters.

GOOD:

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

BAD:

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

GOOD:

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

BAD:

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

always_require_non_null_named_parameters

Specify @required on named parameters without defaults.

Rule sets: recommended, flutter, pedantic

Details

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

GOOD:

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

m2({a: 1}) {
  assert(a != null);
}

BAD:

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

NOTE: Only asserts at the start of the bodies will be taken into account.

always_specify_types

Specify type annotations.

Incompatible rules: avoid_types_on_closure_parameters, omit_local_variable_types

Details

From the flutter style guide:

DO specify type annotations.

Avoid var when specifying that a type is unknown and short-hands that elide type annotations. Use dynamic if you are being explicit that the type is unknown. Use Object if you are being explicit that you want an object that implements == and hashCode.

GOOD:

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

BAD:

var foo = 10;
final bar = Bar();
const 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.

Rule sets: recommended, flutter, pedantic

Details

DO annotate overridden methods and fields.

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

GOOD:

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

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

BAD:

class Cat {
  int get lives => 9;
}

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

avoid_annotating_with_dynamic

Avoid annotating with dynamic when not required.

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 is currently deprecated.

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;

DEPRECATED: This advice is no longer recommended.

The rule will be removed in a future Linter release.

avoid_bool_literals_in_conditional_expressions

Avoid bool literals in conditional expressions.

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.

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.

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.

Details

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.

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.

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.

GOOD:

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

BAD:

class B {
  String key;
  const B(this.key);
  @override
  operator ==(other) => other is B && other.key == key;
  @override
  int 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 B && other.key == key;
  @override
  int hashCode() => key.hashCode;
}

avoid_escaping_inner_quotes

Avoid escaping inner quotes by converting surrounding quotes.

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.

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

Incompatible rules: prefer_final_parameters

Details

AVOID declaring parameters as final.

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

GOOD:

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

BAD:

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

GOOD:

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

BAD:

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

GOOD:

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

BAD:

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

avoid_function_literals_in_foreach_calls

Avoid using forEach with a function literal.

Rule sets: recommended, flutter

Details

AVOID using forEach with a function literal.

BAD:

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

GOOD:

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

people.forEach(print);

avoid_implementing_value_types

Don’t implement classes that override ==.

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.

Rule sets: recommended, flutter, pedantic

Details

From effective dart:

DON’T explicitly initialize variables to null.

In Dart, a variable or field that is not explicitly initialized automatically gets initialized to null. This is reliably specified by the language. There’s no concept of “uninitialized memory” in Dart. Adding = null is redundant and unneeded.

GOOD:

int _nextId;

class LazyId {
  int _id;

  int get id {
    if (_nextId == null) _nextId = 0;
    if (_id == null) _id = _nextId++;

    return _id;
  }
}

BAD:

int _nextId = null;

class LazyId {
  int _id = null;

  int get id {
    if (_nextId == null) _nextId = 0;
    if (_id == null) _id = _nextId++;

    return _id;
  }
}

avoid_js_rounded_ints

Avoid JavaScript rounded ints.

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.

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.

Rule sets: recommended, flutter, pedantic

Details

DON’T check for null in custom == operators.

As null is a special type, no class 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 ==(other) =>
      other != null && other is Person && name == other.name;
}

GOOD:

class Person {
  final String name;

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

avoid_positional_boolean_parameters

Avoid positional boolean parameters.

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.

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.

Details

Avoid redundant argument values.

DON’T declare arguments with values that match the defaults for the corresponding parameter.

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.

Rule sets: recommended, flutter

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 dartdoc produces documentation. If the inherited method contains the name of the parameter (in square brackets), then dartdoc 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.

Rule sets: recommended, flutter, pedantic

Details

AVOID return types on setters.

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

GOOD:

set speed(int ms);

BAD:

void set speed(int ms);

avoid_returning_null

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

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.

Rule sets: recommended, flutter

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.

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.

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.

Rule sets: core, recommended, flutter, pedantic

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.

Rule sets: recommended, flutter, pedantic

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.

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.

Rule sets: flutter

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.

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.

Details

DO mark async functions to return Future.

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

BAD:

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

GOOD:

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

await_only_futures

Await only futures.

Rule sets: core, recommended, flutter, pedantic

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.

Rule sets: core, recommended, flutter, pedantic

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.

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.

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

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

constant_identifier_names

Prefer using lowerCamelCase for constant names.

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.

GOOD:

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

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

BAD:

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

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

curly_braces_in_flow_control_structures

DO use curly braces for all flow control structures.

Rule sets: core, recommended, flutter, pedantic

Details

DO use curly braces for all flow control structures.

Doing so avoids the dangling else problem.

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

BAD:

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

deprecated_consistency

Missing deprecated annotation.

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

directives_ordering

Adhere to Effective Dart Guide directives sorting conventions.

Details

DO follow the conventions in the Effective Dart Guide

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.

Details

Using values derived from the environment at compile-time, creates hidden global state and makes applications hard to understand and maintain.

DO NOT use fromEnvironment or hasEnvironment factory constructors.

BAD:

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

empty_catches

Avoid empty catch blocks.

Rule sets: core, recommended, flutter, pedantic

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.

Rule sets: recommended, flutter, pedantic

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.

GOOD:

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

BAD:

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

eol_at_end_of_file

Put a single newline at end of file.

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.

Rule sets: recommended, flutter

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.

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.

GOOD:

  • slider_menu.dart
  • file_system.dart

BAD:

  • SliderMenu.dart
  • filesystem.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.

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.

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/lib/src/internals.dart;

join_return_with_assignment

Join return statement with assignment when possible.

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.

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_names

Name libraries using lowercase_with_underscores.

Rule sets: recommended, flutter, pedantic

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.

GOOD:

library peg_parser;

BAD:

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.

Rule sets: recommended, flutter, pedantic

Details

DO use lowercase_with_underscores when specifying a library prefix.

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;

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;

library_private_types_in_public_api

Avoid using private types in public APIs.

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

GOOD:

f(String s) { ... }

BAD:

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

lines_longer_than_80_chars

Avoid lines longer than 80 characters.

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.

missing_whitespace_between_adjacent_strings

Missing whitespace between adjacent strings.

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.

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.

GOOD:

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

BAD:

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

no_leading_underscores_for_library_prefixes

Avoid leading underscores for library prefixes.

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.

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_runtimeType_toString

Avoid calling toString() on runtimeType.

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.

Rule sets: core, recommended, flutter

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.

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

null_check_on_nullable_type_parameter

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

This rule is currently experimental.

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.

Rule sets: recommended, flutter, pedantic

Details

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

Rule sets: pedantic

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.

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.

GOOD:

typedef Predicate = bool Function(item);

BAD:

abstract class Predicate {
  bool test(item);
}

only_throw_errors

Only throw instances of classes extending either Exception or Error.

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.

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.

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.

GOOD:

/// A Foo.
abstract class Foo {
  /// Start foo-ing.
  void start() => _start();

  _start();
}

BAD:

class Bar {
  void bar();
}

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.

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.

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.

Rule sets: recommended, flutter, pedantic

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

Details

DO put asserts in initializer list for constructors with only asserts in their body.

GOOD:

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

BAD:

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

prefer_asserts_with_message

Prefer asserts with message.

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 is currently deprecated.

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

DEPRECATED: In Dart 2, asserts no longer accept non-bool values so this rule is made redundant by the Dart analyzer’s basic checks and is no longer necessary.

The rule will be removed in a future Linter release.

prefer_collection_literals

Use collection literals when possible.

Rule sets: recommended, flutter, pedantic

Details

DO use collection literals when possible.

BAD:

var points = List();
var addresses = Map();
var uniqueNames = Set();
var ids = LinkedHashSet();
var coordinates = LinkedHashMap();

GOOD:

var points = [];
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.

Rule sets: recommended, flutter, pedantic

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.

Rule sets: flutter

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.

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

BAD:

class A {
  const A();
}

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

prefer_const_constructors_in_immutables

Prefer declaring const constructors on @immutable classes.

Rule sets: flutter

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.

GOOD:

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

BAD:

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

prefer_const_declarations

Prefer const over final for declarations.

Rule sets: flutter

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.

GOOD:

const o = <int>[];

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

BAD:

final o = const <int>[];

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

prefer_const_literals_to_create_immutables

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

Rule sets: flutter

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.

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.

Rule sets: recommended, flutter, pedantic

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.

GOOD:

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

BAD:

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

prefer_double_quotes

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

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.

Rule sets: recommended, flutter, pedantic

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.

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.

Rule sets: recommended, flutter, pedantic

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.

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.

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.

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.

Rule sets: recommended, flutter, pedantic

Details

When building maps from iterables, it is preferable to use for elements.

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

prefer_foreach

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

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.

Rule sets: recommended, flutter

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.

Rule sets: core, recommended, flutter, pedantic

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.

Details

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

BAD:

Widget build(BuildContext context) {
  return Row(
    children: [
      IconButton(icon: Icon(Icons.menu)),
      Expanded(child: title),
      isAndroid ? IconButton(icon: Icon(Icons.search)) : null,
    ].where((child) => child != null).toList(),
  );
}

GOOD:

Widget build(BuildContext context) {
  return Row(
    children: [
      IconButton(icon: Icon(Icons.menu)),
      Expanded(child: title),
      if (isAndroid) IconButton(icon: Icon(Icons.search)),
    ]
  );
}

prefer_if_null_operators

Prefer using if null operators.

Rule sets: recommended, flutter, pedantic

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.

Rule sets: recommended, flutter

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

prefer_inlined_adds

Inline list item declarations where possible.

Rule sets: recommended, flutter, pedantic

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 2 = ['a', 'b', 'c'];

prefer_int_literals

Prefer int literals over double literals.

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.

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, ' + name + '! You are ' + (year - birth) + ' years old.';

GOOD:

'Hello, $name! You are ${year - birth} years old.';

prefer_is_empty

Use isEmpty for Iterables and Maps.

Rule sets: core, recommended, flutter, pedantic

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.

GOOD:

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

BAD:

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

prefer_is_not_empty

Use isNotEmpty for Iterables and Maps.

Rule sets: core, recommended, flutter, pedantic

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.

GOOD:

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

BAD:

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

prefer_is_not_operator

Prefer is! operator.

Rule sets: recommended, flutter

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.

Rule sets: core, recommended, flutter, pedantic

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.

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.

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.

Rule sets: recommended, flutter

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.

Rule sets: pedantic

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.

Rule sets: recommended, flutter, pedantic

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.

Rule sets: core, recommended, flutter

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

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.

Details

DO document all public members.

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

GOOD:

/// A good thing.
abstract class Good {
  /// Start doing your thing.
  void start() => _start();

  _start();
}

BAD:

class Bad {
  void meh() { }
}

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

Rule sets: recommended, flutter, pedantic

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

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.

GOOD:

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

BAD:

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.

Rule sets: flutter

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.

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.

Rule sets: recommended, flutter, pedantic

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.

Rule sets: pedantic

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.

Details

DO sort constructor declarations before other members.

GOOD:

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

BAD:

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

sort_unnamed_constructors_first

Sort unnamed constructor declarations first.

Details

DO sort unnamed constructor declarations first, before named ones.

GOOD:

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

BAD:

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

super_goes_last

Place the super call last in a constructor initialization list.

This rule is currently deprecated.

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.

GOOD:

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

BAD:

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

DEPRECATED: In Dart 2, it is a compile-time error if a superinitializer appears in an initializer list at any other position than at the end so this rule is made redundant by the Dart analyzer’s basic checks and is no longer necessary.

The rule will be removed in a future Linter release.

tighten_type_of_initializing_formals

Tighten type of initializing formal.

Details

Tighten type of 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) : assert(p != null);
  A.c2(this.p);
  final String? p;
}

type_annotate_public_apis

Type annotate public APIs.

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.

Rule sets: recommended, flutter, pedantic

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.

GOOD:

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

BAD:

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

unawaited_futures

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

Rule sets: pedantic

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.

GOOD:

Future doSomething() => ...;

void main() async {
  await doSomething();

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

BAD:

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

unnecessary_await_in_return

Unnecessary await keyword in return.

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.

Rule sets: recommended, flutter, pedantic

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.

GOOD:

print("Hi, $name!");

BAD:

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

unnecessary_const

Avoid const keyword.

Rule sets: recommended, flutter, pedantic

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.

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.

Incompatible rules: prefer_final_locals, prefer_final_parameters

Details

DON’T use final for local variables.

var is shorter, and final does not change the meaning of the code.

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

Rule sets: recommended, flutter, pedantic

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.

GOOD:

class Box {
  var contents;
}

BAD:

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

unnecessary_lambdas

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

Details

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

BAD:

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

GOOD:

names.forEach(print);

unnecessary_new

Unnecessary new keyword.

Rule sets: recommended, flutter, pedantic

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.

Details

AVOID null in null-aware assignment.

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

GOOD:

var x;
x ??= 1;

BAD:

var x;
x ??= null;

unnecessary_null_checks

Unnecessary null checks.

This rule is currently experimental.

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.

Rule sets: recommended, flutter, pedantic

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.

GOOD:

var x = a ?? 1;

BAD:

var x = a ?? null;
var y = null ?? 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 currently experimental.

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.

Rule sets: core, recommended, flutter

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 method,
  • 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.

noSuchMethod is a special method and is not checked by this rule.

unnecessary_parenthesis

Unnecessary parenthesis can be removed.

Details

AVOID using parenthesis when not needed.

GOOD:

a = b;

BAD:

a = (b);

unnecessary_raw_strings

Unnecessary raw string.

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.

Rule sets: recommended, flutter

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.

Rule sets: recommended, flutter

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.

Rule sets: recommended, flutter, pedantic

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

use_decorated_box

Use DecoratedBox.

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_full_hex_values_for_flutter_colors

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

Rule sets: flutter, pedantic

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.

Rule sets: recommended, flutter, pedantic

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.

Details

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.

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 non-nullable type.

This rule is currently experimental.

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

use_named_constants

Use predefined named constants.

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.

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.

Rule sets: recommended, flutter, pedantic

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.

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.

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_test_throws_matchers

Use throwsA matcher instead of fail().

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.

Details

From the design guide:

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.

Rule sets: core, recommended, flutter

Details

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

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.

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.

Details

DO Use secure urls in pubspec.yaml.

Use https instead of http an git:.

GOOD:

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

BAD:

repository: 'http://github.com/dart-lang/example'

sort_pub_dependencies

Sort pub dependencies.

Details

DO sort pub dependencies in pubspec.yaml.

Sorting list of pub dependencies makes maintenance easier.