Index: dart/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/resolver/ElementResolver.java |
=================================================================== |
--- dart/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/resolver/ElementResolver.java (revision 29808) |
+++ dart/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/resolver/ElementResolver.java (working copy) |
@@ -237,6 +237,24 @@ |
} |
/** |
+ * Checks if the given expression is the reference to the type, if it is then the |
+ * {@link ClassElement} is returned, otherwise {@code null} is returned. |
+ * |
+ * @param expr the expression to evaluate |
+ * @return the {@link ClassElement} if the given expression is the reference to the type, and |
+ * {@code null} otherwise |
+ */ |
+ public static ClassElementImpl getTypeReference(Expression expr) { |
+ if (expr instanceof Identifier) { |
+ Identifier identifier = (Identifier) expr; |
+ if (identifier.getStaticElement() instanceof ClassElementImpl) { |
+ return (ClassElementImpl) identifier.getStaticElement(); |
+ } |
+ } |
+ return null; |
+ } |
+ |
+ /** |
* @return {@code true} if the given identifier is the return type of a constructor declaration. |
*/ |
private static boolean isConstructorReturnType(SimpleIdentifier node) { |
@@ -937,8 +955,18 @@ |
propagatedElement = null; |
} else { |
Type staticType = getStaticType(target); |
- staticElement = resolveInvokedElement(target, staticType, methodName); |
- propagatedElement = resolveInvokedElement(target, getPropagatedType(target), methodName); |
+ // |
+ // If this method invocation is of the form 'C.m' where 'C' is a class, then we don't call |
+ // resolveInvokedElement(..) which walks up the class hierarchy, instead we just look for the |
+ // member in the type only. |
+ // |
+ ClassElementImpl typeReference = getTypeReference(target); |
+ if (typeReference != null) { |
+ staticElement = propagatedElement = resolveElement(typeReference, methodName.getName()); |
+ } else { |
+ staticElement = resolveInvokedElement(target, staticType, methodName); |
+ propagatedElement = resolveInvokedElement(target, getPropagatedType(target), methodName); |
+ } |
} |
staticElement = convertSetterToGetter(staticElement); |
propagatedElement = convertSetterToGetter(propagatedElement); |
@@ -1169,7 +1197,7 @@ |
// Validate annotation element. |
if (node.getParent() instanceof Annotation) { |
Annotation annotation = (Annotation) node.getParent(); |
- resolveAnnotationElement(annotation, element, null); |
+ resolveAnnotationElement(annotation); |
return null; |
} |
return null; |
@@ -1178,7 +1206,7 @@ |
// May be annotation, resolve invocation of "const" constructor. |
if (node.getParent() instanceof Annotation) { |
Annotation annotation = (Annotation) node.getParent(); |
- resolveAnnotationElement(annotation, prefixElement, identifier); |
+ resolveAnnotationElement(annotation); |
} |
// |
@@ -1338,7 +1366,7 @@ |
// |
if (node.getParent() instanceof Annotation) { |
Annotation annotation = (Annotation) node.getParent(); |
- resolveAnnotationElement(annotation, element, null); |
+ resolveAnnotationElement(annotation); |
} |
return null; |
} |
@@ -2295,64 +2323,121 @@ |
} |
/** |
- * Validates that the given {@link Element} is the constant variable; or resolves it as a |
- * constructor invocation. |
+ * Continues resolution of the given {@link Annotation}. |
* |
* @param annotation the {@link Annotation} to resolve |
- * @param element the current known {@link Element} of the annotation, or {@link ClassElement} |
- * @param nameNode the name of the invoked constructor, may be {@code null} if unnamed constructor |
- * or not a constructor invocation |
*/ |
- private void resolveAnnotationElement(Annotation annotation, Element element, |
- SimpleIdentifier nameNode) { |
- // constant variable |
- if (element instanceof PropertyAccessorElement) { |
- PropertyAccessorElement accessorElement = (PropertyAccessorElement) element; |
- // accessor should be synthetic |
- if (!accessorElement.isSynthetic()) { |
- resolver.reportError(CompileTimeErrorCode.INVALID_ANNOTATION, annotation); |
+ private void resolveAnnotationElement(Annotation annotation) { |
+ SimpleIdentifier nameNode1; |
+ SimpleIdentifier nameNode2; |
+ { |
+ Identifier annName = annotation.getName(); |
+ if (annName instanceof PrefixedIdentifier) { |
+ PrefixedIdentifier prefixed = (PrefixedIdentifier) annName; |
+ nameNode1 = prefixed.getPrefix(); |
+ nameNode2 = prefixed.getIdentifier(); |
+ } else { |
+ nameNode1 = (SimpleIdentifier) annName; |
+ nameNode2 = null; |
+ } |
+ } |
+ SimpleIdentifier nameNode3 = annotation.getConstructorName(); |
+ ConstructorElement constructor = null; |
+ // |
+ // CONST or Class(args) |
+ // |
+ if (nameNode1 != null && nameNode2 == null && nameNode3 == null) { |
+ Element element1 = nameNode1.getStaticElement(); |
+ // CONST |
+ if (element1 instanceof PropertyAccessorElement) { |
+ resolveAnnotationElementGetter(annotation, (PropertyAccessorElement) element1); |
return; |
} |
- // variable should be constant |
- VariableElement variableElement = accessorElement.getVariable(); |
- if (!variableElement.isConst()) { |
- resolver.reportError(CompileTimeErrorCode.INVALID_ANNOTATION, annotation); |
+ // Class(args) |
+ if (element1 instanceof ClassElement) { |
+ ClassElement classElement = (ClassElement) element1; |
+ constructor = new InterfaceTypeImpl(classElement).lookUpConstructor(null, definingLibrary); |
} |
- // OK |
- return; |
} |
- // const constructor invocation |
- if (element instanceof ClassElement) { |
- // prepare constructor name |
- if (nameNode == null) { |
- nameNode = annotation.getConstructorName(); |
+ // |
+ // prefix.CONST or prefix.Class() or Class.CONST or Class.constructor(args) |
+ // |
+ if (nameNode1 != null && nameNode2 != null && nameNode3 == null) { |
+ Element element1 = nameNode1.getStaticElement(); |
+ Element element2 = nameNode2.getStaticElement(); |
+ // Class.CONST - not resolved yet |
+ if (element1 instanceof ClassElement) { |
+ ClassElement classElement = (ClassElement) element1; |
+ element2 = classElement.lookUpGetter(nameNode2.getName(), definingLibrary); |
} |
- String name = nameNode != null ? nameNode.getName() : null; |
- // look up ConstructorElement |
- ConstructorElement constructor; |
- { |
- InterfaceType interfaceType = new InterfaceTypeImpl((ClassElement) element); |
- constructor = interfaceType.lookUpConstructor(name, definingLibrary); |
- } |
- // not a constructor |
- if (constructor == null) { |
- resolver.reportError(CompileTimeErrorCode.INVALID_ANNOTATION, annotation); |
+ // prefix.CONST or Class.CONST |
+ if (element2 instanceof PropertyAccessorElement) { |
+ nameNode2.setStaticElement(element2); |
+ annotation.setElement(element2); |
+ resolveAnnotationElementGetter(annotation, (PropertyAccessorElement) element2); |
return; |
} |
- // record element |
- annotation.setElement(constructor); |
- if (nameNode != null) { |
- nameNode.setStaticElement(constructor); |
+ // prefix.Class() |
+ if (element2 instanceof ClassElement) { |
+ ClassElement classElement = (ClassElement) element2; |
+ constructor = classElement.getUnnamedConstructor(); |
} |
- // resolve arguments |
- resolveAnnotationConstructorInvocationArguments(annotation, constructor); |
- // OK |
+ // Class.constructor(args) |
+ if (element1 instanceof ClassElement) { |
+ ClassElement classElement = (ClassElement) element1; |
+ constructor = new InterfaceTypeImpl(classElement).lookUpConstructor( |
+ nameNode2.getName(), |
+ definingLibrary); |
+ nameNode2.setStaticElement(constructor); |
+ } |
+ } |
+ // |
+ // prefix.Class.CONST or prefix.Class.constructor(args) |
+ // |
+ if (nameNode1 != null && nameNode2 != null && nameNode3 != null) { |
+ Element element2 = nameNode2.getStaticElement(); |
+ // element2 should be ClassElement |
+ if (element2 instanceof ClassElement) { |
+ ClassElement classElement = (ClassElement) element2; |
+ String name3 = nameNode3.getName(); |
+ // prefix.Class.CONST |
+ PropertyAccessorElement getter = classElement.lookUpGetter(name3, definingLibrary); |
+ if (getter != null) { |
+ nameNode3.setStaticElement(getter); |
+ annotation.setElement(element2); |
+ resolveAnnotationElementGetter(annotation, getter); |
+ return; |
+ } |
+ // prefix.Class.constructor(args) |
+ constructor = new InterfaceTypeImpl(classElement).lookUpConstructor(name3, definingLibrary); |
+ nameNode3.setStaticElement(constructor); |
+ } |
+ } |
+ // we need constructor |
+ if (constructor == null) { |
+ resolver.reportError(CompileTimeErrorCode.INVALID_ANNOTATION, annotation); |
return; |
} |
- // something unknown |
- if (element != null) { |
+ // record element |
+ annotation.setElement(constructor); |
+ // resolve arguments |
+ resolveAnnotationConstructorInvocationArguments(annotation, constructor); |
+ } |
+ |
+ private void resolveAnnotationElementGetter(Annotation annotation, |
+ PropertyAccessorElement accessorElement) { |
+ // accessor should be synthetic |
+ if (!accessorElement.isSynthetic()) { |
resolver.reportError(CompileTimeErrorCode.INVALID_ANNOTATION, annotation); |
+ return; |
} |
+ // variable should be constant |
+ VariableElement variableElement = accessorElement.getVariable(); |
+ if (!variableElement.isConst()) { |
+ resolver.reportError(CompileTimeErrorCode.INVALID_ANNOTATION, annotation); |
+ } |
+ // OK |
+ return; |
} |
/** |
@@ -2484,6 +2569,29 @@ |
} |
/** |
+ * Given an invocation of the form 'C.x()' where 'C' is a class, find and return the element 'x' |
+ * in 'C'. |
+ * |
+ * @param classElement the class element |
+ * @param memberName the member name |
+ */ |
+ private Element resolveElement(ClassElementImpl classElement, String memberName) { |
+ Element element = null; |
+ String methodNameStr = memberName; |
+ element = classElement.getMethod(methodNameStr); |
+ if (element == null) { |
+ element = classElement.getSetter(memberName); |
+ if (element == null) { |
+ element = classElement.getGetter(memberName); |
+ } |
+ } |
+ if (element != null && element.isAccessibleIn(definingLibrary)) { |
+ return element; |
+ } |
+ return null; |
+ } |
+ |
+ /** |
* Given an invocation of the form 'e.m(a1, ..., an)', resolve 'e.m' to the element being invoked. |
* If the returned element is a method, then the method will be invoked. If the returned element |
* is a getter, the getter will be invoked without arguments and the result of that invocation |
@@ -2588,8 +2696,24 @@ |
private void resolvePropertyAccess(Expression target, SimpleIdentifier propertyName) { |
Type staticType = getStaticType(target); |
- ExecutableElement staticElement = resolveProperty(target, staticType, propertyName); |
+ Type propagatedType = getPropagatedType(target); |
+ Element staticElement = null; |
+ Element propagatedElement = null; |
+ |
+ // |
+ // If this property access is of the form 'C.m' where 'C' is a class, then we don't call |
+ // resolveProperty(..) which walks up the class hierarchy, instead we just look for the |
+ // member in the type only. |
+ // |
+ ClassElementImpl typeReference = getTypeReference(target); |
+ if (typeReference != null) { |
+ staticElement = propagatedElement = resolveElement(typeReference, propertyName.getName()); |
+ } else { |
+ staticElement = resolveProperty(target, staticType, propertyName); |
+ propagatedElement = resolveProperty(target, propagatedType, propertyName); |
+ } |
+ |
// May be part of annotation, record property element only if exists. |
// Error was already reported in validateAnnotationElement(). |
if (target.getParent().getParent() instanceof Annotation) { |
@@ -2598,10 +2722,8 @@ |
} |
return; |
} |
+ |
propertyName.setStaticElement(staticElement); |
- |
- Type propagatedType = getPropagatedType(target); |
- ExecutableElement propagatedElement = resolveProperty(target, propagatedType, propertyName); |
propertyName.setPropagatedElement(propagatedElement); |
boolean shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticElement) |
@@ -2792,7 +2914,7 @@ |
* @param member the result of the look-up |
* @return {@code true} if we should report an error |
*/ |
- private boolean shouldReportMissingMember(Type type, ExecutableElement member) { |
+ private boolean shouldReportMissingMember(Type type, Element member) { |
if (member != null || type == null || type.isDynamic() || type.isBottom()) { |
return false; |
} |