duke@1: /* jjg@696: * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.api; duke@1: duke@1: import java.io.IOException; duke@1: import java.util.Map; duke@1: import javax.annotation.processing.ProcessingEnvironment; duke@1: import javax.lang.model.element.AnnotationMirror; duke@1: import javax.lang.model.element.AnnotationValue; duke@1: import javax.lang.model.element.Element; duke@1: import javax.lang.model.element.ExecutableElement; duke@1: import javax.lang.model.element.TypeElement; duke@1: import javax.lang.model.type.DeclaredType; duke@1: import javax.lang.model.type.TypeMirror; jjg@308: import javax.tools.Diagnostic; duke@1: import javax.tools.JavaCompiler; duke@1: import javax.tools.JavaFileObject; duke@1: duke@1: import com.sun.source.tree.CompilationUnitTree; duke@1: import com.sun.source.tree.Scope; duke@1: import com.sun.source.tree.Tree; duke@1: import com.sun.source.util.SourcePositions; duke@1: import com.sun.source.util.TreePath; duke@1: import com.sun.source.util.Trees; jjg@672: import com.sun.tools.javac.code.Flags; duke@1: import com.sun.tools.javac.code.Symbol.ClassSymbol; duke@1: import com.sun.tools.javac.code.Symbol.TypeSymbol; duke@1: import com.sun.tools.javac.code.Symbol; duke@1: import com.sun.tools.javac.comp.Attr; duke@1: import com.sun.tools.javac.comp.AttrContext; duke@1: import com.sun.tools.javac.comp.Enter; duke@1: import com.sun.tools.javac.comp.Env; duke@1: import com.sun.tools.javac.comp.MemberEnter; duke@1: import com.sun.tools.javac.comp.Resolve; duke@1: import com.sun.tools.javac.model.JavacElements; duke@1: import com.sun.tools.javac.processing.JavacProcessingEnvironment; duke@1: import com.sun.tools.javac.tree.JCTree.*; duke@1: import com.sun.tools.javac.tree.JCTree; duke@1: import com.sun.tools.javac.tree.TreeCopier; duke@1: import com.sun.tools.javac.tree.TreeInfo; duke@1: import com.sun.tools.javac.tree.TreeMaker; duke@1: import com.sun.tools.javac.util.Context; jjg@308: import com.sun.tools.javac.util.JCDiagnostic; duke@1: import com.sun.tools.javac.util.List; duke@1: import com.sun.tools.javac.util.Log; duke@1: import com.sun.tools.javac.util.Pair; duke@1: duke@1: /** duke@1: * Provides an implementation of Trees. duke@1: * jjg@581: *

This is NOT part of any supported API. duke@1: * If you write code that depends on this, you do so at your own duke@1: * risk. This code and its internal interfaces are subject to change duke@1: * or deletion without notice.

duke@1: * duke@1: * @author Peter von der Ahé duke@1: */ duke@1: public class JavacTrees extends Trees { duke@1: jjg@696: // in a world of a single context per compilation, these would all be final jjg@696: private Resolve resolve; jjg@696: private Enter enter; jjg@696: private Log log; jjg@696: private MemberEnter memberEnter; jjg@696: private Attr attr; jjg@696: private TreeMaker treeMaker; jjg@696: private JavacElements elements; jjg@696: private JavacTaskImpl javacTaskImpl; duke@1: duke@1: public static JavacTrees instance(JavaCompiler.CompilationTask task) { duke@1: if (!(task instanceof JavacTaskImpl)) duke@1: throw new IllegalArgumentException(); duke@1: return instance(((JavacTaskImpl)task).getContext()); duke@1: } duke@1: duke@1: public static JavacTrees instance(ProcessingEnvironment env) { duke@1: if (!(env instanceof JavacProcessingEnvironment)) duke@1: throw new IllegalArgumentException(); duke@1: return instance(((JavacProcessingEnvironment)env).getContext()); duke@1: } duke@1: duke@1: public static JavacTrees instance(Context context) { duke@1: JavacTrees instance = context.get(JavacTrees.class); duke@1: if (instance == null) duke@1: instance = new JavacTrees(context); duke@1: return instance; duke@1: } duke@1: duke@1: private JavacTrees(Context context) { duke@1: context.put(JavacTrees.class, this); jjg@696: init(context); jjg@696: } jjg@696: jjg@696: public void updateContext(Context context) { jjg@696: init(context); jjg@696: } jjg@696: jjg@696: private void init(Context context) { duke@1: attr = Attr.instance(context); duke@1: enter = Enter.instance(context); duke@1: elements = JavacElements.instance(context); duke@1: log = Log.instance(context); duke@1: resolve = Resolve.instance(context); duke@1: treeMaker = TreeMaker.instance(context); duke@1: memberEnter = MemberEnter.instance(context); duke@1: javacTaskImpl = context.get(JavacTaskImpl.class); duke@1: } duke@1: duke@1: public SourcePositions getSourcePositions() { duke@1: return new SourcePositions() { duke@1: public long getStartPosition(CompilationUnitTree file, Tree tree) { duke@1: return TreeInfo.getStartPos((JCTree) tree); duke@1: } duke@1: duke@1: public long getEndPosition(CompilationUnitTree file, Tree tree) { duke@1: Map endPositions = ((JCCompilationUnit) file).endPositions; duke@1: return TreeInfo.getEndPos((JCTree) tree, endPositions); duke@1: } duke@1: }; duke@1: } duke@1: duke@1: public JCClassDecl getTree(TypeElement element) { duke@1: return (JCClassDecl) getTree((Element) element); duke@1: } duke@1: duke@1: public JCMethodDecl getTree(ExecutableElement method) { duke@1: return (JCMethodDecl) getTree((Element) method); duke@1: } duke@1: duke@1: public JCTree getTree(Element element) { duke@1: Symbol symbol = (Symbol) element; duke@1: TypeSymbol enclosing = symbol.enclClass(); duke@1: Env env = enter.getEnv(enclosing); duke@1: if (env == null) duke@1: return null; duke@1: JCClassDecl classNode = env.enclClass; duke@1: if (classNode != null) { duke@1: if (TreeInfo.symbolFor(classNode) == element) duke@1: return classNode; duke@1: for (JCTree node : classNode.getMembers()) duke@1: if (TreeInfo.symbolFor(node) == element) duke@1: return node; duke@1: } duke@1: return null; duke@1: } duke@1: duke@1: public JCTree getTree(Element e, AnnotationMirror a) { duke@1: return getTree(e, a, null); duke@1: } duke@1: duke@1: public JCTree getTree(Element e, AnnotationMirror a, AnnotationValue v) { duke@1: Pair treeTopLevel = elements.getTreeAndTopLevel(e, a, v); duke@1: if (treeTopLevel == null) duke@1: return null; duke@1: return treeTopLevel.fst; duke@1: } duke@1: duke@1: public TreePath getPath(CompilationUnitTree unit, Tree node) { duke@1: return TreePath.getPath(unit, node); duke@1: } duke@1: duke@1: public TreePath getPath(Element e) { duke@1: return getPath(e, null, null); duke@1: } duke@1: duke@1: public TreePath getPath(Element e, AnnotationMirror a) { duke@1: return getPath(e, a, null); duke@1: } duke@1: duke@1: public TreePath getPath(Element e, AnnotationMirror a, AnnotationValue v) { duke@1: final Pair treeTopLevel = elements.getTreeAndTopLevel(e, a, v); duke@1: if (treeTopLevel == null) duke@1: return null; duke@1: return TreePath.getPath(treeTopLevel.snd, treeTopLevel.fst); duke@1: } duke@1: duke@1: public Element getElement(TreePath path) { jjg@672: JCTree tree = (JCTree) path.getLeaf(); jjg@672: Symbol sym = TreeInfo.symbolFor(tree); jjg@672: if (sym == null && TreeInfo.isDeclaration(tree)) { jjg@672: for (TreePath p = path; p != null; p = p.getParentPath()) { jjg@672: JCTree t = (JCTree) p.getLeaf(); jjg@672: if (t.getTag() == JCTree.CLASSDEF) { jjg@672: JCClassDecl ct = (JCClassDecl) t; jjg@672: if (ct.sym != null) { jjg@672: if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) { jjg@672: attr.attribClass(ct.pos(), ct.sym); jjg@672: sym = TreeInfo.symbolFor(tree); jjg@672: } jjg@672: break; jjg@672: } jjg@672: } jjg@672: } jjg@672: } jjg@672: return sym; duke@1: } duke@1: duke@1: public TypeMirror getTypeMirror(TreePath path) { duke@1: Tree t = path.getLeaf(); duke@1: return ((JCTree)t).type; duke@1: } duke@1: duke@1: public JavacScope getScope(TreePath path) { duke@1: return new JavacScope(getAttrContext(path)); duke@1: } duke@1: duke@1: public boolean isAccessible(Scope scope, TypeElement type) { duke@1: if (scope instanceof JavacScope && type instanceof ClassSymbol) { duke@1: Env env = ((JavacScope) scope).env; duke@1: return resolve.isAccessible(env, (ClassSymbol)type); duke@1: } else duke@1: return false; duke@1: } duke@1: duke@1: public boolean isAccessible(Scope scope, Element member, DeclaredType type) { duke@1: if (scope instanceof JavacScope duke@1: && member instanceof Symbol duke@1: && type instanceof com.sun.tools.javac.code.Type) { duke@1: Env env = ((JavacScope) scope).env; duke@1: return resolve.isAccessible(env, (com.sun.tools.javac.code.Type)type, (Symbol)member); duke@1: } else duke@1: return false; duke@1: } duke@1: duke@1: private Env getAttrContext(TreePath path) { duke@1: if (!(path.getLeaf() instanceof JCTree)) // implicit null-check duke@1: throw new IllegalArgumentException(); duke@1: duke@1: // if we're being invoked via from a JSR199 client, we need to make sure duke@1: // all the classes have been entered; if we're being invoked from JSR269, duke@1: // then the classes will already have been entered. duke@1: if (javacTaskImpl != null) { duke@1: try { duke@1: javacTaskImpl.enter(null); duke@1: } catch (IOException e) { duke@1: throw new Error("unexpected error while entering symbols: " + e); duke@1: } duke@1: } duke@1: duke@1: duke@1: JCCompilationUnit unit = (JCCompilationUnit) path.getCompilationUnit(); duke@1: Copier copier = new Copier(treeMaker.forToplevel(unit)); duke@1: duke@1: Env env = null; duke@1: JCMethodDecl method = null; duke@1: JCVariableDecl field = null; duke@1: duke@1: List l = List.nil(); duke@1: TreePath p = path; duke@1: while (p != null) { duke@1: l = l.prepend(p.getLeaf()); duke@1: p = p.getParentPath(); duke@1: } duke@1: duke@1: for ( ; l.nonEmpty(); l = l.tail) { duke@1: Tree tree = l.head; duke@1: switch (tree.getKind()) { duke@1: case COMPILATION_UNIT: duke@1: // System.err.println("COMP: " + ((JCCompilationUnit)tree).sourcefile); duke@1: env = enter.getTopLevelEnv((JCCompilationUnit)tree); duke@1: break; jjg@727: case ANNOTATION_TYPE: duke@1: case CLASS: jjg@727: case ENUM: jjg@682: case INTERFACE: duke@1: // System.err.println("CLASS: " + ((JCClassDecl)tree).sym.getSimpleName()); duke@1: env = enter.getClassEnv(((JCClassDecl)tree).sym); duke@1: break; duke@1: case METHOD: duke@1: // System.err.println("METHOD: " + ((JCMethodDecl)tree).sym.getSimpleName()); duke@1: method = (JCMethodDecl)tree; duke@1: break; duke@1: case VARIABLE: duke@1: // System.err.println("FIELD: " + ((JCVariableDecl)tree).sym.getSimpleName()); duke@1: field = (JCVariableDecl)tree; duke@1: break; duke@1: case BLOCK: { duke@1: // System.err.println("BLOCK: "); duke@1: if (method != null) duke@1: env = memberEnter.getMethodEnv(method, env); duke@1: JCTree body = copier.copy((JCTree)tree, (JCTree) path.getLeaf()); duke@1: env = attribStatToTree(body, env, copier.leafCopy); duke@1: return env; duke@1: } duke@1: default: duke@1: // System.err.println("DEFAULT: " + tree.getKind()); duke@1: if (field != null && field.getInitializer() == tree) { duke@1: env = memberEnter.getInitEnv(field, env); duke@1: JCExpression expr = copier.copy((JCExpression)tree, (JCTree) path.getLeaf()); duke@1: env = attribExprToTree(expr, env, copier.leafCopy); duke@1: return env; duke@1: } duke@1: } duke@1: } duke@1: return field != null ? memberEnter.getInitEnv(field, env) : env; duke@1: } duke@1: duke@1: private Env attribStatToTree(JCTree stat, Envenv, JCTree tree) { duke@1: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); duke@1: try { duke@1: return attr.attribStatToTree(stat, env, tree); duke@1: } finally { duke@1: log.useSource(prev); duke@1: } duke@1: } duke@1: duke@1: private Env attribExprToTree(JCExpression expr, Envenv, JCTree tree) { duke@1: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); duke@1: try { duke@1: return attr.attribExprToTree(expr, env, tree); duke@1: } finally { duke@1: log.useSource(prev); duke@1: } duke@1: } duke@1: duke@1: /** duke@1: * Makes a copy of a tree, noting the value resulting from copying a particular leaf. duke@1: **/ duke@1: static class Copier extends TreeCopier { duke@1: JCTree leafCopy = null; duke@1: duke@1: Copier(TreeMaker M) { duke@1: super(M); duke@1: } duke@1: jjg@696: @Override duke@1: public T copy(T t, JCTree leaf) { duke@1: T t2 = super.copy(t, leaf); duke@1: if (t == leaf) duke@1: leafCopy = t2; duke@1: return t2; duke@1: } duke@1: } jjg@110: jjg@110: /** jjg@110: * Gets the original type from the ErrorType object. jjg@110: * @param errorType The errorType for which we want to get the original type. jjg@110: * @returns TypeMirror corresponding to the original type, replaced by the ErrorType. jjg@110: * noType (type.tag == NONE) is returned if there is no original type. jjg@110: */ jjg@110: public TypeMirror getOriginalType(javax.lang.model.type.ErrorType errorType) { jjg@110: if (errorType instanceof com.sun.tools.javac.code.Type.ErrorType) { jjg@110: return ((com.sun.tools.javac.code.Type.ErrorType)errorType).getOriginalType(); jjg@110: } jjg@110: jjg@110: return com.sun.tools.javac.code.Type.noType; jjg@110: } jjg@308: jjg@308: /** jjg@308: * Prints a message of the specified kind at the location of the jjg@308: * tree within the provided compilation unit jjg@308: * jjg@308: * @param kind the kind of message jjg@308: * @param msg the message, or an empty string if none jjg@308: * @param t the tree to use as a position hint jjg@308: * @param root the compilation unit that contains tree jjg@308: */ jjg@308: public void printMessage(Diagnostic.Kind kind, CharSequence msg, jjg@308: com.sun.source.tree.Tree t, jjg@308: com.sun.source.tree.CompilationUnitTree root) { jjg@308: JavaFileObject oldSource = null; jjg@308: JavaFileObject newSource = null; jjg@308: JCDiagnostic.DiagnosticPosition pos = null; jjg@308: jjg@308: newSource = root.getSourceFile(); jjg@308: if (newSource != null) { jjg@308: oldSource = log.useSource(newSource); jjg@308: pos = ((JCTree) t).pos(); jjg@308: } jjg@308: jjg@308: try { jjg@308: switch (kind) { jjg@308: case ERROR: jjg@308: boolean prev = log.multipleErrors; jjg@308: try { jjg@308: log.error(pos, "proc.messager", msg.toString()); jjg@308: } finally { jjg@308: log.multipleErrors = prev; jjg@308: } jjg@308: break; jjg@308: jjg@308: case WARNING: jjg@308: log.warning(pos, "proc.messager", msg.toString()); jjg@308: break; jjg@308: jjg@308: case MANDATORY_WARNING: jjg@308: log.mandatoryWarning(pos, "proc.messager", msg.toString()); jjg@308: break; jjg@308: jjg@308: default: jjg@308: log.note(pos, "proc.messager", msg.toString()); jjg@308: } jjg@308: } finally { jjg@308: if (oldSource != null) jjg@308: log.useSource(oldSource); jjg@308: } jjg@308: } duke@1: }