Skip to content

Commit aeacf56

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Check for missing required arguments using parameter elements.
Bug: https://buganizer.corp.google.com/issues/140314870 Change-Id: I42a615fbd17af2b3d3b424f847a4b75463415377 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121540 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Paul Berry <paulberry@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
1 parent b5bbc97 commit aeacf56

File tree

2 files changed

+118
-72
lines changed

2 files changed

+118
-72
lines changed

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

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,29 @@ class RequiredParametersVerifier extends SimpleAstVisitor<void> {
1919

2020
@override
2121
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
22-
_checkForMissingRequiredParam(
23-
node.staticInvokeType,
24-
node.argumentList,
25-
node,
26-
);
22+
var type = node.staticInvokeType;
23+
if (type is FunctionType) {
24+
_check(
25+
type.parameters,
26+
node.argumentList,
27+
node,
28+
);
29+
}
2730
}
2831

2932
@override
3033
void visitInstanceCreationExpression(InstanceCreationExpression node) {
31-
_checkForMissingRequiredParam(
32-
node.staticElement?.type,
34+
_check(
35+
node.staticElement?.parameters,
3336
node.argumentList,
3437
node.constructorName,
3538
);
3639
}
3740

3841
@override
3942
void visitMethodInvocation(MethodInvocation node) {
40-
_checkForMissingRequiredParam(
41-
node.staticInvokeType,
43+
_check(
44+
_executableElement(node.methodName.staticElement)?.parameters,
4245
node.argumentList,
4346
node.methodName,
4447
);
@@ -47,58 +50,60 @@ class RequiredParametersVerifier extends SimpleAstVisitor<void> {
4750
@override
4851
void visitRedirectingConstructorInvocation(
4952
RedirectingConstructorInvocation node) {
50-
_checkForMissingRequiredParam(
51-
node.staticElement?.type,
53+
_check(
54+
_executableElement(node.staticElement)?.parameters,
5255
node.argumentList,
5356
node,
5457
);
5558
}
5659

5760
@override
5861
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
59-
_checkForMissingRequiredParam(
60-
node.staticElement?.type,
62+
_check(
63+
_executableElement(node.staticElement)?.parameters,
6164
node.argumentList,
6265
node,
6366
);
6467
}
6568

66-
void _checkForMissingRequiredParam(
67-
DartType type,
69+
void _check(
70+
List<ParameterElement> parameters,
6871
ArgumentList argumentList,
6972
AstNode node,
7073
) {
71-
if (type is FunctionType) {
72-
for (ParameterElement parameter in type.parameters) {
73-
if (parameter.isRequiredNamed) {
74+
if (parameters == null) {
75+
return;
76+
}
77+
78+
for (ParameterElement parameter in parameters) {
79+
if (parameter.isRequiredNamed) {
80+
String parameterName = parameter.name;
81+
if (!_containsNamedExpression(argumentList, parameterName)) {
82+
_errorReporter.reportErrorForNode(
83+
CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT,
84+
node,
85+
[parameterName],
86+
);
87+
}
88+
}
89+
if (parameter.isOptionalNamed) {
90+
ElementAnnotationImpl annotation = _requiredAnnotation(parameter);
91+
if (annotation != null) {
7492
String parameterName = parameter.name;
7593
if (!_containsNamedExpression(argumentList, parameterName)) {
76-
_errorReporter.reportErrorForNode(
77-
CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT,
78-
node,
79-
[parameterName],
80-
);
81-
}
82-
}
83-
if (parameter.isOptionalNamed) {
84-
ElementAnnotationImpl annotation = _requiredAnnotation(parameter);
85-
if (annotation != null) {
86-
String parameterName = parameter.name;
87-
if (!_containsNamedExpression(argumentList, parameterName)) {
88-
String reason = _requiredReason(annotation);
89-
if (reason != null) {
90-
_errorReporter.reportErrorForNode(
91-
HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
92-
node,
93-
[parameterName, reason],
94-
);
95-
} else {
96-
_errorReporter.reportErrorForNode(
97-
HintCode.MISSING_REQUIRED_PARAM,
98-
node,
99-
[parameterName],
100-
);
101-
}
94+
String reason = _requiredReason(annotation);
95+
if (reason != null) {
96+
_errorReporter.reportErrorForNode(
97+
HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
98+
node,
99+
[parameterName, reason],
100+
);
101+
} else {
102+
_errorReporter.reportErrorForNode(
103+
HintCode.MISSING_REQUIRED_PARAM,
104+
node,
105+
[parameterName],
106+
);
102107
}
103108
}
104109
}
@@ -119,6 +124,14 @@ class RequiredParametersVerifier extends SimpleAstVisitor<void> {
119124
return false;
120125
}
121126

127+
static ExecutableElement _executableElement(Element element) {
128+
if (element is ExecutableElement) {
129+
return element;
130+
} else {
131+
return null;
132+
}
133+
}
134+
122135
static ElementAnnotationImpl _requiredAnnotation(ParameterElement element) {
123136
return element.metadata.firstWhere(
124137
(e) => e.isRequired,

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

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ main() {
1919

2020
@reflectiveTest
2121
class MissingRequiredParamTest extends DriverResolutionTest with PackageMixin {
22-
test_constructorParam_argumentGiven() async {
22+
test_constructor_argumentGiven() async {
2323
addMetaPackage();
2424
await assertNoErrorsInCode(r'''
2525
import 'package:meta/meta.dart';
@@ -34,7 +34,7 @@ main() {
3434
''');
3535
}
3636

37-
test_constructorParam_missingArgument() async {
37+
test_constructor_hasReason() async {
3838
addMetaPackage();
3939
await assertErrorsInCode(r'''
4040
import 'package:meta/meta.dart';
@@ -49,7 +49,7 @@ main() {
4949
]);
5050
}
5151

52-
test_constructorParam_noReason() async {
52+
test_constructor_noReason() async {
5353
addMetaPackage();
5454
await assertErrorsInCode(r'''
5555
import 'package:meta/meta.dart';
@@ -66,7 +66,24 @@ main() {
6666
]);
6767
}
6868

69-
test_constructorParam_nullReason() async {
69+
test_constructor_noReason_generic() async {
70+
addMetaPackage();
71+
await assertErrorsInCode(r'''
72+
import 'package:meta/meta.dart';
73+
74+
class C<T> {
75+
C({@required int a}) {}
76+
}
77+
78+
main() {
79+
new C();
80+
}
81+
''', [
82+
error(HintCode.MISSING_REQUIRED_PARAM, 91, 1),
83+
]);
84+
}
85+
86+
test_constructor_nullReason() async {
7087
addMetaPackage();
7188
await assertErrorsInCode(r'''
7289
import 'package:meta/meta.dart';
@@ -83,7 +100,7 @@ main() {
83100
]);
84101
}
85102

86-
test_constructorParam_redirectingConstructorCall() async {
103+
test_constructor_redirectingConstructorCall() async {
87104
addMetaPackage();
88105
await assertErrorsInCode(r'''
89106
import 'package:meta/meta.dart';
@@ -96,7 +113,7 @@ class C {
96113
]);
97114
}
98115

99-
test_constructorParam_superCall() async {
116+
test_constructor_superCall() async {
100117
addMetaPackage();
101118
await assertErrorsInCode(r'''
102119
import 'package:meta/meta.dart';
@@ -113,7 +130,7 @@ class D extends C {
113130
]);
114131
}
115132

116-
test_functionParam() async {
133+
test_function() async {
117134
addMetaPackage();
118135
await assertErrorsInCode(r'''
119136
import 'package:meta/meta.dart';
@@ -128,7 +145,7 @@ main() {
128145
]);
129146
}
130147

131-
test_methodParam() async {
148+
test_method() async {
132149
addMetaPackage();
133150
await assertErrorsInCode(r'''
134151
import 'package:meta/meta.dart';
@@ -143,7 +160,23 @@ f() {
143160
]);
144161
}
145162

146-
test_methodParam_inOtherLib() async {
163+
test_method_generic() async {
164+
addMetaPackage();
165+
await assertErrorsInCode(r'''
166+
import 'package:meta/meta.dart';
167+
168+
class A<T> {
169+
void m<U>(U a, {@Required('must specify an `b`') int b}) {}
170+
}
171+
f() {
172+
new A<double>().m(true);
173+
}
174+
''', [
175+
error(HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS, 135, 1),
176+
]);
177+
}
178+
179+
test_method_inOtherLib() async {
147180
addMetaPackage();
148181
newFile('/a_lib.dart', content: r'''
149182
library a_lib;
@@ -170,7 +203,7 @@ the return type of `C.m` is a structural FunctionType, which does
170203
not know its elements, and does not know that there was a parameter
171204
marked `@required`. There is exactly one such typedef in Flutter.
172205
''')
173-
test_typedef_functionParam() async {
206+
test_typedef_function() async {
174207
addMetaPackage();
175208
await assertErrorsInCode(r'''
176209
import 'package:meta/meta.dart';
@@ -202,7 +235,7 @@ class MissingRequiredParamWithNnbdTest extends DriverResolutionTest {
202235
..contextFeatures = new FeatureSet.forTesting(
203236
sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
204237

205-
test_constructorParam_argumentGiven() async {
238+
test_constructor_argumentGiven() async {
206239
await assertNoErrorsInCode(r'''
207240
class C {
208241
C({required int a}) {}
@@ -214,7 +247,7 @@ main() {
214247
''');
215248
}
216249

217-
test_constructorParam_missingArgument() async {
250+
test_constructor_missingArgument() async {
218251
await assertErrorsInCode(r'''
219252
class C {
220253
C({required int a}) {}
@@ -227,7 +260,7 @@ main() {
227260
]);
228261
}
229262

230-
test_constructorParam_redirectingConstructorCall() async {
263+
test_constructor_redirectingConstructorCall() async {
231264
await assertErrorsInCode(r'''
232265
class C {
233266
C({required int x});
@@ -238,7 +271,7 @@ class C {
238271
]);
239272
}
240273

241-
test_constructorParam_superCall() async {
274+
test_constructor_superCall() async {
242275
await assertErrorsInCode(r'''
243276
class C {
244277
C({required int a}) {}
@@ -252,30 +285,30 @@ class D extends C {
252285
]);
253286
}
254287

255-
test_functionInvocation() async {
288+
test_function() async {
256289
await assertErrorsInCode(r'''
257-
void Function({required int a}) f() => throw '';
258-
g() {
259-
f()();
290+
void f({required int a}) {}
291+
292+
main() {
293+
f();
260294
}
261295
''', [
262-
error(CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT, 57, 5),
296+
error(CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT, 40, 1),
263297
]);
264298
}
265299

266-
test_functionParam() async {
300+
test_functionInvocation() async {
267301
await assertErrorsInCode(r'''
268-
void f({required int a}) {}
269-
270-
main() {
271-
f();
302+
void Function({required int a}) f() => throw '';
303+
g() {
304+
f()();
272305
}
273306
''', [
274-
error(CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT, 40, 1),
307+
error(CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT, 57, 5),
275308
]);
276309
}
277310

278-
test_methodParam() async {
311+
test_method() async {
279312
await assertErrorsInCode(r'''
280313
class A {
281314
void m({required int a}) {}
@@ -288,7 +321,7 @@ f() {
288321
]);
289322
}
290323

291-
test_methodParam_inOtherLib() async {
324+
test_method_inOtherLib() async {
292325
newFile('/test/lib/a_lib.dart', content: r'''
293326
class A {
294327
void m({required int a}) {}
@@ -304,7 +337,7 @@ f() {
304337
]);
305338
}
306339

307-
test_typedef_functionParam() async {
340+
test_typedef_function() async {
308341
await assertErrorsInCode(r'''
309342
String test(C c) => c.m()();
310343

0 commit comments

Comments
 (0)