blob: 4e1c06f08d6a2740e3efffbc66b74ce2334bca55 [file] [log] [blame]
/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.engine.ast.visitor;
import com.google.dart.engine.ast.Annotation;
import com.google.dart.engine.ast.AssignmentExpression;
import com.google.dart.engine.ast.AstNode;
import com.google.dart.engine.ast.BinaryExpression;
import com.google.dart.engine.ast.ClassDeclaration;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.ast.ConstructorDeclaration;
import com.google.dart.engine.ast.FunctionDeclaration;
import com.google.dart.engine.ast.Identifier;
import com.google.dart.engine.ast.ImportDirective;
import com.google.dart.engine.ast.IndexExpression;
import com.google.dart.engine.ast.InstanceCreationExpression;
import com.google.dart.engine.ast.LibraryDirective;
import com.google.dart.engine.ast.LibraryIdentifier;
import com.google.dart.engine.ast.MethodDeclaration;
import com.google.dart.engine.ast.MethodInvocation;
import com.google.dart.engine.ast.PartOfDirective;
import com.google.dart.engine.ast.PostfixExpression;
import com.google.dart.engine.ast.PrefixExpression;
import com.google.dart.engine.ast.PrefixedIdentifier;
import com.google.dart.engine.ast.SimpleIdentifier;
import com.google.dart.engine.ast.StringLiteral;
import com.google.dart.engine.ast.UriBasedDirective;
import com.google.dart.engine.ast.VariableDeclaration;
import com.google.dart.engine.element.ClassElement;
import com.google.dart.engine.element.Element;
import com.google.dart.engine.element.LibraryElement;
import com.google.dart.engine.internal.builder.AngularCompilationUnitBuilder;
import com.google.dart.engine.internal.builder.PolymerCompilationUnitBuilder;
/**
* Instances of the class {@code ElementLocator} locate the {@link Element Dart model element}
* associated with a given {@link AstNode AST node}.
*
* @coverage dart.engine.ast
*/
public class ElementLocator {
/**
* Visitor that maps nodes to elements.
*/
private static final class ElementMapper extends GeneralizingAstVisitor<Element> {
@Override
public Element visitAnnotation(Annotation node) {
return node.getElement();
}
@Override
public Element visitAssignmentExpression(AssignmentExpression node) {
return node.getBestElement();
}
@Override
public Element visitBinaryExpression(BinaryExpression node) {
return node.getBestElement();
}
@Override
public Element visitClassDeclaration(ClassDeclaration node) {
return node.getElement();
}
@Override
public Element visitCompilationUnit(CompilationUnit node) {
return node.getElement();
}
@Override
public Element visitConstructorDeclaration(ConstructorDeclaration node) {
return node.getElement();
}
@Override
public Element visitFunctionDeclaration(FunctionDeclaration node) {
return node.getElement();
}
@Override
public Element visitIdentifier(Identifier node) {
AstNode parent = node.getParent();
// Type name in Annotation
if (parent instanceof Annotation) {
Annotation annotation = (Annotation) parent;
if (annotation.getName() == node && annotation.getConstructorName() == null) {
return annotation.getElement();
}
}
// Extra work to map Constructor Declarations to their associated Constructor Elements
if (parent instanceof ConstructorDeclaration) {
ConstructorDeclaration decl = (ConstructorDeclaration) parent;
Identifier returnType = decl.getReturnType();
if (returnType == node) {
SimpleIdentifier name = decl.getName();
if (name != null) {
return name.getBestElement();
}
Element element = node.getBestElement();
if (element instanceof ClassElement) {
return ((ClassElement) element).getUnnamedConstructor();
}
}
}
if (parent instanceof LibraryIdentifier) {
AstNode grandParent = ((LibraryIdentifier) parent).getParent();
if (grandParent instanceof PartOfDirective) {
Element element = ((PartOfDirective) grandParent).getElement();
if (element instanceof LibraryElement) {
return ((LibraryElement) element).getDefiningCompilationUnit();
}
}
}
return node.getBestElement();
}
@Override
public Element visitImportDirective(ImportDirective node) {
return node.getElement();
}
@Override
public Element visitIndexExpression(IndexExpression node) {
return node.getBestElement();
}
@Override
public Element visitInstanceCreationExpression(InstanceCreationExpression node) {
return node.getStaticElement();
}
@Override
public Element visitLibraryDirective(LibraryDirective node) {
return node.getElement();
}
@Override
public Element visitMethodDeclaration(MethodDeclaration node) {
return node.getElement();
}
@Override
public Element visitMethodInvocation(MethodInvocation node) {
return node.getMethodName().getBestElement();
}
@Override
public Element visitPostfixExpression(PostfixExpression node) {
return node.getBestElement();
}
@Override
public Element visitPrefixedIdentifier(PrefixedIdentifier node) {
return node.getBestElement();
}
@Override
public Element visitPrefixExpression(PrefixExpression node) {
return node.getBestElement();
}
@Override
public Element visitStringLiteral(StringLiteral node) {
AstNode parent = node.getParent();
if (parent instanceof UriBasedDirective) {
return ((UriBasedDirective) parent).getUriElement();
}
return null;
}
@Override
public Element visitVariableDeclaration(VariableDeclaration node) {
return node.getElement();
}
}
/**
* Locate the {@link Element Dart model element} associated with the given {@link AstNode AST
* node}.
*
* @param node the node (not {@code null})
* @return the associated element, or {@code null} if none is found
*/
public static Element locate(AstNode node) {
ElementMapper mapper = new ElementMapper();
return node.accept(mapper);
}
/**
* Locate the {@link Element Dart model element} associated with the given {@link AstNode AST
* node} and offset.
*
* @param node the node (not {@code null})
* @param offset the offset relative to source
* @return the associated element, or {@code null} if none is found
*/
public static Element locateWithOffset(AstNode node, int offset) {
if (node == null) {
return null;
}
// try to get Element from node
{
Element nodeElement = locate(node);
if (nodeElement != null) {
return nodeElement;
}
}
// try to get Angular specific Element
{
Element element = AngularCompilationUnitBuilder.getElement(node, offset);
if (element != null) {
return element;
}
}
// try to get Polymer specific Element
{
Element element = PolymerCompilationUnitBuilder.getElement(node, offset);
if (element != null) {
return element;
}
}
// no Element
return null;
}
/**
* Clients should use {@link #locate(AstNode)} or {@link #locateWithOffset(AstNode, int)}.
*/
private ElementLocator() {
}
}