Skip to content

Commit 8f477fd

Browse files
jensjohacommit-bot@chromium.org
authored andcommitted
[parser] Disallow covariant on extension method parameters
Fixes #38560. Change-Id: I4c941fb6713983cc01efbe143c7924d0643efe73 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119332 Commit-Queue: Jens Johansen <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent dee6458 commit 8f477fd

20 files changed

+158
-95
lines changed

pkg/analyzer/lib/error/error.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ const List<ErrorCode> errorCodeValues = const [
196196
CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_SET,
197197
CompileTimeErrorCode.INVALID_URI,
198198
CompileTimeErrorCode.INVALID_USE_OF_COVARIANT,
199+
// ignore: deprecated_member_use_from_same_package
199200
CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION,
200201
CompileTimeErrorCode.INVOCATION_OF_EXTENSION_WITHOUT_CALL,
201202
CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE,
@@ -522,6 +523,7 @@ const List<ErrorCode> errorCodeValues = const [
522523
ParserErrorCode.INVALID_STAR_AFTER_ASYNC,
523524
ParserErrorCode.INVALID_SYNC,
524525
ParserErrorCode.INVALID_UNICODE_ESCAPE,
526+
ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION,
525527
ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST,
526528
ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER,
527529
ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR,

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,38 @@ class ParserErrorCode extends ErrorCode {
481481

482482
static const ParserErrorCode INVALID_UNICODE_ESCAPE = _INVALID_UNICODE_ESCAPE;
483483

484+
/**
485+
* No parameters.
486+
*/
487+
// #### Description
488+
//
489+
// The analyzer produces this diagnostic when a member declared inside an
490+
// extension uses the keyword `covariant` in the declaration of a parameter.
491+
// Extensions aren't classes and don't have subclasses, so the keyword serves
492+
// no purpose.
493+
//
494+
// #### Example
495+
//
496+
// The following code produces this diagnostic:
497+
//
498+
// ```dart
499+
// extension E on String {
500+
// void a([!covariant!] int i) {}
501+
// }
502+
// ```
503+
//
504+
// #### Common fixes
505+
//
506+
// Remove the 'covariant' keyword:
507+
//
508+
// ```dart
509+
// extension E on String {
510+
// void a(int i) {}
511+
// }
512+
// ```
513+
static const ParserErrorCode INVALID_USE_OF_COVARIANT_IN_EXTENSION =
514+
_INVALID_USE_OF_COVARIANT_IN_EXTENSION;
515+
484516
static const ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST =
485517
_LIBRARY_DIRECTIVE_NOT_FIRST;
486518

pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ final fastaAnalyzerErrorCodes = <ErrorCode>[
105105
_MIXIN_DECLARES_CONSTRUCTOR,
106106
_NULL_AWARE_CASCADE_OUT_OF_ORDER,
107107
_MULTIPLE_VARIANCE_MODIFIERS,
108+
_INVALID_USE_OF_COVARIANT_IN_EXTENSION,
108109
];
109110

110111
const ParserErrorCode _ABSTRACT_CLASS_MEMBER = const ParserErrorCode(
@@ -398,6 +399,11 @@ const ParserErrorCode _INVALID_UNICODE_ESCAPE = const ParserErrorCode(
398399
'INVALID_UNICODE_ESCAPE',
399400
r"An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.");
400401

402+
const ParserErrorCode _INVALID_USE_OF_COVARIANT_IN_EXTENSION =
403+
const ParserErrorCode('INVALID_USE_OF_COVARIANT_IN_EXTENSION',
404+
r"Can't have modifier '#lexeme' in an extension.",
405+
correction: "Try removing '#lexeme'.");
406+
401407
const ParserErrorCode _LIBRARY_DIRECTIVE_NOT_FIRST = const ParserErrorCode(
402408
'LIBRARY_DIRECTIVE_NOT_FIRST',
403409
r"The library directive must appear before all other directives.",

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

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2599,40 +2599,9 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
25992599
"methods or before non-final instance fields.",
26002600
correction: "Try removing the 'covariant' keyword.");
26012601

2602-
/**
2603-
* No parameters.
2604-
*/
2605-
// #### Description
2606-
//
2607-
// The analyzer produces this diagnostic when a member declared inside an
2608-
// extension uses the keyword `covariant` in the declaration of a parameter.
2609-
// Extensions aren't classes and don't have subclasses, so the keyword serves
2610-
// no purpose.
2611-
//
2612-
// #### Example
2613-
//
2614-
// The following code produces this diagnostic:
2615-
//
2616-
// ```dart
2617-
// extension E on String {
2618-
// void a([!covariant!] int i) {}
2619-
// }
2620-
// ```
2621-
//
2622-
// #### Common fixes
2623-
//
2624-
// Remove the 'covariant' keyword:
2625-
//
2626-
// ```dart
2627-
// extension E on String {
2628-
// void a(int i) {}
2629-
// }
2630-
// ```
2631-
static const CompileTimeErrorCode INVALID_USE_OF_COVARIANT_IN_EXTENSION =
2632-
const CompileTimeErrorCode('INVALID_USE_OF_COVARIANT_IN_EXTENSION',
2633-
"The 'covariant' keyword can't be used in an extension.",
2634-
correction: "Try removing the 'covariant' keyword.",
2635-
hasPublishedDocs: true);
2602+
@Deprecated('Use ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION')
2603+
static const ParserErrorCode INVALID_USE_OF_COVARIANT_IN_EXTENSION =
2604+
ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION;
26362605

26372606
/**
26382607
* 14.2 Exports: It is a compile-time error if the compilation unit found at

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5497,10 +5497,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
54975497
Token keyword = parameter.covariantKeyword;
54985498
if (keyword != null) {
54995499
if (_enclosingExtension != null) {
5500-
_errorReporter.reportErrorForToken(
5501-
CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION,
5502-
keyword,
5503-
);
5500+
// Reported by the parser.
55045501
} else {
55055502
_errorReporter.reportErrorForToken(
55065503
CompileTimeErrorCode.INVALID_USE_OF_COVARIANT,

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:analyzer/dart/analysis/features.dart';
6-
import 'package:analyzer/src/error/codes.dart';
76
import 'package:analyzer/src/generated/engine.dart';
7+
import 'package:analyzer/src/generated/parser.dart';
88
import 'package:test_reflective_loader/test_reflective_loader.dart';
99

1010
import '../dart/resolution/driver_resolution.dart';
@@ -28,7 +28,7 @@ extension E on String {
2828
void foo({covariant int a}) {}
2929
}
3030
''', [
31-
error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 36, 9),
31+
error(ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 36, 9),
3232
]);
3333
}
3434

@@ -38,7 +38,7 @@ extension E on String {
3838
void foo([covariant int a]) {}
3939
}
4040
''', [
41-
error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 36, 9),
41+
error(ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 36, 9),
4242
]);
4343
}
4444

@@ -48,7 +48,7 @@ extension E on String {
4848
void foo(covariant int a) {}
4949
}
5050
''', [
51-
error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 35, 9),
51+
error(ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 35, 9),
5252
]);
5353
}
5454
}

pkg/analyzer/tool/diagnostics/diagnostics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,7 @@ var x;
13071307

13081308
### invalid_use_of_covariant_in_extension
13091309

1310-
_The 'covariant' keyword can't be used in an extension._
1310+
_Can't have modifier '#lexeme' in an extension._
13111311

13121312
#### Description
13131313

pkg/front_end/lib/src/fasta/fasta_codes_generated.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3573,6 +3573,29 @@ Message _withArgumentsExtraneousModifier(Token token) {
35733573
arguments: {'token': token});
35743574
}
35753575

3576+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3577+
const Template<Message Function(Token token)>
3578+
templateExtraneousModifierInExtension =
3579+
const Template<Message Function(Token token)>(
3580+
messageTemplate: r"""Can't have modifier '#lexeme' in an extension.""",
3581+
tipTemplate: r"""Try removing '#lexeme'.""",
3582+
withArguments: _withArgumentsExtraneousModifierInExtension);
3583+
3584+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3585+
const Code<Message Function(Token token)> codeExtraneousModifierInExtension =
3586+
const Code<Message Function(Token token)>(
3587+
"ExtraneousModifierInExtension", templateExtraneousModifierInExtension,
3588+
index: 98);
3589+
3590+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3591+
Message _withArgumentsExtraneousModifierInExtension(Token token) {
3592+
String lexeme = token.lexeme;
3593+
return new Message(codeExtraneousModifierInExtension,
3594+
message: """Can't have modifier '${lexeme}' in an extension.""",
3595+
tip: """Try removing '${lexeme}'.""",
3596+
arguments: {'token': token});
3597+
}
3598+
35763599
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
35773600
const Code<Null> codeFactoryNotSync = messageFactoryNotSync;
35783601

pkg/front_end/lib/src/fasta/parser/member_kind.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ enum MemberKind {
3232
/// A top-level method.
3333
TopLevelMethod,
3434

35+
/// A non-static method in an extension.
36+
ExtensionNonStaticMethod,
37+
38+
/// A static method in an extension.
39+
ExtensionStaticMethod,
40+
3541
/// An instance field in a class.
3642
NonStaticField,
3743

pkg/front_end/lib/src/fasta/parser/modifier_context.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ class ModifierRecoveryContext {
117117
memberKind == MemberKind.TopLevelMethod) {
118118
reportExtraneousModifier(this.covariantToken);
119119
this.covariantToken = null;
120+
} else if (memberKind == MemberKind.ExtensionNonStaticMethod ||
121+
memberKind == MemberKind.ExtensionStaticMethod) {
122+
reportExtraneousModifierInExtension(this.covariantToken);
123+
this.covariantToken = null;
120124
}
121125
if (constToken != null) {
122126
reportExtraneousModifier(constToken);
@@ -462,6 +466,13 @@ class ModifierRecoveryContext {
462466
}
463467
}
464468

469+
void reportExtraneousModifierInExtension(Token modifier) {
470+
if (modifier != null) {
471+
parser.reportRecoverableErrorWithToken(
472+
modifier, fasta.templateExtraneousModifierInExtension);
473+
}
474+
}
475+
465476
void reportModifierOutOfOrder(Token modifier, String beforeModifier) {
466477
parser.reportRecoverableError(
467478
modifier,

pkg/front_end/lib/src/fasta/parser/parser.dart

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,9 @@ class Parser {
13371337
if (isModifier(next)) {
13381338
if (optional('covariant', next)) {
13391339
if (memberKind != MemberKind.StaticMethod &&
1340-
memberKind != MemberKind.TopLevelMethod) {
1340+
memberKind != MemberKind.TopLevelMethod &&
1341+
memberKind != MemberKind.ExtensionNonStaticMethod &&
1342+
memberKind != MemberKind.ExtensionStaticMethod) {
13411343
covariantToken = token = next;
13421344
next = token.next;
13431345
}
@@ -3327,9 +3329,13 @@ class Parser {
33273329
token,
33283330
name,
33293331
isGetter,
3330-
staticToken != null
3331-
? MemberKind.StaticMethod
3332-
: MemberKind.NonStaticMethod);
3332+
kind == DeclarationKind.Extension
3333+
? staticToken != null
3334+
? MemberKind.ExtensionStaticMethod
3335+
: MemberKind.ExtensionNonStaticMethod
3336+
: staticToken != null
3337+
? MemberKind.StaticMethod
3338+
: MemberKind.NonStaticMethod);
33333339
token = parseInitializersOpt(beforeInitializers);
33343340
if (token == beforeInitializers) beforeInitializers = null;
33353341

pkg/front_end/messages.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,14 @@ ExtraneousModifier:
775775
- "abstract typedef foo();"
776776
- "static typedef foo();"
777777

778+
ExtraneousModifierInExtension:
779+
index: 98
780+
template: "Can't have modifier '#lexeme' in an extension."
781+
tip: "Try removing '#lexeme'."
782+
analyzerCode: ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION
783+
script:
784+
- "extension on String { foo(covariant String child) {} }"
785+
778786
FinalAndCovariant:
779787
index: 80
780788
template: "Members can't be declared to be both 'final' and 'covariant'."

pkg/front_end/parser_testcases/extensions/covariant.dart.expect

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,18 @@ beginCompilationUnit(class)
4747
handleNoType({)
4848
handleIdentifier(addChild, methodDeclaration)
4949
handleNoTypeVariables(()
50-
beginFormalParameters((, MemberKind.NonStaticMethod)
50+
beginFormalParameters((, MemberKind.ExtensionNonStaticMethod)
5151
beginMetadataStar(covariant)
5252
endMetadataStar(0)
53-
beginFormalParameter(covariant, MemberKind.NonStaticMethod, null, covariant, null)
53+
handleRecoverableError(Instance of 'Message', covariant, covariant)
54+
beginFormalParameter(covariant, MemberKind.ExtensionNonStaticMethod, null, null, null)
5455
handleIdentifier(A, typeReference)
5556
handleNoTypeArguments(child)
5657
handleType(A, null)
5758
handleIdentifier(child, formalParameterDeclaration)
5859
handleFormalParameterWithoutValue())
59-
endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
60-
endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
60+
endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
61+
endFormalParameters(1, (, ), MemberKind.ExtensionNonStaticMethod)
6162
handleNoInitializers()
6263
handleAsyncModifier(null, null)
6364
beginBlockFunctionBody({)

pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,23 +89,25 @@ parseUnit(class)
8989
parseQualifiedRestOpt(addChild, methodDeclarationContinuation)
9090
parseMethodTypeVar(addChild)
9191
listener: handleNoTypeVariables(()
92-
parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.NonStaticMethod)
93-
parseFormalParameters(addChild, MemberKind.NonStaticMethod)
94-
parseFormalParametersRest((, MemberKind.NonStaticMethod)
95-
listener: beginFormalParameters((, MemberKind.NonStaticMethod)
96-
parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
92+
parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.ExtensionNonStaticMethod)
93+
parseFormalParameters(addChild, MemberKind.ExtensionNonStaticMethod)
94+
parseFormalParametersRest((, MemberKind.ExtensionNonStaticMethod)
95+
listener: beginFormalParameters((, MemberKind.ExtensionNonStaticMethod)
96+
parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
9797
parseMetadataStar(()
9898
listener: beginMetadataStar(covariant)
9999
listener: endMetadataStar(0)
100-
listener: beginFormalParameter(covariant, MemberKind.NonStaticMethod, null, covariant, null)
100+
reportRecoverableErrorWithToken(covariant, Instance of 'Template<(Token) => Message>')
101+
listener: handleRecoverableError(Instance of 'Message', covariant, covariant)
102+
listener: beginFormalParameter(covariant, MemberKind.ExtensionNonStaticMethod, null, null, null)
101103
listener: handleIdentifier(A, typeReference)
102104
listener: handleNoTypeArguments(child)
103105
listener: handleType(A, null)
104106
ensureIdentifier(A, formalParameterDeclaration)
105107
listener: handleIdentifier(child, formalParameterDeclaration)
106108
listener: handleFormalParameterWithoutValue())
107-
listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
108-
listener: endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
109+
listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
110+
listener: endFormalParameters(1, (, ), MemberKind.ExtensionNonStaticMethod)
109111
parseInitializersOpt())
110112
listener: handleNoInitializers()
111113
parseAsyncModifierOpt())

pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,17 @@ beginCompilationUnit(class)
4747
handleNoType({)
4848
handleIdentifier(addChild, methodDeclaration)
4949
handleNoTypeVariables(()
50-
beginFormalParameters((, MemberKind.NonStaticMethod)
50+
beginFormalParameters((, MemberKind.ExtensionNonStaticMethod)
5151
beginMetadataStar(A)
5252
endMetadataStar(0)
53-
beginFormalParameter(A, MemberKind.NonStaticMethod, null, null, null)
53+
beginFormalParameter(A, MemberKind.ExtensionNonStaticMethod, null, null, null)
5454
handleIdentifier(A, typeReference)
5555
handleNoTypeArguments(child)
5656
handleType(A, null)
5757
handleIdentifier(child, formalParameterDeclaration)
5858
handleFormalParameterWithoutValue())
59-
endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
60-
endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
59+
endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
60+
endFormalParameters(1, (, ), MemberKind.ExtensionNonStaticMethod)
6161
handleNoInitializers()
6262
handleAsyncModifier(null, null)
6363
beginBlockFunctionBody({)

pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,23 +89,23 @@ parseUnit(class)
8989
parseQualifiedRestOpt(addChild, methodDeclarationContinuation)
9090
parseMethodTypeVar(addChild)
9191
listener: handleNoTypeVariables(()
92-
parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.NonStaticMethod)
93-
parseFormalParameters(addChild, MemberKind.NonStaticMethod)
94-
parseFormalParametersRest((, MemberKind.NonStaticMethod)
95-
listener: beginFormalParameters((, MemberKind.NonStaticMethod)
96-
parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
92+
parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.ExtensionNonStaticMethod)
93+
parseFormalParameters(addChild, MemberKind.ExtensionNonStaticMethod)
94+
parseFormalParametersRest((, MemberKind.ExtensionNonStaticMethod)
95+
listener: beginFormalParameters((, MemberKind.ExtensionNonStaticMethod)
96+
parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
9797
parseMetadataStar(()
9898
listener: beginMetadataStar(A)
9999
listener: endMetadataStar(0)
100-
listener: beginFormalParameter(A, MemberKind.NonStaticMethod, null, null, null)
100+
listener: beginFormalParameter(A, MemberKind.ExtensionNonStaticMethod, null, null, null)
101101
listener: handleIdentifier(A, typeReference)
102102
listener: handleNoTypeArguments(child)
103103
listener: handleType(A, null)
104104
ensureIdentifier(A, formalParameterDeclaration)
105105
listener: handleIdentifier(child, formalParameterDeclaration)
106106
listener: handleFormalParameterWithoutValue())
107-
listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
108-
listener: endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
107+
listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
108+
listener: endFormalParameters(1, (, ), MemberKind.ExtensionNonStaticMethod)
109109
parseInitializersOpt())
110110
listener: handleNoInitializers()
111111
parseAsyncModifierOpt())

0 commit comments

Comments
 (0)