Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 69387f9

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Issue 43268. Report warnings for Ext(c)?.foo() when 'c' is non-nullable.
Bug: dart-lang/sdk#43268 Change-Id: I8b36e3e112eb91dc5d56e98f657f2c77bf761ada Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/161143 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
1 parent 96d2c2d commit 69387f9

File tree

3 files changed

+131
-40
lines changed

3 files changed

+131
-40
lines changed

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -834,13 +834,10 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
834834
checkIndexExpression(node.auxiliaryElements?.staticElement);
835835

836836
if (node.isNullAware) {
837-
var target = node.realTarget;
838-
if (_isExpressionWithType(target)) {
839-
_checkForUnnecessaryNullAware(
840-
target,
841-
node.question ?? node.period ?? node.leftBracket,
842-
);
843-
}
837+
_checkForUnnecessaryNullAware(
838+
node.realTarget,
839+
node.question ?? node.period ?? node.leftBracket,
840+
);
844841
}
845842
super.visitIndexExpression(node);
846843
}
@@ -934,9 +931,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
934931
_checkForStaticAccessToInstanceMember(typeReference, methodName);
935932
_checkForInstanceAccessToStaticMember(
936933
typeReference, node.target, methodName);
937-
if (_isExpressionWithType(target)) {
938-
_checkForUnnecessaryNullAware(target, node.operator);
939-
}
934+
_checkForUnnecessaryNullAware(target, node.operator);
940935
} else {
941936
_checkForUnqualifiedReferenceToNonLocalStaticMember(methodName);
942937
}
@@ -1039,9 +1034,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
10391034
_checkForStaticAccessToInstanceMember(typeReference, propertyName);
10401035
_checkForInstanceAccessToStaticMember(
10411036
typeReference, node.target, propertyName);
1042-
if (_isExpressionWithType(target)) {
1043-
_checkForUnnecessaryNullAware(target, node.operator);
1044-
}
1037+
_checkForUnnecessaryNullAware(target, node.operator);
10451038

10461039
super.visitPropertyAccess(node);
10471040
}
@@ -4364,33 +4357,37 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
43644357
var type = operator.type;
43654358
if (type == TokenType.QUESTION_PERIOD) {
43664359
var realTarget = target.realTarget;
4367-
if (_isExpressionWithType(realTarget)) {
4368-
return previousShortCircuitingOperator(realTarget) ?? operator;
4369-
}
4360+
return previousShortCircuitingOperator(realTarget) ?? operator;
43704361
}
43714362
} else if (target is IndexExpression) {
43724363
if (target.question != null) {
43734364
var realTarget = target.realTarget;
4374-
if (_isExpressionWithType(realTarget)) {
4375-
return previousShortCircuitingOperator(realTarget) ??
4376-
target.question;
4377-
}
4365+
return previousShortCircuitingOperator(realTarget) ?? target.question;
43784366
}
43794367
} else if (target is MethodInvocation) {
43804368
var operator = target.operator;
43814369
var type = operator?.type;
43824370
if (type == TokenType.QUESTION_PERIOD) {
43834371
var realTarget = target.realTarget;
4384-
if (_isExpressionWithType(realTarget)) {
4385-
return previousShortCircuitingOperator(realTarget) ?? operator;
4386-
}
4387-
return operator;
4372+
return previousShortCircuitingOperator(realTarget) ?? operator;
43884373
}
43894374
}
43904375
return null;
43914376
}
43924377

4393-
if (_typeSystem.isStrictlyNonNullable(target.staticType)) {
4378+
var targetType = target.staticType;
4379+
if (target is ExtensionOverride) {
4380+
var arguments = target.argumentList.arguments;
4381+
if (arguments.length == 1) {
4382+
targetType = arguments[0].staticType;
4383+
} else {
4384+
return;
4385+
}
4386+
} else if (targetType == null) {
4387+
return;
4388+
}
4389+
4390+
if (_typeSystem.isStrictlyNonNullable(targetType)) {
43944391
if (errorCode == StaticWarningCode.INVALID_NULL_AWARE_OPERATOR) {
43954392
var previousOperator = previousShortCircuitingOperator(target);
43964393
if (previousOperator != null) {
@@ -5331,20 +5328,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
53315328
}
53325329
return null;
53335330
}
5334-
5335-
static bool _isExpressionWithType(Expression node) {
5336-
if (node is ExtensionOverride) {
5337-
return false;
5338-
}
5339-
5340-
// For `foo?.bar`, `foo` must be an identifier with a value.
5341-
if (node is Identifier) {
5342-
var element = node.staticElement;
5343-
return element is PropertyAccessorElement || element is VariableElement;
5344-
}
5345-
5346-
return true;
5347-
}
53485331
}
53495332

53505333
/// A record of the elements that will be declared in some scope (block), but

pkg/analyzer/test/src/diagnostics/invalid_null_aware_operator_test.dart

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,88 @@ void f(String? s) {
8989
@reflectiveTest
9090
class InvalidNullAwareOperatorTest extends PubPackageResolutionTest
9191
with WithNullSafetyMixin {
92+
test_extensionOverride_assignmentExpression_indexExpression() async {
93+
await assertErrorsInCode('''
94+
extension E on int {
95+
operator[]=(int index, bool _) {}
96+
}
97+
98+
void f(int? a, int b) {
99+
E(a)?[0] = true;
100+
E(b)?[0] = true;
101+
}
102+
''', [
103+
error(StaticWarningCode.INVALID_NULL_AWARE_OPERATOR, 109, 2),
104+
]);
105+
}
106+
107+
test_extensionOverride_assignmentExpression_propertyAccess() async {
108+
await assertErrorsInCode('''
109+
extension E on int {
110+
set foo(bool _) {}
111+
}
112+
113+
void f(int? a, int b) {
114+
E(a)?.foo = true;
115+
E(b)?.foo = true;
116+
}
117+
''', [
118+
error(StaticWarningCode.INVALID_NULL_AWARE_OPERATOR, 95, 2),
119+
]);
120+
}
121+
122+
test_extensionOverride_indexExpression() async {
123+
await assertErrorsInCode('''
124+
extension E on int {
125+
bool operator[](int index) => true;
126+
}
127+
128+
void f(int? a, int b) {
129+
E(a)?[0];
130+
E(b)?[0];
131+
}
132+
''', [
133+
error(StaticWarningCode.INVALID_NULL_AWARE_OPERATOR, 104, 2),
134+
]);
135+
assertType(findNode.index('E(a)'), 'bool?');
136+
assertType(findNode.index('E(b)'), 'bool?');
137+
}
138+
139+
test_extensionOverride_methodInvocation() async {
140+
await assertErrorsInCode('''
141+
extension E on int {
142+
bool foo() => true;
143+
}
144+
145+
void f(int? a, int b) {
146+
E(a)?.foo();
147+
E(b)?.foo();
148+
}
149+
''', [
150+
error(StaticWarningCode.INVALID_NULL_AWARE_OPERATOR, 91, 2),
151+
]);
152+
153+
assertType(findNode.methodInvocation('E(a)'), 'bool?');
154+
assertType(findNode.methodInvocation('E(b)'), 'bool?');
155+
}
156+
157+
test_extensionOverride_propertyAccess() async {
158+
await assertErrorsInCode('''
159+
extension E on int {
160+
bool get foo => true;
161+
}
162+
163+
void f(int? a, int b) {
164+
E(a)?.foo;
165+
E(b)?.foo;
166+
}
167+
''', [
168+
error(StaticWarningCode.INVALID_NULL_AWARE_OPERATOR, 91, 2),
169+
]);
170+
assertType(findNode.propertyAccess('E(a)'), 'bool?');
171+
assertType(findNode.propertyAccess('E(b)'), 'bool?');
172+
}
173+
92174
test_getter_class() async {
93175
await assertNoErrorsInCode('''
94176
class C {

pkg/analyzer/test/src/diagnostics/unnecessary_non_null_assertion_test.dart

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,33 @@ f() {
3131
''');
3232
}
3333

34-
test_nonNull() async {
34+
test_nonNull_function() async {
35+
await assertErrorsInCode('''
36+
void g() {}
37+
38+
void f() {
39+
g!();
40+
}
41+
''', [
42+
error(StaticWarningCode.UNNECESSARY_NON_NULL_ASSERTION, 27, 1),
43+
]);
44+
}
45+
46+
test_nonNull_method() async {
47+
await assertErrorsInCode('''
48+
class A {
49+
static void foo() {}
50+
}
51+
52+
void f() {
53+
A.foo!();
54+
}
55+
''', [
56+
error(StaticWarningCode.UNNECESSARY_NON_NULL_ASSERTION, 54, 1),
57+
]);
58+
}
59+
60+
test_nonNull_parameter() async {
3561
await assertErrorsInCode('''
3662
f(int x) {
3763
x!;

0 commit comments

Comments
 (0)