avoid_non_null_assertion_operator 1.8.0 copy "avoid_non_null_assertion_operator: ^1.8.0" to clipboard
avoid_non_null_assertion_operator: ^1.8.0 copied to clipboard

A custom lint package to forbid the non-null assertion operator (!).

example/main.dart

class A {
  String? nullable;
  int? counter;

  String getFieldSafeWithBang() {
    if (nullable != null) {
      return nullable!; // Allowed: Null check before using !
    }
    return "";
  }

  String getFieldUnsafe() {
    return nullable!; // Flagged: No null check before using !
  }
}

class B {
  String? field;
}

class C {
  B? b;
}

class D {
  String? name;
  D() {
    print(name!); // Flagged: No check in constructor
  }
  D.withCheck() {
    if (name != null) {
      print(name!); // Allowed: Check in constructor
    }
  }
}

class E {
  F? testF;
  E(this.testF);
}

class F {
  G testG;
  H? testH;
  F(this.testG, [this.testH]);
}

class H {
  F? testF;
  H(this.testF);
}

enum G { g_a, g_b, g_c }

F _createTaskAction(E task, int serviceUserId) {
  return F(G.g_c);
}

// --- Test Functions ---

void test1() {
  String? text;
  print(text!); // Flagged: No null check
}

void test2() {
  String? text;
  if (text != null) {
    print("Not null");
  }
  print(text!); // Flagged: Null check in different scope
}

void test3(String? outer, String? inner) {
  if (outer != null) {
    if (inner != null) {
      print(outer!); // Allowed: Outer is checked
      print(inner!); // Allowed: Inner is checked
    }
    print(outer!); // Allowed: Outer is checked
    print(inner!); // Flagged: Inner check in nested scope
  }
}

void test4(B b) {
  print(b.field!); // Flagged: No null check
  if (b.field != null) {
    print(b.field!); // Allowed: Checked
  }
}

void test5(C c) {
  print(c.b!.field!); // Flagged: Neither c.b nor field is checked
  if (c.b != null) {
    print(c.b!.field!); // Flagged: c.b is checked, but field isn’t
  }
  if (c.b != null && c.b!.field != null) {
    print(c.b!.field!); // Allowed: Both are checked
  }
}

void test6() {
  String? value;
  if (value != null && true) {
    print(value!); // Allowed: Value is checked
  }
  if (value == null || false) {
    print(value!); // Flagged: No guarantee value isn’t null
  }
}

void test7() {
  String? item;
  while (item != null) {
    print(item!); // Allowed: Checked in loop condition
  }
  print(item!); // Flagged: No check outside loop
}

String? getString() => null;

void test8() {
  print(getString()!); // Flagged: No null check on return value
  var result = getString();
  if (result != null) {
    print(result!); // Allowed: Checked
  }
}

void test9() {
  String? x;
  String y;
  if (x != null) {
    y = x!; // Allowed: Checked
  }
  y = x!; // Flagged: No check
}

void test10() {
  String? a;
  String? b;
  print((a! + b!)); // Flagged: Neither a nor b is checked
  if (a != null && b != null) {
    print((a! + b!)); // Allowed: Both checked
  }
}

void test12() {
  String? data;
  if (data != null) {
    print(data!); // Allowed: Checked
  } else {
    print(data!); // Flagged: Data is null in else
  }
}

void test13() {
  final Map<String, int> data = {};
  if (data.containsKey('test')) {
    var t = data['test'];
    print(t!); // Allowed: Map key check
  }
}

void test14() {
  String? value;
  var result =
      true ? value! : "default"; // Flagged: No check in conditional expression
  print(result);
}

void test15() {
  String? value;
  if (value != null) {
    var result = true
        ? value!
        : "default"; // Allowed: Check before conditional expression
    print(result);
  }
}

void test16() {
  String? value;
  var result = (value != null)
      ? value!
      : "default"; // Allowed: Check in conditional expression
  print(result);
}

void test17() {
  String? value;
  var result = (value != null)
      ? "default"
      : value!; // Flagged: No check in conditional expression
  print(result);
}

void test18() {
  String? value;
  String? other;
  var result = (value != null)
      ? value!
      : (other != null)
          ? other!
          : "default"; // Allowed: Both checked in nested conditional expression
  print(result);
}

void test19() {
  final Map<String, int> data = {};
  var result =
      data.containsKey('key1') ? data['key1']! : 0; // Allowed: Map key check
  var result2 = data.containsKey('key1')
      ? data['key2']! // Flagged: No check for 'key2'
      : 0;
  print(result);
}

String? test20(D testD) {
  if (testD.name == null) {
    return null;
  }

  return testD.name!; // Allowed: Check before return
}

void test21() {
  String? n = 'hello';
  final items = [
    'start',
    if (n != null) n!, // Allowed: Check in list literal
    if (n != null && n.isNotEmpty) n!, // Allowed: Check in list literal
    'end',
  ];
  print(items);
}

String? test22(D testD) {
  if (testD.name == null) {
    throw Error();
  }

  return testD.name!; // Allowed: Check before throw
}

String? test23(D testD) {
  if (testD.name == null) {
    return null;
  } else {
    return testD.name!; // Allowed: Check in else block
  }
}

void test24(List<String> elements) {
  Map<String, List<int>> grouped = {};
  for (var e in elements) {
    if (grouped.containsKey(e)) {
      grouped[e]!.add(1); // Allowed: Map key check in loop
    }
  }
}

void test25() {
  String? value;
  var result =
      (value == null) ? "" : value!; // Allowed: Check in conditional expression
  print(result);
}

void test26() {
  List<int>? l = null;

  if (l == null || l!.isEmpty) {
    // Allowed: Check in conditional expression
    print(l);
  }
}

void test27() {
  final List<A> testA = [];

  testA.map((e) =>
      e.counter != null &&
      e.counter! >= 0 &&
      e.counter! <= 10); // Allowed: Multiple checks
}

// TODO
// void test28(String? bar) {
//   if (bar == null) return;
//   print(bar!); // Allowed: Check before return
// }

// void test29(String? bar) {
//   if (identical(bar, null)) return;
//   print(bar!); // Allowed: Identical check
// }

// void test30(String? bar) {
//   if (bar is! String) return;
//   print(bar!); // Allowed: Type check
// }

// void test31(String? bar) {
//   if (bar?.isNotEmpty == true) {
//     print(bar!); // Allowed: Null-aware operator check
//   }
// }

// void testFunction(E task, dynamic event) {
//   F testFLocal = _createTaskAction(task, event.serviceUserId);

//   if (task.testF?.testH?.testF != null &&
//       (task.testF!.testG == G.g_a || task.testF!.testG == G.g_b)) {
//     final localTestTestF = task.testF!;
//     final testFHF = localTestTestF.testH!.testF!; // Allowed: Multiple checks
//   }
// }

void test32() {
  String? value;
  if (value == null) {
    return;
  }
  print(value!); // Allowed: Check before return
}

void test33() {
  String? value;
  if (value != null) {
    print(value!); // Allowed
  } else if (value == null) {
    return;
  }
  print(value!); // Flagged: value is null
}

void test34() {
  String? value;
  if (value == null) {
    print(value!); // Flagged: value is null
  }
}

void test35() {
  String? value;
  if (value != null) {
    print(value!); // Allowed
  }
  if (value == null) {
    return;
  }
  print(value!); // Allowed
}

void test36() {
  String? value;
  if (value == null) {
    return;
  }
  if (value != null) {
    print(value!); // Allowed
  }
}

void test37() {
  String? value;
  if (value != null) {
    print(value!); // Allowed
  }
  if (value != null) {
    print(value!); // Allowed
  }
}

void test38() {
  String? value;
  if (value == null) {
    return;
  }
  if (value == null) {
    return;
  }
  print(value!); // Allowed
}

void test39() {
  String? value;
  if (value != null) {
    print(value!); // Allowed
  } else if (value == null) {
    print(value!); // Flagged: value is null
  }
  print(value!); // Flagged: value is null
}

void main() {
  final A testA = A();

  print(testA.nullable!); // Flagged: No check

  if (testA.nullable != null) {
    print(testA.nullable!); // Allowed: Checked
  }
}
0
likes
50
points
1.18k
downloads

Publisher

unverified uploader

Weekly Downloads

A custom lint package to forbid the non-null assertion operator (!).

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

analyzer, custom_lint, custom_lint_builder

More

Packages that depend on avoid_non_null_assertion_operator