Index: pkg/analyzer/lib/src/generated/error_verifier.dart |
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart |
index 463e9165f7f3e26fe5b6ac9f0352c28bd6e19ca7..1fef4df5e9716c07a4d982426528872ddb9e7140 100644 |
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart |
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart |
@@ -896,6 +896,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
_checkForAllInvalidOverrideErrorCodesForMethod(node); |
_checkForTypeAnnotationDeferredClass(returnTypeName); |
_checkForIllegalReturnType(returnTypeName); |
+ _checkForMustCallSuper(node); |
return super.visitMethodDeclaration(node); |
} finally { |
_enclosingFunction = previousFunction; |
@@ -4416,6 +4417,25 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
return numSuperInitializers > 0; |
} |
+ void _checkForMustCallSuper(MethodDeclaration node) { |
+ ExecutableElement overriddenMember = _getOverriddenMember(node.element); |
+ while (overriddenMember is MethodElement) { |
+ for (ElementAnnotation annotation in overriddenMember.metadata) { |
+ if (annotation.isMustCallSuper) { |
+ _InvocationCollector collector = new _InvocationCollector(); |
+ node.accept(collector); |
+ if (!collector.superCalls.contains(overriddenMember.name)) { |
+ _errorReporter.reportErrorForNode(HintCode.MUST_CALL_SUPER, |
+ node.name, [overriddenMember.enclosingElement.name]); |
+ return; |
Brian Wilkerson
2016/03/07 21:07:09
I think this 'return' wants to be in the outer 'if
pquitslund
2016/03/07 21:29:39
Good catch and good idea.
Updating.
|
+ } |
+ } |
+ } |
+ // Keep looking up the chain. |
+ overriddenMember = _getOverriddenMember(overriddenMember); |
+ } |
+ } |
+ |
/** |
* Checks to ensure that the given native function [body] is in SDK code. |
* |
@@ -5837,6 +5857,19 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
} |
} |
+ ExecutableElement _getOverriddenMember(Element member) { |
+ if (member == null || _inheritanceManager == null) { |
+ return null; |
+ } |
+ |
+ ClassElement classElement = |
+ member.getAncestor((element) => element is ClassElement); |
+ if (classElement == null) { |
+ return null; |
+ } |
+ return _inheritanceManager.lookupInheritance(classElement, member.name); |
+ } |
+ |
/** |
* Return the type of the first and only parameter of the given [setter]. |
*/ |
@@ -6220,3 +6253,17 @@ class GeneralizingElementVisitor_ErrorVerifier_hasTypedefSelfReference |
} |
} |
} |
+ |
+/** |
+ * Recursively visits an AST, looking for method invocations. |
+ */ |
+class _InvocationCollector extends RecursiveAstVisitor { |
+ final List<String> superCalls = <String>[]; |
+ |
+ @override |
+ visitMethodInvocation(MethodInvocation node) { |
+ if (node.target is SuperExpression) { |
+ superCalls.add(node.methodName.name); |
+ } |
+ } |
+} |