Test potentially-nullable access errors
Change-Id: Ia166dbb6fb353120e30555f60b7bea186537b05b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/102242
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index a5e2927..1ea57d9 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -4660,8 +4660,8 @@
if (expression == null ||
!_isNonNullable ||
expression.staticType == null ||
- (expression.staticType as TypeImpl).nullabilitySuffix !=
- NullabilitySuffix.question) {
+ expression.staticType.isDynamic ||
+ !_typeSystem.isPotentiallyNullable(expression.staticType)) {
return false;
}
diff --git a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
index 19907e9..0fbc64d 100644
--- a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
@@ -219,6 +219,15 @@
''');
}
+ test_member_dynamic_nullable() async {
+ await assertNoErrorsInCode(r'''
+m() {
+ dynamic x;
+ x.foo;
+}
+''');
+ }
+
test_member_hashCode_nullable() async {
await assertNoErrorsInCode(r'''
m() {
@@ -273,6 +282,24 @@
''');
}
+ test_member_potentiallyNullable() async {
+ await assertErrorCodesInCode(r'''
+m<T extends int?>() {
+ T x;
+ x.isEven;
+}
+''', [StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE]);
+ }
+
+ test_member_potentiallyNullable_called() async {
+ await assertErrorCodesInCode(r'''
+m<T extends Function>() {
+ List<T?> x;
+ x.first();
+}
+''', [StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE]);
+ }
+
test_member_questionDot_nullable() async {
await assertNoErrorsInCode(r'''
m() {
diff --git a/tests/language_2/nnbd/static_errors/unchecked_use_of_nullable_test.dart b/tests/language_2/nnbd/static_errors/unchecked_use_of_nullable_test.dart
index a991f55..ce24941 100644
--- a/tests/language_2/nnbd/static_errors/unchecked_use_of_nullable_test.dart
+++ b/tests/language_2/nnbd/static_errors/unchecked_use_of_nullable_test.dart
@@ -9,7 +9,6 @@
int? x;
bool? cond;
List? list;
- dynamic dyn;
Function? func;
List<Function?> funcList;
Stream? stream;
@@ -51,8 +50,8 @@
cond != null; //# 33: ok
x?.isEven; //# 34: ok
x?.round(); //# 35: ok
- for(i in list) {}; //# 36: compile-time error
- await for(i in stream) {}; //# 37: compile-time error
+ for(var i in list) {}; //# 36: compile-time error
+ await for(var i in stream) {}; //# 37: compile-time error
assert(cond); //# 38: compile-time error
}
@@ -60,3 +59,148 @@
Iterable? iter;
yield* iter; //# 39: compile-time error
}
+
+void typeParametersNullableBounds<IQ extends int?, BQ extends bool?, LQ extends List?, FQ extends Function?, SQ extends Stream?>(
+ IQ x,
+ BQ cond,
+ LQ list,
+ FQ func,
+ List<FQ> funcList,
+ SQ stream,
+ ) async {
+ x.isEven; //# 40: compile-time error
+ x.round(); //# 41: compile-time error
+ x.toString(); //# 42: ok
+ x.hashCode; //# 43: ok
+ x.runtimeType; //# 44: ok
+ x.noSuchMethod(null); //# 45: ok
+ x + 1; //# 46: compile-time error
+ -x; //# 47: compile-time error
+ x++; //# 48: compile-time error
+ ++x; //# 49: compile-time error
+ x..isEven; //# 50: compile-time error
+ list[0]; //# 51: compile-time error
+ list[0] = 0; //# 52: compile-time error
+ x += 1; //# 53: compile-time error
+ x ??= null; //# 54: ok
+ x.round; //# 55: compile-time error
+ x.toString; //# 56: ok
+ x.noSuchMethod; //# 57: ok
+ func(); //# 58: compile-time error
+ funcList[0](); //# 59: compile-time error
+ funcList.single(); //# 60: compile-time error
+ throw x; //# 61: compile-time error
+ cond || true; //# 62: compile-time error
+ true || cond; //# 63: compile-time error
+ cond && true; //# 64: compile-time error
+ true && cond; //# 65: compile-time error
+ !cond; //# 66: compile-time error
+ cond ? null : null; //# 67: compile-time error
+ if (cond) {} //# 68: compile-time error
+ while (cond) {} //# 69: compile-time error
+ for (;cond;){} //# 70: compile-time error
+ do {} while (cond); //# 71: compile-time error
+ cond!; //# 72: ok
+ cond ?? null; //# 73: ok
+ cond == null; //# 74: ok
+ cond != null; //# 75: ok
+ x?.isEven; //# 76: ok
+ x?.round(); //# 77: ok
+ for(var i in list) {}; //# 78: compile-time error
+ await for(var i in stream) {}; //# 79: compile-time error
+ assert(cond); //# 39: compile-time error
+}
+
+void typeParametersNullableUses<I extends int, B extends bool, L extends List, F extends Function, S extends Stream>(
+ I? x,
+ B? cond,
+ L? list,
+ F? func,
+ List<F?> funcList,
+ S? stream,
+ ) async {
+ x.isEven; //# 80: compile-time error
+ x.round(); //# 81: compile-time error
+ x.toString(); //# 82: ok
+ x.hashCode; //# 83: ok
+ x.runtimeType; //# 84: ok
+ x.noSuchMethod(null); //# 85: ok
+ x + 1; //# 86: compile-time error
+ -x; //# 87: compile-time error
+ x++; //# 88: compile-time error
+ ++x; //# 89: compile-time error
+ x..isEven; //# 90: compile-time error
+ list[0]; //# 91: compile-time error
+ list[0] = 0; //# 92: compile-time error
+ x += 1; //# 93: compile-time error
+ x ??= null; //# 94: ok
+ x.round; //# 95: compile-time error
+ x.toString; //# 96: ok
+ x.noSuchMethod; //# 97: ok
+ func(); //# 98: compile-time error
+ funcList[0](); //# 99: compile-time error
+ funcList.single(); //# 100: compile-time error
+ throw x; //# 101: compile-time error
+ cond || true; //# 102: compile-time error
+ true || cond; //# 103: compile-time error
+ cond && true; //# 104: compile-time error
+ true && cond; //# 105: compile-time error
+ !cond; //# 106: compile-time error
+ cond ? null : null; //# 107: compile-time error
+ if (cond) {} //# 108: compile-time error
+ while (cond) {} //# 109: compile-time error
+ for (;cond;) {} //# 110: compile-time error
+ do {} while (cond); //# 111: compile-time error
+ cond!; //# 112: ok
+ cond ?? null; //# 113: ok
+ cond == null; //# 114: ok
+ cond != null; //# 115: ok
+ x?.isEven; //# 116: ok
+ x?.round(); //# 117: ok
+ for(var i in list) {}; //# 118: compile-time error
+ await for(var i in stream) {}; //# 119: compile-time error
+}
+
+void dynamicUses() async {
+ dynamic dyn;
+ dyn.isEven; //# 120: ok
+ dyn.round(); //# 121: ok
+ dyn.toString(); //# 122: ok
+ dyn.hashCode; //# 123: ok
+ dyn.runtimeType; //# 124: ok
+ dyn.noSuchMethod(null); //# 125: ok
+ dyn + 1; //# 126: ok
+ -dyn; //# 127: ok
+ dyn++; //# 128: ok
+ ++dyn; //# 129: ok
+ dyn..isEven; //# 130: ok
+ dyn[0]; //# 131: ok
+ dyn[0] = 0; //# 132: ok
+ dyn += 1; //# 133: ok
+ dyn ??= null; //# 134: ok
+ dyn.round; //# 135: ok
+ dyn.toString; //# 136: ok
+ dyn.noSuchMethod; //# 137: ok
+ dyn(); //# 138: ok
+ dyn[0](); //# 139: ok
+ dyn.single(); //# 140: ok
+ throw dyn; //# 141: ok
+ dyn || true; //# 142: ok
+ true || dyn; //# 143: ok
+ dyn && true; //# 144: ok
+ true && dyn; //# 145: ok
+ !dyn; //# 146: ok
+ dyn ? null : null; //# 147: ok
+ if (dyn) {} //# 148: ok
+ while (dyn) {} //# 149: ok
+ for (;dyn;) {} //# 150: ok
+ do {} while (dyn); //# 151: ok
+ dyn!; //# 152: ok
+ dyn ?? null; //# 153: ok
+ dyn == null; //# 154: ok
+ dyn != null; //# 155: ok
+ dyn?.isEven; //# 156: ok
+ dyn?.round(); //# 157: ok
+ for(var i in dyn) {}; //# 158: ok
+ await for(var i in dyn) {}; //# 159: ok
+}