/* * 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() { } }