Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(277)

Unified Diff: pkg/analyzer/lib/src/generated/resolver.dart

Issue 1723243002: Validation of `@protected` method invocations. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: fixes Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/generated/resolver.dart
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 59359c19e033baa505730e881a6fa2a963e29a0b..805765cc07bb608614d05f7fe77cd7992747dbb5 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -206,6 +206,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
@override
Object visitMethodInvocation(MethodInvocation node) {
_checkForCanBeNullAfterNullAware(node.realTarget, node.operator);
+ _checkForInvalidProtectedMethodCalls(node);
return super.visitMethodInvocation(node);
}
@@ -608,6 +609,39 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
}
/**
+ * Produces a hint if the given invocation is of a protected method outside
+ * a subclass instance method.
+ */
+ void _checkForInvalidProtectedMethodCalls(MethodInvocation node) {
+ Element element = node.methodName.bestElement;
+ if (element == null || !element.isProtected) {
+ return;
+ }
+
+ ClassElement definingClass = element.enclosingElement;
+
+ MethodDeclaration decl =
+ node.getAncestor((AstNode node) => node is MethodDeclaration);
+ if (decl == null) {
Brian Wilkerson 2016/02/23 23:42:57 Are we handling static methods as a call site? cl
pquitslund 2016/02/24 17:12:17 Yep. Test added!
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+ node,
+ [node.methodName.toString(), definingClass.name]);
+ return;
+ }
+
+ ClassElement invokingClass = decl.element?.enclosingElement;
+ if (invokingClass != null) {
+ if (!_hasSuperClassOrMixin(invokingClass, definingClass.type)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+ node,
+ [node.methodName.toString(), definingClass.name]);
+ }
+ }
+ }
+
+ /**
* Check that the imported library does not define a loadLibrary function. The import has already
* been determined to be deferred when this is called.
*
@@ -790,35 +824,6 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
}
/**
- * Check for the passed class declaration for the
- * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
- *
- * @param node the class declaration to check
- * @return `true` if and only if a hint code is generated on the passed node
- * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
- */
-// bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
-// ClassElement classElement = node.element;
-// if (classElement == null) {
-// return false;
-// }
-// MethodElement equalsOperatorMethodElement =
-// classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
-// if (equalsOperatorMethodElement != null) {
-// PropertyAccessorElement hashCodeElement =
-// classElement.getGetter(_HASHCODE_GETTER_NAME);
-// if (hashCodeElement == null) {
-// _errorReporter.reportErrorForNode(
-// HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
-// node.name,
-// [classElement.displayName]);
-// return true;
-// }
-// }
-// return false;
-// }
-
- /**
* Generate a hint for `noSuchMethod` methods that do nothing except of
* calling another `noSuchMethod` that is not defined by `Object`.
*
@@ -867,6 +872,35 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
}
/**
+ * Check for the passed class declaration for the
+ * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
+ *
+ * @param node the class declaration to check
+ * @return `true` if and only if a hint code is generated on the passed node
+ * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
+ */
+// bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
+// ClassElement classElement = node.element;
+// if (classElement == null) {
+// return false;
+// }
+// MethodElement equalsOperatorMethodElement =
+// classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
+// if (equalsOperatorMethodElement != null) {
+// PropertyAccessorElement hashCodeElement =
+// classElement.getGetter(_HASHCODE_GETTER_NAME);
+// if (hashCodeElement == null) {
+// _errorReporter.reportErrorForNode(
+// HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
+// node.name,
+// [classElement.displayName]);
+// return true;
+// }
+// }
+// return false;
+// }
+
+ /**
* Check for situations where the result of a method or function is used, when it returns 'void'.
*
* TODO(jwren) Many other situations of use could be covered. We currently cover the cases var x =
@@ -891,6 +925,24 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
return false;
}
+ bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) {
+ List<ClassElement> seenClasses = <ClassElement>[];
+ while (element != null && !seenClasses.contains(element)) {
+ if (element.type == type) {
+ return true;
+ }
+
+ if (element.mixins.any((InterfaceType t) => t == type)) {
+ return true;
+ }
+
+ seenClasses.add(element);
+ element = element.supertype?.element;
+ }
+
+ return false;
+ }
+
/**
* Given a parenthesized expression, this returns the parent (or recursively grand-parent) of the
* expression that is a parenthesized expression, but whose parent is not a parenthesized
@@ -8387,26 +8439,6 @@ class ResolverVisitor extends ScopedVisitor {
return null;
}
- void _inferArgumentTypesFromContext(InvocationExpression node) {
- DartType contextType = node.staticInvokeType;
- if (contextType is FunctionType) {
- DartType originalType = node.function.staticType;
- DartType returnContextType = InferenceContext.getType(node);
- TypeSystem ts = typeSystem;
- if (returnContextType != null &&
- node.typeArguments == null &&
- originalType is FunctionType &&
- originalType.typeFormals.isNotEmpty &&
- ts is StrongTypeSystemImpl) {
-
- contextType = ts.inferGenericFunctionCall(typeProvider, originalType,
- DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType);
- }
-
- InferenceContext.setType(node.argumentList, contextType);
- }
- }
-
@override
Object visitNamedExpression(NamedExpression node) {
InferenceContext.setType(node.expression, InferenceContext.getType(node));
@@ -8734,6 +8766,25 @@ class ResolverVisitor extends ScopedVisitor {
return null;
}
+ void _inferArgumentTypesFromContext(InvocationExpression node) {
+ DartType contextType = node.staticInvokeType;
+ if (contextType is FunctionType) {
+ DartType originalType = node.function.staticType;
+ DartType returnContextType = InferenceContext.getType(node);
+ TypeSystem ts = typeSystem;
+ if (returnContextType != null &&
+ node.typeArguments == null &&
+ originalType is FunctionType &&
+ originalType.typeFormals.isNotEmpty &&
+ ts is StrongTypeSystemImpl) {
+ contextType = ts.inferGenericFunctionCall(typeProvider, originalType,
+ DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType);
+ }
+
+ InferenceContext.setType(node.argumentList, contextType);
+ }
+ }
+
void _inferFormalParameterList(FormalParameterList node, DartType type) {
if (typeAnalyzer.inferFormalParameterList(node, type)) {
// TODO(leafp): This gets dropped on the floor if we're in the field

Powered by Google App Engine
This is Rietveld 408576698