diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart index cd170321fd4..ec868b6c492 100644 --- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart +++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart @@ -190,13 +190,19 @@ class BestPracticesVerifier extends RecursiveAstVisitor { } } else if (element.isMustBeOverridden) { if ((parent is MethodDeclaration && parent.isStatic) || - (parent is FieldDeclaration && parent.isStatic)) { + (parent is FieldDeclaration && parent.isStatic) || + parent.parent is ExtensionDeclaration || + parent.parent is EnumDeclaration) { _errorReporter.reportErrorForNode( HintCode.INVALID_ANNOTATION_TARGET, node, [node.name.name, 'instance members of classes and mixins'], ); - } else if (parent.parent is ExtensionDeclaration || + } + } else if (element.isMustCallSuper) { + if ((parent is MethodDeclaration && parent.isStatic) || + (parent is FieldDeclaration && parent.isStatic) || + parent.parent is ExtensionDeclaration || parent.parent is EnumDeclaration) { _errorReporter.reportErrorForNode( HintCode.INVALID_ANNOTATION_TARGET, diff --git a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart index 05d90229843..d6c64beff70 100644 --- a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart +++ b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart @@ -179,6 +179,12 @@ class _MustBeOverridden { const _MustBeOverridden(); } +@Target({ + TargetKind.field, + TargetKind.getter, + TargetKind.method, + TargetKind.setter, +}) class _MustCallSuper { const _MustCallSuper(); } 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 dd7c73827ad..992314608a0 100644 --- a/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart +++ b/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart @@ -10,6 +10,7 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(InvalidAnnotationTarget_MustBeOverriddenTest); + defineReflectiveTests(InvalidAnnotationTarget_MustCallSuperTest); defineReflectiveTests(InvalidAnnotationTargetTest); }); } @@ -178,6 +179,170 @@ void m() {} } } +@reflectiveTest +class InvalidAnnotationTarget_MustCallSuperTest + extends PubPackageResolutionTest { + @override + void setUp() { + super.setUp(); + writeTestPackageConfigWithMeta(); + } + + test_class_instance_field() async { + await assertNoErrorsInCode(r''' +import 'package:meta/meta.dart'; + +class A { + @mustCallSuper + int f = 0; +} +'''); + } + + test_class_instance_getter() async { + await assertNoErrorsInCode(r''' +import 'package:meta/meta.dart'; + +class A { + @mustCallSuper + int get f => 0; +} +'''); + } + + test_class_instance_method() async { + await assertNoErrorsInCode(r''' +import 'package:meta/meta.dart'; + +class A { + @mustCallSuper + void m() {} +} +'''); + } + + test_class_instance_setter() async { + await assertNoErrorsInCode(r''' +import 'package:meta/meta.dart'; + +class A { + @mustCallSuper + void set s(int value) {} +} +'''); + } + + test_class_static_field() async { + await assertErrorsInCode(r''' +import 'package:meta/meta.dart'; +class A { + @mustCallSuper + static int f = 0; +} +''', [ + error(HintCode.INVALID_ANNOTATION_TARGET, 45, 14), + ]); + } + + test_class_static_getter() async { + await assertErrorsInCode(r''' +import 'package:meta/meta.dart'; +class A { + @mustCallSuper + static int get f => 0; +} +''', [ + error(HintCode.INVALID_ANNOTATION_TARGET, 45, 14), + ]); + } + + test_class_static_method() async { + await assertErrorsInCode(r''' +import 'package:meta/meta.dart'; +class A { + @mustCallSuper + static void m() {} +} +''', [ + error(HintCode.INVALID_ANNOTATION_TARGET, 45, 14), + ]); + } + + test_class_static_setter() async { + await assertErrorsInCode(r''' +import 'package:meta/meta.dart'; +class A { + @mustCallSuper + static void set f(int value) {} +} +''', [ + error(HintCode.INVALID_ANNOTATION_TARGET, 45, 14), + ]); + } + + test_constructor() async { + await assertErrorsInCode(r''' +import 'package:meta/meta.dart'; + +class C { + @mustCallSuper + C(); +} +''', [ + error(HintCode.INVALID_ANNOTATION_TARGET, 47, 13), + ]); + } + + test_enum_member() async { + await assertErrorsInCode(r''' +import 'package:meta/meta.dart'; + +enum E { + one, two; + @mustCallSuper + void m() {} +} +''', [ + error(HintCode.INVALID_ANNOTATION_TARGET, 57, 14), + ]); + } + + test_extension_member() async { + await assertErrorsInCode(r''' +import 'package:meta/meta.dart'; + +extension E on String { + @mustCallSuper + void m() {} +} +''', [ + error(HintCode.INVALID_ANNOTATION_TARGET, 60, 14), + ]); + } + + test_mixin_instance_method() async { + await assertNoErrorsInCode(r''' +import 'package:meta/meta.dart'; + +mixin M { + @mustCallSuper + void m() {} +} +'''); + } + + test_topLevel() async { + await assertErrorsInCode(r''' +import 'package:meta/meta.dart'; + +@mustCallSuper +void m() {} +''', [ + error(HintCode.INVALID_ANNOTATION_TARGET, 35, 13), + ]); + } +} + @reflectiveTest class InvalidAnnotationTargetTest extends PubPackageResolutionTest { // todo(pq): add tests for topLevelVariables: diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart index 7a1ce9ff45a..fb15a7d3bf2 100644 --- a/pkg/meta/lib/meta.dart +++ b/pkg/meta/lib/meta.dart @@ -458,6 +458,12 @@ class _MustBeOverridden { const _MustBeOverridden(); } +@Target({ + TargetKind.field, + TargetKind.getter, + TargetKind.method, + TargetKind.setter, +}) class _MustCallSuper { const _MustCallSuper(); }