Skip to content

Commit 220aac2

Browse files
srawlinsCommit Queue
authored andcommitted
analyzer: Detect and report more cases of omitted args for Deprecated.optional parameters
Change-Id: I654a3b3bc5bea9c44368345bdd869c1d922e8178 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/451980 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 7185e85 commit 220aac2

File tree

3 files changed

+93
-7
lines changed

3 files changed

+93
-7
lines changed

pkg/analyzer/lib/src/error/best_practices_verifier.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,16 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
316316
for (var v in _elementUsageFrontierDetectors) {
317317
v.pushElement(element);
318318
}
319+
// TODO(srawlins): Use _deprecatedFunctionalityVerifier to detect omitted
320+
// super-parameters corresponding to `@Deprecated.optional` parameters.
321+
// TODO(srawlins): Use _deprecatedFunctionalityVerifier to detect omitted
322+
// parameters in a redirecting factory constructor.
323+
for (var redirectingConstructorInvocation
324+
in node.initializers.whereType<RedirectingConstructorInvocation>()) {
325+
_deprecatedFunctionalityVerifier.redirectingConstructorInvocation(
326+
redirectingConstructorInvocation,
327+
);
328+
}
319329
try {
320330
super.visitConstructorDeclaration(node);
321331
} finally {
@@ -864,6 +874,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
864874
for (var v in _elementUsageFrontierDetectors) {
865875
v.superConstructorInvocation(node);
866876
}
877+
_deprecatedFunctionalityVerifier.superConstructorInvocation(node);
867878
_invalidAccessVerifier.verifySuperConstructorInvocation(node);
868879
super.visitSuperConstructorInvocation(node);
869880
}

pkg/analyzer/lib/src/error/deprecated_functionality_verifier.dart

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/dart/ast/syntactic_entity.dart';
56
import 'package:analyzer/dart/element/element.dart';
67
import 'package:analyzer/error/listener.dart';
78
import 'package:analyzer/src/dart/ast/ast.dart';
@@ -44,7 +45,7 @@ class DeprecatedFunctionalityVerifier {
4445
_checkForDeprecatedOptional(
4546
element: element,
4647
argumentList: node.argumentList,
47-
errorNode: node.constructorName,
48+
errorEntity: node.constructorName,
4849
);
4950
_checkForDeprecatedInstantiate(
5051
element: element.enclosingElement,
@@ -58,7 +59,7 @@ class DeprecatedFunctionalityVerifier {
5859
_checkForDeprecatedOptional(
5960
element: element,
6061
argumentList: node.argumentList,
61-
errorNode: node.memberName,
62+
errorEntity: node.memberName,
6263
);
6364
}
6465

@@ -73,7 +74,7 @@ class DeprecatedFunctionalityVerifier {
7374
_checkForDeprecatedOptional(
7475
element: constructor,
7576
argumentList: node.argumentList,
76-
errorNode: node.constructorName,
77+
errorEntity: node.constructorName,
7778
);
7879
var interfaceElement = node.constructorName.type.element;
7980
if (interfaceElement is! InterfaceElement) return;
@@ -90,7 +91,7 @@ class DeprecatedFunctionalityVerifier {
9091
_checkForDeprecatedOptional(
9192
element: method,
9293
argumentList: node.argumentList,
93-
errorNode: node.methodName,
94+
errorEntity: node.methodName,
9495
);
9596
}
9697

@@ -101,6 +102,26 @@ class DeprecatedFunctionalityVerifier {
101102
_checkForDeprecatedImplement(node.onClause?.superclassConstraints);
102103
}
103104

105+
void redirectingConstructorInvocation(RedirectingConstructorInvocation node) {
106+
var element = node.element;
107+
if (element is! ConstructorElement) return;
108+
_checkForDeprecatedOptional(
109+
element: element,
110+
argumentList: node.argumentList,
111+
errorEntity: node.constructorName ?? node.thisKeyword,
112+
);
113+
}
114+
115+
void superConstructorInvocation(SuperConstructorInvocation node) {
116+
var constructor = node.element;
117+
if (constructor == null) return;
118+
_checkForDeprecatedOptional(
119+
element: constructor,
120+
argumentList: node.argumentList,
121+
errorEntity: node.constructorName ?? node.superKeyword,
122+
);
123+
}
124+
104125
void _checkForDeprecatedExtend(NamedType? node) {
105126
if (node == null) return;
106127
var element = node.element;
@@ -179,7 +200,7 @@ class DeprecatedFunctionalityVerifier {
179200
void _checkForDeprecatedOptional({
180201
required ExecutableElement element,
181202
required ArgumentList argumentList,
182-
required AstNode errorNode,
203+
required SyntacticEntity errorEntity,
183204
}) {
184205
var omittedParameters = element.formalParameters.toList();
185206
for (var argument in argumentList.arguments) {
@@ -189,8 +210,8 @@ class DeprecatedFunctionalityVerifier {
189210
}
190211
for (var parameter in omittedParameters) {
191212
if (parameter.isDeprecatedWithKind('optional')) {
192-
_diagnosticReporter.atNode(
193-
errorNode,
213+
_diagnosticReporter.atEntity(
214+
errorEntity,
194215
WarningCode.deprecatedOptional,
195216
arguments: [parameter.name ?? '<unknown>'],
196217
);

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,60 @@ void g(D d) {
138138
''');
139139
}
140140

141+
test_argumentOmitted_redirectedConstructor() async {
142+
await assertErrorsInCode(
143+
r'''
144+
class C {
145+
C([@Deprecated.optional() int? p]);
146+
C.two() : this();
147+
}
148+
''',
149+
[error(WarningCode.deprecatedOptional, 60, 4)],
150+
);
151+
}
152+
153+
test_argumentOmitted_redirectedConstructor_named() async {
154+
await assertErrorsInCode(
155+
r'''
156+
class C {
157+
C.one([@Deprecated.optional() int? p]);
158+
C.two() : this.one();
159+
}
160+
''',
161+
[error(WarningCode.deprecatedOptional, 69, 3)],
162+
);
163+
}
164+
165+
test_argumentOmitted_superInvocation() async {
166+
await assertErrorsInCode(
167+
r'''
168+
class C {
169+
C([@Deprecated.optional() int? p]);
170+
}
171+
172+
class D extends C {
173+
D() : super();
174+
}
175+
''',
176+
[error(WarningCode.deprecatedOptional, 79, 5)],
177+
);
178+
}
179+
180+
test_argumentOmitted_superInvocation_named() async {
181+
await assertErrorsInCode(
182+
r'''
183+
class C {
184+
C.named([@Deprecated.optional() int? p]);
185+
}
186+
187+
class D extends C {
188+
D() : super.named();
189+
}
190+
''',
191+
[error(WarningCode.deprecatedOptional, 91, 5)],
192+
);
193+
}
194+
141195
test_noAnnotation() async {
142196
await assertNoErrorsInCode(r'''
143197
void f([int? p]) {}

0 commit comments

Comments
 (0)