unnecessary-statements

Same as unnecessary_statements in Dart lints

Path
lint/correctness/unnecessary-statements
Default
On (recommended)
Origin
Dart lints
Rule
472 of 512
recommended

Flags expression statements whose expression has no clear effect.

A statement such as x;, 1 + 2;, list.clear; or c ? a : b; computes a value and throws it away, which usually means the author forgot a call, an assignment, or a return. Expressions with a clear effect are allowed: assignments, invocations, instance creations, await, throw, rethrow, cascades, as casts, postfix operators (x++, x!) and prefix ++/--. The right operand of &&, ||, and ??, and both branches of a conditional, are checked in turn, since those operators are used for control flow. A parenthesized expression is always reported, as are binary operations, index reads, literals, and is tests.

Identifiers and resolved property reads are reported unless they denote an explicitly declared getter, which may have side effects. Dynamic reads and unresolved identifiers are reported too. Applicable extension getters are allowed, while property reads of unavailable external members are conservatively left alone. The same checks apply to the initializer and updaters of a for (;;) loop with an expression initializer. A cascade section that reads a method or function-valued member (..clear) is reported. Constructor and generic function tear-offs are references without an effect. Reading a function's synthetic call member is also a tear-off, including null-aware reads and cascade sections; invoking it still has an effect.

void f(List<int> list, int a, int b) {
  a;          // flagged
  list.clear; // flagged
  a + b;      // flagged
  list.clear(); // ok
}

Invalid

example.dartdart
int topLevel = 0;

void topFunction() {}

int methodOne() => 1;

int methodTwo() => 2;

class Box {
  int value = 0;
  static int count = 0;

  void tick() {}

  void run(List<int> list, bool foo, int a, int b) {
    value;
    this.value;
    tick;
    Box.count;
    list..clear;
  }
}

void f(List<int> list, bool foo, int a, int b, Box box) {
  a;
  list.clear;
  1 + 2;
  methodOne() + methodTwo();
  foo ? a : b;
  topLevel;
  topFunction;
  box.value;
  box.tick;
  'string';
  list[0];
  a is int;
  -a;
  [1, 2];
  foo && a > 0;
  (methodOne());
  Box;
  for (a; a < 10; a + 1) {}
}

void dynamicReads(dynamic value) {
  value.missing;
  value.first.last;
  unknownName;
  unknownPrefix.member;
}

class MissingMember {
  void test() {
    this.missing;
  }
}

class FunctionValues {
  void Function() callback = () {};
  void Function() get getter => callback;
}

void functionCascades(FunctionValues value) {
  value..callback;
  value..getter;
}

extension BoxMethods on Box {
  void extensionMethod() {}
}

void extensionMethodTearoff(Box box) {
  box.extensionMethod;
}
Unnecessary statement.
15 void run(List<int> list, bool foo, int a, int b) {
16 value;
Unnecessary statement.
16 value;
17 this.value;
Unnecessary statement.
17 this.value;
18 tick;
Unnecessary statement.
18 tick;
19 Box.count;
Unnecessary statement.
19 Box.count;
20 list..clear;
Unnecessary statement.
24void f(List<int> list, bool foo, int a, int b, Box box) {
25 a;
Unnecessary statement.
25 a;
26 list.clear;
Unnecessary statement.
26 list.clear;
27 1 + 2;
Unnecessary statement.
27 1 + 2;
28 methodOne() + methodTwo();
Unnecessary statement.
28 methodOne() + methodTwo();
29 foo ? a : b;
Unnecessary statement.
28 methodOne() + methodTwo();
29 foo ? a : b;
Unnecessary statement.
29 foo ? a : b;
30 topLevel;
Unnecessary statement.
30 topLevel;
31 topFunction;
Unnecessary statement.
31 topFunction;
32 box.value;
Unnecessary statement.
32 box.value;
33 box.tick;
Unnecessary statement.
33 box.tick;
34 'string';
Unnecessary statement.
34 'string';
35 list[0];
Unnecessary statement.
35 list[0];
36 a is int;
Unnecessary statement.
36 a is int;
37 -a;
Unnecessary statement.
37 -a;
38 [1, 2];
Unnecessary statement.
38 [1, 2];
39 foo && a > 0;
Unnecessary statement.
39 foo && a > 0;
40 (methodOne());
Unnecessary statement.
40 (methodOne());
41 Box;
Unnecessary statement.
41 Box;
42 for (a; a < 10; a + 1) {}
Unnecessary statement.
41 Box;
42 for (a; a < 10; a + 1) {}
Unnecessary statement.
45void dynamicReads(dynamic value) {
46 value.missing;
Unnecessary statement.
46 value.missing;
47 value.first.last;
Unnecessary statement.
47 value.first.last;
48 unknownName;
Unnecessary statement.
48 unknownName;
49 unknownPrefix.member;
Unnecessary statement.
53 void test() {
54 this.missing;
Unnecessary statement.
63void functionCascades(FunctionValues value) {
64 value..callback;
Unnecessary statement.
64 value..callback;
65 value..getter;
Unnecessary statement.
72void extensionMethodTearoff(Box box) {
73 box.extensionMethod;

Valid

example.dartdart
int get topGetter => 0;

int methodOne() => 1;

int methodTwo() => 2;

class Some {
  const Some();

  int get computed => 1;

  void method() {}

  void run() {
    computed;
    this.computed;
  }
}

Future<void> f(List<int> list, Some some, bool foo, int? a, int b, Object o) async {
  some.method();
  const Some();
  Some();
  methodOne();
  methodTwo();
  foo ? methodOne() : methodTwo();
  foo && list.remove(1);
  a ?? methodOne();
  a = 3;
  b++;
  ++b;
  a!;
  o as int;
  await Future.value(1);
  list..add(1)..clear();
  some.computed;
  topGetter;
  for (var i = 0; i < b; i++) {}
}

int g(int x) {
  return x;
}

void h(Object e) {
  try {
    throw e;
  } catch (_) {
    rethrow;
  }
}

int arrow(int x) => x;

void annotatedLocalFunctions() {
  @pragma('vm:prefer-inline')
  void local() {}
  local();
}

abstract class GetterInterface {
  int get value;
}

class ForwardingGetter implements GetterInterface {
  @override
  dynamic noSuchMethod(Invocation invocation) => 0;
}

void inheritedGetter(ForwardingGetter value) {
  value.value;
}

void functionReturnGetter(GetterInterface Function() create) {
  final value = create();
  value.value;
}

void declaredForUpdates() {
  for (var i = 0; i < 1; i + 1) {}
}

extension<T> on Future<T> {
  void get unawaited {}
}

void extensionGetter(Future<void> Function() work) {
  // An extension getter may have side effects.
  work().then((_) {}).unawaited;
}

class Box {}

extension BoxEffects on Box {
  void get effect {}
}

void localExtensionGetter(Box box) {
  box.effect;
}

Configure unnecessary-statements

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "correctness": {
        "unnecessary-statements": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/correctness/unnecessary-statements: <reason>
  • unrelated-type-equality-checksunrelated_type_equality_checksrecommended

    Reports ==/!= comparisons and relational ==/!= patterns whose operand types are unrelated.

  • unused-codecheck-unused-codecross-file

    Report public top-level declarations that nothing references.

  • unused-dependenciescross-file

    Report regular pubspec dependencies with no Dart import or export in the analyzed package.

  • unused-filescheck-unused-filescross-file

    Report lib/ files that no project entrypoint can reach.

  • use-build-context-synchronouslyuse_build_context_synchronouslyrecommendedflutter

    Flags BuildContext use after an asynchronous gap without a mounted guard.

  • use-closest-build-contextrecommendedflutter

    Use the nearest BuildContext parameter inside nested callbacks.

  • use-key-in-widget-constructorsuse_key_in_widget_constructorsrecommendedflutter

    Require public widget constructors to accept or initialize a Flutter Key.

  • use-once-constructors-once-provideruse_once_constructors_once_providerflutter

    Require Riverpod once-providers to be created through .once().