Index: lib/src/rules/must_call_super.dart |
diff --git a/lib/src/rules/annotate_overrides.dart b/lib/src/rules/must_call_super.dart |
similarity index 53% |
copy from lib/src/rules/annotate_overrides.dart |
copy to lib/src/rules/must_call_super.dart |
index e0d1a46864365a5922ad661355ecf4f88b370ec2..451b2080d100fcef46fb22893a56e7ef707161a3 100644 |
--- a/lib/src/rules/annotate_overrides.dart |
+++ b/lib/src/rules/must_call_super.dart |
@@ -2,49 +2,72 @@ |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
-library linter.src.rules.annotate_overrides; |
+library linter.src.rules.must_call_super; |
import 'package:analyzer/dart/element/element.dart'; |
import 'package:analyzer/src/generated/ast.dart'; |
import 'package:analyzer/src/generated/resolver.dart'; |
import 'package:linter/src/linter.dart'; |
-const desc = r'Annotate overridden members'; |
+const desc = r'Methods marked @mustCallSuper must invoke super'; |
const details = r''' |
-**DO** annotate overridden methods and fields. |
+Methods marked `@mustCallSuper` must invoke the overriden super method. |
-**GOOD:** |
+**DO** ensure that all methods that override a method with the `@mustCallSuper` |
+annotation contain a super invocation of the overridden method. |
+ |
+The `@mustCallSuper` annotation is implemented in the `meta` |
+[package](https://pub.dartlang.org/packages/meta). |
+ |
+**BAD:** |
``` |
-abstract class Dog { |
- String get breed; |
- void bark() {} |
+class TestCase { |
+ @mustCallSuper |
+ void setUp() { ... } |
} |
-class Husky extends Dog { |
- @override |
- final String breed = 'Husky'; |
+class MyTest extends TestCase { |
@override |
- void bark() {} |
+ void setUp() { |
+ // do nothing. |
+ } |
+ ... |
} |
``` |
-**BAD:** |
+**GOOD:** |
``` |
-class Cat { |
- int get lives => 9; |
+class TestCase { |
+ @mustCallSuper |
+ void setUp() { ... } |
} |
-class Lucky extends Cat { |
- final int lives = 14; |
+class MyTest extends TestCase { |
+ @override |
+ void setUp() { |
+ super.setUp(); |
+ } |
} |
``` |
+ |
'''; |
-class AnnotateOverrides extends LintRule { |
- AnnotateOverrides() |
+class InvocationCollector extends RecursiveAstVisitor { |
+ final List<String> superCalls = <String>[]; |
+ |
+ @override |
+ visitMethodInvocation(MethodInvocation node) { |
+ if (node.target is SuperExpression) { |
+ superCalls.add(node.methodName.name); |
+ } |
+ } |
+} |
+ |
+class MustCallSuper extends LintRule { |
+ MustCallSuper() |
: super( |
- name: 'annotate_overrides', |
+ name: 'must_call_super', |
description: desc, |
details: details, |
group: Group.style); |
@@ -79,22 +102,12 @@ class Visitor extends SimpleAstVisitor { |
} |
@override |
- visitFieldDeclaration(FieldDeclaration node) { |
- for (VariableDeclaration field in node.fields.variables) { |
- if (field?.element != null && !field.element.isOverride) { |
- ExecutableElement member = getOverriddenMember(field.element); |
- if (member != null) { |
- rule.reportLint(field); |
- } |
- } |
- } |
- } |
- |
- @override |
visitMethodDeclaration(MethodDeclaration node) { |
- if (node?.element != null && !node.element.isOverride) { |
- ExecutableElement member = getOverriddenMember(node.element); |
- if (member != null) { |
+ ExecutableElement overriddenMember = getOverriddenMember(node.element); |
+ if (overriddenMember != null) { |
+ InvocationCollector collector = new InvocationCollector(); |
+ node.accept(collector); |
+ if (!collector.superCalls.contains(overriddenMember.name)) { |
rule.reportLint(node.name); |
} |
} |