analyzer: enforce TargetKind.overridableMember and optionalParameter
Change-Id: Ic34e9df7ea10acd81e7280c4f77ec7b6b3ab86e3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365680
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
diff --git a/pkg/analyzer/lib/src/error/annotation_verifier.dart b/pkg/analyzer/lib/src/error/annotation_verifier.dart
index e1fb491..e601785 100644
--- a/pkg/analyzer/lib/src/error/annotation_verifier.dart
+++ b/pkg/analyzer/lib/src/error/annotation_verifier.dart
@@ -586,6 +586,21 @@
/// when the annotation is marked as being valid for the given [kinds] of
/// targets.
bool _isValidTarget(AstNode target, Set<TargetKind> kinds) {
+ // `TargetKind.overridableMember` is complex, so we handle it separately.
+ if (kinds.contains(TargetKind.overridableMember)) {
+ if ((target is FieldDeclaration && !target.isStatic) ||
+ target is MethodDeclaration && !target.isStatic) {
+ var parent = target.parent;
+ if (parent is ClassDeclaration ||
+ parent is ExtensionTypeDeclaration ||
+ parent is MixinDeclaration) {
+ // Members of `EnumDeclaration`s and `ExtensionDeclaration`s are not
+ // overridable.
+ return true;
+ }
+ }
+ }
+
return switch (target) {
ClassDeclaration() =>
kinds.contains(TargetKind.classType) || kinds.contains(TargetKind.type),
@@ -609,7 +624,8 @@
MethodDeclaration() => kinds.contains(TargetKind.method),
MixinDeclaration() =>
kinds.contains(TargetKind.mixinType) || kinds.contains(TargetKind.type),
- FormalParameter() => kinds.contains(TargetKind.parameter),
+ FormalParameter() => kinds.contains(TargetKind.parameter) ||
+ (target.isOptional && kinds.contains(TargetKind.optionalParameter)),
FunctionTypeAlias() ||
GenericTypeAlias() =>
kinds.contains(TargetKind.typedefType) ||
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
index de5b3fb1..8db3012 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
@@ -350,10 +350,14 @@
static const extensionType = TargetKind._('extension types', 'extensionType');
static const field = TargetKind._('fields', 'field');
static const function = TargetKind._('top-level functions', 'function');
+ static const optionalParameter =
+ TargetKind._('optional parameters', 'optionalParameter');
static const library = TargetKind._('libraries', 'library');
static const getter = TargetKind._('getters', 'getter');
static const method = TargetKind._('methods', 'method');
static const mixinType = TargetKind._('mixins', 'mixinType');
+ static const overridableMember =
+ TargetKind._('overridable members', 'overridableMember');
static const parameter = TargetKind._('parameters', 'parameter');
static const setter = TargetKind._('setters', 'setter');
static const topLevelVariable =
@@ -373,10 +377,12 @@
extensionType,
field,
function,
+ overridableMember,
library,
getter,
method,
mixinType,
+ optionalParameter,
parameter,
setter,
topLevelVariable,
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index b8b068c..fdb98f3 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -14,7 +14,7 @@
crypto: ^3.0.0
glob: ^2.0.0
macros: '>=0.1.0-0 <0.1.1'
- meta: ^1.14.0
+ meta: ^1.15.0
package_config: ^2.0.0
path: ^1.9.0
pub_semver: ^2.1.4
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
index 566aa3c..5146ba5 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
@@ -1068,6 +1068,215 @@
''');
}
+ void test_optionalParameter_optionalNamed() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.optionalParameter})
+class A {
+ const A();
+}
+
+void f({@A() int? x}) {}
+''');
+ }
+
+ void test_optionalParameter_optionalPositional() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.optionalParameter})
+class A {
+ const A();
+}
+
+void f([@A() int? x]) {}
+''');
+ }
+
+ void test_optionalParameter_requiredNamed() async {
+ await assertErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.optionalParameter})
+class A {
+ const A();
+}
+
+void f({@A() required int x}) {}
+''', [
+ error(WarningCode.INVALID_ANNOTATION_TARGET, 114, 1),
+ ]);
+ }
+
+ void test_optionalParameter_requiredPositional() async {
+ await assertErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.optionalParameter})
+class A {
+ const A();
+}
+
+void f(@A() int x) {}
+''', [
+ error(WarningCode.INVALID_ANNOTATION_TARGET, 113, 1),
+ ]);
+ }
+
+ void test_overridableMember_constructor() async {
+ await assertErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+ const A();
+}
+
+class C {
+ @A()
+ C();
+}
+''', [
+ error(WarningCode.INVALID_ANNOTATION_TARGET, 118, 1),
+ ]);
+ }
+
+ void test_overridableMember_instanceGetter() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+ const A();
+}
+
+class C {
+ @A()
+ int get x => 0;
+}
+''');
+ }
+
+ void test_overridableMember_instanceMethod() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+ const A();
+}
+
+class C {
+ @A()
+ int x() => 0;
+}
+''');
+ }
+
+ void test_overridableMember_instanceMethod_onEnum() async {
+ await assertErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+ const A();
+}
+
+enum E {
+ one, two;
+ @A()
+ int x() => 0;
+}
+''', [
+ error(WarningCode.INVALID_ANNOTATION_TARGET, 129, 1),
+ ]);
+ }
+
+ void test_overridableMember_instanceMethod_onExtension() async {
+ await assertErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+ const A();
+}
+
+extension E on int {
+ @A()
+ int x() => 0;
+}
+''', [
+ error(WarningCode.INVALID_ANNOTATION_TARGET, 129, 1),
+ ]);
+ }
+
+ void test_overridableMember_instanceMethod_onMixin() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+ const A();
+}
+
+mixin M {
+ @A()
+ int x() => 0;
+}
+''');
+ }
+
+ void test_overridableMember_instanceOperator() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+ const A();
+}
+
+class C {
+ @A()
+ int operator +(int value) => 0;
+}
+''');
+ }
+
+ void test_overridableMember_instanceSetter() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+ const A();
+}
+
+class C {
+ @A()
+ set x(int value) {}
+}
+''');
+ }
+
+ void test_overridableMember_staticMethod() async {
+ await assertErrorsInCode('''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+ const A();
+}
+
+class C {
+ @A()
+ static int x() => 0;
+}
+''', [
+ error(WarningCode.INVALID_ANNOTATION_TARGET, 118, 1),
+ ]);
+ }
+
void test_parameter_function() async {
await assertErrorsInCode('''
import 'package:meta/meta_meta.dart';