blob: af821a0e6f44125cef44836b7b0c1b5bd6ad989c [file]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
import '../dart/resolution/node_text_expectations.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(InvalidUseOfNullValueTest);
defineReflectiveTests(UncheckedUseOfNullableValueTest);
defineReflectiveTests(UncheckedUseOfNullableValueInsideExtensionTest);
defineReflectiveTests(UpdateNodeTextExpectations);
});
}
@reflectiveTest
class InvalidUseOfNullValueTest extends PubPackageResolutionTest {
test_as() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Null x;
x as int;
//^^^^^^^^
// [diag.castFromNullAlwaysFails] This cast always throws an exception because the expression always evaluates to 'null'.
}
''');
}
test_await() async {
await resolveTestCodeWithDiagnostics(r'''
m() async {
Null x;
await x;
}
''');
}
test_cascade() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Null x;
x..toString;
}
''');
}
test_eq() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Null x;
x == null;
//^^^^
// [diag.unnecessaryNullComparisonAlwaysNullTrue] The operand must be 'null', so the condition is always 'true'.
}
''');
}
test_forLoop() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Null x;
for (var y in x) {}
// ^
// [diag.unusedLocalVariable] The value of the local variable 'y' isn't used.
// ^
// [diag.invalidUseOfNullValue] An expression whose value is always 'null' can't be dereferenced.
}
''');
}
test_is() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Null x;
x is int;
}
''');
}
test_member() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Null x;
x.runtimeType;
}
''');
}
test_method() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Null x;
x.toString();
}
''');
}
test_notEq() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Null x;
x != null;
//^^^^
// [diag.unnecessaryNullComparisonAlwaysNullFalse] The operand must be 'null', so the condition is always 'false'.
}
''');
}
test_ternary_lhs() async {
await resolveTestCodeWithDiagnostics(r'''
m(bool cond) {
Null x;
cond ? x : 1;
}
''');
}
test_ternary_rhs() async {
await resolveTestCodeWithDiagnostics(r'''
m(bool cond) {
Null x;
cond ? 0 : x;
}
''');
}
}
@reflectiveTest
class UncheckedUseOfNullableValueInsideExtensionTest
extends PubPackageResolutionTest {
test_indexExpression_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
int operator[](int index) => 0;
operator[]=(int index, int value) {}
}
extension E on A {
void bar() {
this[0];
this[0] = 0;
}
}
''');
}
test_indexExpression_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
int operator[](int index) => 0;
operator[]=(int index, int value) {}
}
extension E on A? {
void bar() {
this[0];
// ^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '[]' can't be unconditionally invoked because the receiver can be 'null'.
this?[0];
this[0] = 0;
// ^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '[]' can't be unconditionally invoked because the receiver can be 'null'.
this?[0] = 0;
}
}
''');
}
test_methodInvocation_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
void foo() {}
}
extension E on A {
void bar() {
foo();
this.foo();
bar();
this.bar();
}
}
''');
}
test_methodInvocation_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
void foo() {}
}
extension E on A? {
void bar() {
foo();
// ^^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'foo' can't be unconditionally invoked because the receiver can be 'null'.
this.foo();
// ^^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'foo' can't be unconditionally invoked because the receiver can be 'null'.
this?.foo();
bar();
this.bar();
this?.bar();
}
}
''');
}
test_methodInvocation_nuverNullable_extensionMethod() async {
await resolveTestCodeWithDiagnostics(r'''
extension<X> on X {
X m() => this;
}
Future<void> f(Never? x) async {
(await x).m();
}
''');
}
test_prefixExpression_minus_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
A operator-() => this;
}
extension E on A {
void bar() {
-this;
}
}
''');
}
test_prefixExpression_minus_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
A operator-() => this;
}
extension E on A? {
void bar() {
-this;
// ^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'unary-' can't be unconditionally invoked because the receiver can be 'null'.
}
}
''');
}
test_propertyAccess_getter_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
int get foo => 0;
}
extension E on A {
int get bar => 0;
void baz() {
foo;
this.foo;
bar;
this.bar;
}
}
''');
}
test_propertyAccess_getter_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
int get foo => 0;
}
extension E on A? {
int get bar => 0;
void baz() {
foo;
// ^^^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'foo' can't be unconditionally accessed because the receiver can be 'null'.
this.foo;
// ^^^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'foo' can't be unconditionally accessed because the receiver can be 'null'.
this?.foo;
bar;
this.bar;
this?.bar;
}
}
''');
}
test_propertyAccess_setter_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
set foo(int _) {}
}
extension E on A {
set bar(int _) {}
void baz() {
foo = 0;
this.foo = 0;
bar = 0;
this.bar = 0;
}
}
''');
}
test_propertyAccess_setter_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
set foo(int _) {}
}
extension E on A? {
set bar(int _) {}
void baz() {
foo = 0;
// ^^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'foo' can't be unconditionally invoked because the receiver can be 'null'.
this.foo = 0;
// ^^^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'foo' can't be unconditionally accessed because the receiver can be 'null'.
this?.foo = 0;
bar = 0;
this.bar = 0;
this?.bar = 0;
}
}
''');
}
}
@reflectiveTest
class UncheckedUseOfNullableValueTest extends PubPackageResolutionTest {
test_and_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool x = true;
if(x && true) {}
}
''');
}
test_and_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool? x;
if(x && true) {}
// ^
// [diag.uncheckedUseOfNullableValueAsCondition] A nullable expression can't be used as a condition.
}
''');
}
test_as_nullable_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
void f() {
num? x;
x as int;
//^
// [diag.castFromNullableAlwaysFails] This cast will always throw an exception because the nullable local variable 'x' is not assigned.
}
''');
}
test_as_nullable_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
void f() {
num? x;
x as String?;
}
''');
}
test_assert_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool x = true;
assert(x);
}
''');
}
test_assert_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool? x;
assert(x);
// ^
// [diag.uncheckedUseOfNullableValueAsCondition] A nullable expression can't be used as a condition.
}
''');
}
test_assignment_eq_propertyAccess3_short1() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
int x;
A(this.x);
}
class B {
final A? a;
B(this.a);
}
m(B b) {
b.a?.x = 1;
b.a.x = 2;
// ^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'x' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
var node1 = result.findNode.assignment('x = 1');
assertResolvedNodeText(node1, r'''
AssignmentExpression
leftHandSide2: PropertyAccess
target2: PrefixedIdentifier
prefix: SimpleIdentifier
token: b
element: <testLibrary>::@function::m::@formalParameter::b
staticType: B
period: .
identifier: SimpleIdentifier
token: a
element: <testLibrary>::@class::B::@getter::a
staticType: A?
element: <testLibrary>::@class::B::@getter::a
staticType: A?
operator: ?.
propertyName: SimpleIdentifier
token: x
element: <null>
staticType: null
staticType: null
operator: =
rightHandSide2: IntegerLiteral
literal: 1
correspondingParameter: <testLibrary>::@class::A::@setter::x::@formalParameter::value
staticType: int
readElement: <null>
readType: null
writeElement: <testLibrary>::@class::A::@setter::x
writeType: int
element: <null>
staticType: int?
''');
var node2 = result.findNode.assignment('x = 2');
assertResolvedNodeText(node2, r'''
AssignmentExpression
leftHandSide2: PropertyAccess
target2: PrefixedIdentifier
prefix: SimpleIdentifier
token: b
element: <testLibrary>::@function::m::@formalParameter::b
staticType: B
period: .
identifier: SimpleIdentifier
token: a
element: <testLibrary>::@class::B::@getter::a
staticType: A?
element: <testLibrary>::@class::B::@getter::a
staticType: A?
operator: .
propertyName: SimpleIdentifier
token: x
element: <null>
staticType: null
staticType: null
operator: =
rightHandSide2: IntegerLiteral
literal: 2
correspondingParameter: <testLibrary>::@class::A::@setter::x::@formalParameter::value
staticType: int
readElement: <null>
readType: null
writeElement: <testLibrary>::@class::A::@setter::x
writeType: int
element: <null>
staticType: int
''');
}
test_assignment_eq_simpleIdentifier() async {
var result = await resolveTestCodeWithDiagnostics(r'''
m(int x, int? y) {
x = 0;
y = 0;
}
''');
var node1 = result.findNode.assignment('x =');
assertResolvedNodeText(node1, r'''
AssignmentExpression
leftHandSide2: SimpleIdentifier
token: x
element: <testLibrary>::@function::m::@formalParameter::x
staticType: null
operator: =
rightHandSide2: IntegerLiteral
literal: 0
correspondingParameter: <null>
staticType: int
readElement: <null>
readType: null
writeElement: <testLibrary>::@function::m::@formalParameter::x
writeType: int
element: <null>
staticType: int
''');
var node2 = result.findNode.assignment('y =');
assertResolvedNodeText(node2, r'''
AssignmentExpression
leftHandSide2: SimpleIdentifier
token: y
element: <testLibrary>::@function::m::@formalParameter::y
staticType: null
operator: =
rightHandSide2: IntegerLiteral
literal: 0
correspondingParameter: <null>
staticType: int
readElement: <null>
readType: null
writeElement: <testLibrary>::@function::m::@formalParameter::y
writeType: int?
element: <null>
staticType: int
''');
}
test_assignment_plusEq_propertyAccess3() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
int x;
int? y;
A(this.x);
}
class B {
final A a;
B(this.a);
}
m(B b) {
b.a.x += 0;
b.a.y += 0;
// ^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '+' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
var node1 = result.findNode.assignment('x +=');
assertResolvedNodeText(node1, r'''
AssignmentExpression
leftHandSide2: PropertyAccess
target2: PrefixedIdentifier
prefix: SimpleIdentifier
token: b
element: <testLibrary>::@function::m::@formalParameter::b
staticType: B
period: .
identifier: SimpleIdentifier
token: a
element: <testLibrary>::@class::B::@getter::a
staticType: A
element: <testLibrary>::@class::B::@getter::a
staticType: A
operator: .
propertyName: SimpleIdentifier
token: x
element: <null>
staticType: null
staticType: null
operator: +=
rightHandSide2: IntegerLiteral
literal: 0
correspondingParameter: dart:core::@class::num::@method::+::@formalParameter::other
staticType: int
readElement: <testLibrary>::@class::A::@getter::x
readType: int
writeElement: <testLibrary>::@class::A::@setter::x
writeType: int
element: dart:core::@class::num::@method::+
staticType: int
''');
var node2 = result.findNode.assignment('y +=');
assertResolvedNodeText(node2, r'''
AssignmentExpression
leftHandSide2: PropertyAccess
target2: PrefixedIdentifier
prefix: SimpleIdentifier
token: b
element: <testLibrary>::@function::m::@formalParameter::b
staticType: B
period: .
identifier: SimpleIdentifier
token: a
element: <testLibrary>::@class::B::@getter::a
staticType: A
element: <testLibrary>::@class::B::@getter::a
staticType: A
operator: .
propertyName: SimpleIdentifier
token: y
element: <null>
staticType: null
staticType: null
operator: +=
rightHandSide2: IntegerLiteral
literal: 0
correspondingParameter: dart:core::@class::num::@method::+::@formalParameter::other
staticType: int
readElement: <testLibrary>::@class::A::@getter::y
readType: int?
writeElement: <testLibrary>::@class::A::@setter::y
writeType: int?
element: dart:core::@class::num::@method::+
staticType: int
''');
}
test_assignment_plusEq_propertyAccess3_short1() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
int x;
A(this.x);
}
class B {
final A? a;
B(this.a);
}
m(B b) {
b.a?.x += 1;
b.a.x += 2;
// ^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'x' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
var node1 = result.findNode.assignment('x += 1');
assertResolvedNodeText(node1, r'''
AssignmentExpression
leftHandSide2: PropertyAccess
target2: PrefixedIdentifier
prefix: SimpleIdentifier
token: b
element: <testLibrary>::@function::m::@formalParameter::b
staticType: B
period: .
identifier: SimpleIdentifier
token: a
element: <testLibrary>::@class::B::@getter::a
staticType: A?
element: <testLibrary>::@class::B::@getter::a
staticType: A?
operator: ?.
propertyName: SimpleIdentifier
token: x
element: <null>
staticType: null
staticType: null
operator: +=
rightHandSide2: IntegerLiteral
literal: 1
correspondingParameter: dart:core::@class::num::@method::+::@formalParameter::other
staticType: int
readElement: <testLibrary>::@class::A::@getter::x
readType: int
writeElement: <testLibrary>::@class::A::@setter::x
writeType: int
element: dart:core::@class::num::@method::+
staticType: int?
''');
var node2 = result.findNode.assignment('x += 2');
assertResolvedNodeText(node2, r'''
AssignmentExpression
leftHandSide2: PropertyAccess
target2: PrefixedIdentifier
prefix: SimpleIdentifier
token: b
element: <testLibrary>::@function::m::@formalParameter::b
staticType: B
period: .
identifier: SimpleIdentifier
token: a
element: <testLibrary>::@class::B::@getter::a
staticType: A?
element: <testLibrary>::@class::B::@getter::a
staticType: A?
operator: .
propertyName: SimpleIdentifier
token: x
element: <null>
staticType: null
staticType: null
operator: +=
rightHandSide2: IntegerLiteral
literal: 2
correspondingParameter: dart:core::@class::num::@method::+::@formalParameter::other
staticType: int
readElement: <testLibrary>::@class::A::@getter::x
readType: int
writeElement: <testLibrary>::@class::A::@setter::x
writeType: int
element: dart:core::@class::num::@method::+
staticType: int
''');
}
test_assignment_plusEq_simpleIdentifier() async {
var result = await resolveTestCodeWithDiagnostics(r'''
m(int x, int? y) {
x += 0;
y += 0;
// ^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '+' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
var node1 = result.findNode.assignment('x +=');
assertResolvedNodeText(node1, r'''
AssignmentExpression
leftHandSide2: SimpleIdentifier
token: x
element: <testLibrary>::@function::m::@formalParameter::x
staticType: null
operator: +=
rightHandSide2: IntegerLiteral
literal: 0
correspondingParameter: dart:core::@class::num::@method::+::@formalParameter::other
staticType: int
readElement: <testLibrary>::@function::m::@formalParameter::x
readType: int
writeElement: <testLibrary>::@function::m::@formalParameter::x
writeType: int
element: dart:core::@class::num::@method::+
staticType: int
''');
var node2 = result.findNode.assignment('y +=');
assertResolvedNodeText(node2, r'''
AssignmentExpression
leftHandSide2: SimpleIdentifier
token: y
element: <testLibrary>::@function::m::@formalParameter::y
staticType: null
operator: +=
rightHandSide2: IntegerLiteral
literal: 0
correspondingParameter: dart:core::@class::num::@method::+::@formalParameter::other
staticType: int
readElement: <testLibrary>::@function::m::@formalParameter::y
readType: int?
writeElement: <testLibrary>::@function::m::@formalParameter::y
writeType: int?
element: dart:core::@class::num::@method::+
staticType: int
''');
}
test_await_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() async {
Future x = Future.value(null);
await x;
}
''');
}
test_await_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() async {
Future? x;
await x;
}
''');
}
test_cascade_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
f() {
int x = 0;
x..isEven;
}
''');
}
test_cascade_nullable_indexed_assignment() async {
await resolveTestCodeWithDiagnostics(r'''
f(List<int>? x) {
x..[0] = 1;
// ^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '[]' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_cascade_nullable_indexed_assignment_null_aware() async {
await resolveTestCodeWithDiagnostics(r'''
f(List<int>? x) {
x?..[0] = 1;
}
''');
}
test_cascade_nullable_method_invocation() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x..abs();
// ^^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'abs' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_cascade_nullable_method_invocation_null_aware() async {
await resolveTestCodeWithDiagnostics(r'''
f(int? x) {
x?..abs();
}
''');
}
test_cascade_nullable_property_access() async {
await resolveTestCodeWithDiagnostics(r'''
f(int? x) {
x..isEven;
// ^^^^^^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'isEven' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
}
test_cascade_nullable_property_access_null_aware() async {
await resolveTestCodeWithDiagnostics(r'''
m(int? x) {
x?..isEven;
}
''');
}
test_eqEq_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x == null;
//^^^^
// [diag.unnecessaryNullComparisonAlwaysNullTrue] The operand must be 'null', so the condition is always 'true'.
}
''');
}
test_forLoop_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
List x = [];
for (var y in x) {}
// ^
// [diag.unusedLocalVariable] The value of the local variable 'y' isn't used.
}
''');
}
test_forLoop_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
List? x;
for (var y in x) {}
// ^
// [diag.unusedLocalVariable] The value of the local variable 'y' isn't used.
// ^
// [diag.uncheckedUseOfNullableValueAsIterator] A nullable expression can't be used as an iterator in a for-in loop.
}
''');
}
test_forLoop_pattern_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
List? x;
for (var (y) in x) {}
// ^
// [diag.unusedLocalVariable] The value of the local variable 'y' isn't used.
// ^
// [diag.uncheckedUseOfNullableValueAsIterator] A nullable expression can't be used as an iterator in a for-in loop.
}
''');
}
test_getter_nullable_nonNullableExtension() async {
await resolveTestCodeWithDiagnostics(r'''
extension E on int {
int get foo => 0;
}
m(int? x) {
x.foo;
// ^^^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'foo' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
}
test_if_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool x = true;
if (x) {}
}
''');
}
test_if_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool? x;
if (x) {}
// ^
// [diag.uncheckedUseOfNullableValueAsCondition] A nullable expression can't be used as a condition.
}
''');
}
test_index_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
List x = [1];
x[0];
}
''');
}
test_index_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
List? x;
x[0];
// ^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '[]' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_invoke_dynamicFunctionType_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Function x = () {};
x();
}
''');
}
test_invoke_dynamicFunctionType_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Function? x;
x();
//^
// [diag.uncheckedInvocationOfNullableValue] The function can't be unconditionally invoked because it can be 'null'.
}
''');
}
test_invoke_dynamicFunctionType_nullable2() async {
await resolveTestCodeWithDiagnostics(r'''
void f<F extends Function>(List<F?> funcList) {
funcList[0]();
//^^^^^^^^^^^
// [diag.uncheckedInvocationOfNullableValue] The function can't be unconditionally invoked because it can be 'null'.
}
''');
}
test_invoke_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Function() x = () {};
x();
}
''');
}
test_invoke_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Function()? x;
x();
//^
// [diag.uncheckedInvocationOfNullableValue] The function can't be unconditionally invoked because it can be 'null'.
}
''');
}
test_invoke_parenthesized_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
Function x = () {};
(x)();
}
''');
}
test_is_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x is int;
}
''');
}
test_member_dynamic_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
dynamic x;
x.foo;
}
''');
}
test_member_hashCode_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x.hashCode;
}
''');
}
test_member_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int x = 0;
x.isEven;
}
''');
}
test_member_nullable() async {
var result = await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x.isEven;
// ^^^^^^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'isEven' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
var node = result.findNode.simple('isEven;');
assertResolvedNodeText(node, r'''
SimpleIdentifier
token: isEven
element: dart:core::@class::int::@getter::isEven
staticType: bool
''');
}
test_member_parenthesized_hashCode_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
(x).hashCode;
}
''');
}
test_member_parenthesized_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
(x).isEven;
// ^^^^^^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'isEven' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
}
test_member_parenthesized_runtimeType_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
(x).runtimeType;
}
''');
}
test_member_potentiallyNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m<T extends int?>(T x) {
x.isEven;
// ^^^^^^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'isEven' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
}
test_member_potentiallyNullable_called() async {
await resolveTestCodeWithDiagnostics(r'''
m<T extends Function>(List<T?> x) {
x.first();
//^^^^^^^
// [diag.uncheckedInvocationOfNullableValue] The function can't be unconditionally invoked because it can be 'null'.
}
''');
}
test_member_questionDot_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
f(int? x) {
x?.isEven;
}
''');
}
test_member_runtimeType_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x.runtimeType;
}
''');
}
test_method_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int x = 0;
x.round();
}
''');
}
test_method_noSuchMethod_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(int x) {
x.noSuchMethod(throw '');
}
''');
}
test_method_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x.round();
// ^^^^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'round' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_method_nullable_notNullableExtension() async {
await resolveTestCodeWithDiagnostics(r'''
extension E on int {
void foo() {}
}
m(int? x) {
x.foo();
// ^^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'foo' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_method_questionDot_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(int? x) {
x?.round();
}
''');
}
test_method_toString_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(int x) {
x.toString();
}
''');
}
test_methodInvocation_call_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(Function x) {
x.call();
}
''');
}
test_methodInvocation_call_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(Function? x) {
x.call();
// ^^^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'call' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_minusEq_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int x = 0;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
x -= 1;
}
''');
}
test_minusEq_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
x -= 1;
// ^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '-' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_not_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool x = true;
if(!x) {}
// ^^
// [diag.deadCode] Dead code.
}
''');
}
test_not_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool? x;
if(!x) {}
// ^
// [diag.uncheckedUseOfNullableValueAsCondition] A nullable expression can't be used as a condition.
}
''');
}
test_notEq_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x != null;
//^^^^
// [diag.unnecessaryNullComparisonAlwaysNullFalse] The operand must be 'null', so the condition is always 'false'.
}
''');
}
test_nullable_dotQ_propertyAccess_dot_methodInvocation() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
int get foo => 0;
}
void f(A? a) {
a?.foo.abs();
}
''');
assertType(result.findNode.propertyAccess('.foo'), 'int');
assertType(result.findNode.methodInvocation('.abs()'), 'int?');
}
test_nullable_dotQ_propertyAccess_dot_propertyAccess() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
int get foo => 0;
}
void f(A? a) {
a?.foo.isEven;
}
''');
assertType(result.findNode.propertyAccess('.foo'), 'int');
assertType(result.findNode.propertyAccess('.isEven'), 'bool?');
}
test_operatorMinus_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int x = 0;
x - 3;
}
''');
}
test_operatorMinus_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x - 3;
// ^
// [diag.uncheckedOperatorInvocationOfNullableValue] The operator '-' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_operatorPlus_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int x = 0;
x + 3;
}
''');
}
test_operatorPlus_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
x + 3;
// ^
// [diag.uncheckedOperatorInvocationOfNullableValue] The operator '+' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_operatorPostfixDec_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int x = 0;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
x--;
}
''');
}
test_operatorPostfixDec_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
x--;
// ^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '-' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_operatorPostfixInc_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(int x) {
x++;
}
''');
}
test_operatorPostfixInc_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(int? x) {
x++;
// ^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '+' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_operatorPostfixInc_nullable_nonNullableExtension() async {
await resolveTestCodeWithDiagnostics(r'''
class A {}
extension E on A {
A operator +(int _) => this;
}
m(A? x) {
x++;
// ^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '+' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_operatorPrefixDec_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int x = 0;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
--x;
}
''');
}
test_operatorPrefixDec_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
--x;
//^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '-' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_operatorPrefixInc_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(int x) {
++x;
}
''');
}
test_operatorPrefixInc_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(int? x) {
++x;
//^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '+' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_operatorUnaryMinus_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int x = 0;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
-x;
}
''');
}
test_operatorUnaryMinus_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
int? x;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
-x;
//^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'unary-' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_operatorUnaryMinus_nullable_nonNullableExtension() async {
await resolveTestCodeWithDiagnostics(r'''
class A {}
extension E on A {
A operator -() => this;
}
m(A? x) {
-x;
//^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'unary-' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_or_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool x = true;
if(x || false) {}
// ^^^^^^^^
// [diag.deadCode] Dead code.
}
''');
}
test_or_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool? x;
if(x || false) {}
// ^
// [diag.uncheckedUseOfNullableValueAsCondition] A nullable expression can't be used as a condition.
}
''');
}
test_plusEq_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(int x) {
x += 1;
}
''');
}
test_plusEq_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(int? x) {
x += 1;
// ^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method '+' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_read_propertyAccess2_short1() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
final int x;
A(this.x);
}
m(A? a) {
a?.x; // 1
a.x; // 2
// ^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'x' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
var propertyAccess1 = result.findNode.propertyAccess('a?.x; // 1');
var propertyAccess2 = result.findNode.prefixed('a.x; // 2');
assertType(propertyAccess1.target2, 'A?');
assertType(propertyAccess2.prefix, 'A?');
assertType(propertyAccess1.propertyName, 'int');
assertType(propertyAccess2.identifier, 'int');
assertType(propertyAccess1, 'int?');
assertType(propertyAccess2, 'int');
}
test_read_propertyAccess3_short1() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
int x;
A(this.x);
}
class B {
final A? a;
B(this.a);
}
m(B b) {
b.a?.x; // 1
b.a.x; // 2
// ^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'x' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
var propertyAccess1 = result.findNode.propertyAccess('b.a?.x; // 1');
var propertyAccess2 = result.findNode.propertyAccess('b.a.x; // 2');
assertType(propertyAccess1.target2, 'A?');
assertType(propertyAccess2.target2, 'A?');
assertType(propertyAccess1.propertyName, 'int');
assertType(propertyAccess2.propertyName, 'int');
assertType(propertyAccess1, 'int?');
assertType(propertyAccess2, 'int');
}
test_read_propertyAccess3_short2() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
int x;
A(this.x);
}
class B {
final A a;
B(this.a);
}
m(B? b) {
b?.a.x; // 1
b.a.x; // 2
// ^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'a' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
var propertyAccess1 = result.findNode.propertyAccess('x; // 1');
var propertyAccess2 = result.findNode.propertyAccess('x; // 2');
assertType(propertyAccess1.target2, 'A');
assertType(propertyAccess2.target2, 'A');
assertType(propertyAccess1.propertyName, 'int');
assertType(propertyAccess2.propertyName, 'int');
assertType(propertyAccess1, 'int?');
assertType(propertyAccess2, 'int');
}
test_read_propertyAccess4_short1() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
int x;
A(this.x);
}
class B {
final A? a;
B(this.a);
}
class C {
final B b;
C(this.b);
}
m(C c) {
c.b.a?.x; // 1
c.b.a.x; // 2
// ^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'x' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
var propertyAccess1 = result.findNode.propertyAccess('x; // 1');
var propertyAccess2 = result.findNode.propertyAccess('x; // 2');
assertType(propertyAccess1.target2, 'A?');
assertType(propertyAccess2.target2, 'A?');
assertType(propertyAccess1.propertyName, 'int');
assertType(propertyAccess2.propertyName, 'int');
assertType(propertyAccess1, 'int?');
assertType(propertyAccess2, 'int');
}
test_read_propertyAccess4_short2() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
final int x;
A(this.x);
}
class B {
final A a;
B(this.a);
}
class C {
final B? b;
C(this.b);
}
m(C c) {
c.b?.a.x; // 1
c.b.a.x; // 2
// ^
// [diag.uncheckedPropertyAccessOfNullableValue] The property 'a' can't be unconditionally accessed because the receiver can be 'null'.
}
''');
var propertyAccess1 = result.findNode.propertyAccess('x; // 1');
var propertyAccess2 = result.findNode.propertyAccess('x; // 2');
var propertyAccess1t = propertyAccess1.target2 as PropertyAccess;
var propertyAccess2t = propertyAccess1.target2 as PropertyAccess;
assertType(propertyAccess1t.target2, 'B?');
assertType(propertyAccess2t.target2, 'B?');
assertType(propertyAccess1t, 'A');
assertType(propertyAccess2t, 'A');
assertType(propertyAccess1.propertyName, 'int');
assertType(propertyAccess2.propertyName, 'int');
assertType(propertyAccess1, 'int?');
assertType(propertyAccess2, 'int');
}
test_spread_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
var list = [];
[...list];
}
''');
}
test_spread_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
List? list;
[...list];
// ^^^^
// [diag.uncheckedUseOfNullableValueInSpread] A nullable expression can't be used in a spread.
}
''');
}
test_spread_nullable_question() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
List? list;
[...?list];
}
''');
}
test_ternary_condition_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() {
bool? x;
x ? 0 : 1;
//^
// [diag.uncheckedUseOfNullableValueAsCondition] A nullable expression can't be used as a condition.
}
''');
}
test_ternary_lhs_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(bool cond) {
int? x;
cond ? x : 1;
}
''');
}
test_ternary_rhs_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(bool cond) {
int? x;
cond ? 0 : x;
}
''');
}
test_tripleShift_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m(String? s) {
s?.length >>> 2;
// ^^^
// [diag.uncheckedOperatorInvocationOfNullableValue] The operator '>>>' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_uncheckedOperatorInvocation_relationalPattern() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int? x) {
if (x case > 0) {}
// ^
// [diag.uncheckedOperatorInvocationOfNullableValue] The operator '>' can't be unconditionally invoked because the receiver can be 'null'.
}
''');
}
test_uncheckedOperatorInvocation_relationalPattern_hasExtension() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int? x) {
if (x case > 0) {}
}
extension on int? {
bool operator >(int other) => true;
}
''');
}
test_yieldEach_nonNullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() sync* {
List<int> x = [];
yield* x;
}
''');
}
test_yieldEach_nullable() async {
await resolveTestCodeWithDiagnostics(r'''
m() sync* {
List<int>? x;
yield* x;
// ^
// [diag.uncheckedUseOfNullableValueInYieldEach] A nullable expression can't be used in a yield-each statement.
// [diag.yieldEachOfInvalidType] The type 'List<int>?' implied by the 'yield*' expression must be assignable to 'Iterable<dynamic>'.
}
''');
}
}