001    /*
002     * Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.api;
027    
028    import java.io.IOException;
029    import java.util.Map;
030    import javax.annotation.processing.ProcessingEnvironment;
031    import javax.lang.model.element.AnnotationMirror;
032    import javax.lang.model.element.AnnotationValue;
033    import javax.lang.model.element.Element;
034    import javax.lang.model.element.ExecutableElement;
035    import javax.lang.model.element.TypeElement;
036    import javax.lang.model.type.DeclaredType;
037    import javax.lang.model.type.TypeMirror;
038    import javax.tools.JavaCompiler;
039    import javax.tools.JavaFileObject;
040    
041    import com.sun.source.tree.CompilationUnitTree;
042    import com.sun.source.tree.Scope;
043    import com.sun.source.tree.Tree;
044    import com.sun.source.util.SourcePositions;
045    import com.sun.source.util.TreePath;
046    import com.sun.source.util.Trees;
047    import com.sun.tools.javac.code.Symbol.ClassSymbol;
048    import com.sun.tools.javac.code.Symbol.TypeSymbol;
049    import com.sun.tools.javac.code.Symbol;
050    import com.sun.tools.javac.comp.Attr;
051    import com.sun.tools.javac.comp.AttrContext;
052    import com.sun.tools.javac.comp.Enter;
053    import com.sun.tools.javac.comp.Env;
054    import com.sun.tools.javac.comp.MemberEnter;
055    import com.sun.tools.javac.comp.Resolve;
056    import com.sun.tools.javac.model.JavacElements;
057    import com.sun.tools.javac.processing.JavacProcessingEnvironment;
058    import com.sun.tools.javac.tree.JCTree.*;
059    import com.sun.tools.javac.tree.JCTree;
060    import com.sun.tools.javac.tree.TreeCopier;
061    import com.sun.tools.javac.tree.TreeInfo;
062    import com.sun.tools.javac.tree.TreeMaker;
063    import com.sun.tools.javac.util.Context;
064    import com.sun.tools.javac.util.List;
065    import com.sun.tools.javac.util.Log;
066    import com.sun.tools.javac.util.Pair;
067    
068    /**
069     * Provides an implementation of Trees.
070     *
071     * <p><b>This is NOT part of any API supported by Sun Microsystems.
072     * If you write code that depends on this, you do so at your own
073     * risk.  This code and its internal interfaces are subject to change
074     * or deletion without notice.</b></p>
075     *
076     * @author Peter von der Ah&eacute;
077     */
078    public class JavacTrees extends Trees {
079    
080        private final Resolve resolve;
081        private final Enter enter;
082        private final Log log;
083        private final MemberEnter memberEnter;
084        private final Attr attr;
085        private final TreeMaker treeMaker;
086        private final JavacElements elements;
087        private final JavacTaskImpl javacTaskImpl;
088    
089        public static JavacTrees instance(JavaCompiler.CompilationTask task) {
090            if (!(task instanceof JavacTaskImpl))
091                throw new IllegalArgumentException();
092            return instance(((JavacTaskImpl)task).getContext());
093        }
094    
095        public static JavacTrees instance(ProcessingEnvironment env) {
096            if (!(env instanceof JavacProcessingEnvironment))
097                throw new IllegalArgumentException();
098            return instance(((JavacProcessingEnvironment)env).getContext());
099        }
100    
101        public static JavacTrees instance(Context context) {
102            JavacTrees instance = context.get(JavacTrees.class);
103            if (instance == null)
104                instance = new JavacTrees(context);
105            return instance;
106        }
107    
108        private JavacTrees(Context context) {
109            context.put(JavacTrees.class, this);
110            attr = Attr.instance(context);
111            enter = Enter.instance(context);
112            elements = JavacElements.instance(context);
113            log = Log.instance(context);
114            resolve = Resolve.instance(context);
115            treeMaker = TreeMaker.instance(context);
116            memberEnter = MemberEnter.instance(context);
117            javacTaskImpl = context.get(JavacTaskImpl.class);
118        }
119    
120        public SourcePositions getSourcePositions() {
121            return new SourcePositions() {
122                    public long getStartPosition(CompilationUnitTree file, Tree tree) {
123                        return TreeInfo.getStartPos((JCTree) tree);
124                    }
125    
126                    public long getEndPosition(CompilationUnitTree file, Tree tree) {
127                        Map<JCTree,Integer> endPositions = ((JCCompilationUnit) file).endPositions;
128                        return TreeInfo.getEndPos((JCTree) tree, endPositions);
129                    }
130                };
131        }
132    
133        public JCClassDecl getTree(TypeElement element) {
134            return (JCClassDecl) getTree((Element) element);
135        }
136    
137        public JCMethodDecl getTree(ExecutableElement method) {
138            return (JCMethodDecl) getTree((Element) method);
139        }
140    
141        public JCTree getTree(Element element) {
142            Symbol symbol = (Symbol) element;
143            TypeSymbol enclosing = symbol.enclClass();
144            Env<AttrContext> env = enter.getEnv(enclosing);
145            if (env == null)
146                return null;
147            JCClassDecl classNode = env.enclClass;
148            if (classNode != null) {
149                if (TreeInfo.symbolFor(classNode) == element)
150                    return classNode;
151                for (JCTree node : classNode.getMembers())
152                    if (TreeInfo.symbolFor(node) == element)
153                        return node;
154            }
155            return null;
156        }
157    
158        public JCTree getTree(Element e, AnnotationMirror a) {
159            return getTree(e, a, null);
160        }
161    
162        public JCTree getTree(Element e, AnnotationMirror a, AnnotationValue v) {
163            Pair<JCTree, JCCompilationUnit> treeTopLevel = elements.getTreeAndTopLevel(e, a, v);
164            if (treeTopLevel == null)
165                return null;
166            return treeTopLevel.fst;
167        }
168    
169        public TreePath getPath(CompilationUnitTree unit, Tree node) {
170            return TreePath.getPath(unit, node);
171        }
172    
173        public TreePath getPath(Element e) {
174            return getPath(e, null, null);
175        }
176    
177        public TreePath getPath(Element e, AnnotationMirror a) {
178            return getPath(e, a, null);
179        }
180    
181        public TreePath getPath(Element e, AnnotationMirror a, AnnotationValue v) {
182            final Pair<JCTree, JCCompilationUnit> treeTopLevel = elements.getTreeAndTopLevel(e, a, v);
183            if (treeTopLevel == null)
184                return null;
185            return TreePath.getPath(treeTopLevel.snd, treeTopLevel.fst);
186        }
187    
188        public Element getElement(TreePath path) {
189            Tree t = path.getLeaf();
190            return TreeInfo.symbolFor((JCTree) t);
191        }
192    
193        public TypeMirror getTypeMirror(TreePath path) {
194            Tree t = path.getLeaf();
195            return ((JCTree)t).type;
196        }
197    
198        public JavacScope getScope(TreePath path) {
199            return new JavacScope(getAttrContext(path));
200        }
201    
202        public boolean isAccessible(Scope scope, TypeElement type) {
203            if (scope instanceof JavacScope && type instanceof ClassSymbol) {
204                Env<AttrContext> env = ((JavacScope) scope).env;
205                return resolve.isAccessible(env, (ClassSymbol)type);
206            } else
207                return false;
208        }
209    
210        public boolean isAccessible(Scope scope, Element member, DeclaredType type) {
211            if (scope instanceof JavacScope
212                    && member instanceof Symbol
213                    && type instanceof com.sun.tools.javac.code.Type) {
214                Env<AttrContext> env = ((JavacScope) scope).env;
215                return resolve.isAccessible(env, (com.sun.tools.javac.code.Type)type, (Symbol)member);
216            } else
217                return false;
218        }
219    
220        private Env<AttrContext> getAttrContext(TreePath path) {
221            if (!(path.getLeaf() instanceof JCTree))  // implicit null-check
222                throw new IllegalArgumentException();
223    
224            // if we're being invoked via from a JSR199 client, we need to make sure
225            // all the classes have been entered; if we're being invoked from JSR269,
226            // then the classes will already have been entered.
227            if (javacTaskImpl != null) {
228                try {
229                    javacTaskImpl.enter(null);
230                } catch (IOException e) {
231                    throw new Error("unexpected error while entering symbols: " + e);
232                }
233            }
234    
235    
236            JCCompilationUnit unit = (JCCompilationUnit) path.getCompilationUnit();
237            Copier copier = new Copier(treeMaker.forToplevel(unit));
238    
239            Env<AttrContext> env = null;
240            JCMethodDecl method = null;
241            JCVariableDecl field = null;
242    
243            List<Tree> l = List.nil();
244            TreePath p = path;
245            while (p != null) {
246                l = l.prepend(p.getLeaf());
247                p = p.getParentPath();
248            }
249    
250            for ( ; l.nonEmpty(); l = l.tail) {
251                Tree tree = l.head;
252                switch (tree.getKind()) {
253                    case COMPILATION_UNIT:
254    //                    System.err.println("COMP: " + ((JCCompilationUnit)tree).sourcefile);
255                        env = enter.getTopLevelEnv((JCCompilationUnit)tree);
256                        break;
257                    case CLASS:
258    //                    System.err.println("CLASS: " + ((JCClassDecl)tree).sym.getSimpleName());
259                        env = enter.getClassEnv(((JCClassDecl)tree).sym);
260                        break;
261                    case METHOD:
262    //                    System.err.println("METHOD: " + ((JCMethodDecl)tree).sym.getSimpleName());
263                        method = (JCMethodDecl)tree;
264                        break;
265                    case VARIABLE:
266    //                    System.err.println("FIELD: " + ((JCVariableDecl)tree).sym.getSimpleName());
267                        field = (JCVariableDecl)tree;
268                        break;
269                    case BLOCK: {
270    //                    System.err.println("BLOCK: ");
271                        if (method != null)
272                            env = memberEnter.getMethodEnv(method, env);
273                        JCTree body = copier.copy((JCTree)tree, (JCTree) path.getLeaf());
274                        env = attribStatToTree(body, env, copier.leafCopy);
275                        return env;
276                    }
277                    default:
278    //                    System.err.println("DEFAULT: " + tree.getKind());
279                        if (field != null && field.getInitializer() == tree) {
280                            env = memberEnter.getInitEnv(field, env);
281                            JCExpression expr = copier.copy((JCExpression)tree, (JCTree) path.getLeaf());
282                            env = attribExprToTree(expr, env, copier.leafCopy);
283                            return env;
284                        }
285                }
286            }
287            return field != null ? memberEnter.getInitEnv(field, env) : env;
288        }
289    
290        private Env<AttrContext> attribStatToTree(JCTree stat, Env<AttrContext>env, JCTree tree) {
291            JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
292            try {
293                return attr.attribStatToTree(stat, env, tree);
294            } finally {
295                log.useSource(prev);
296            }
297        }
298    
299        private Env<AttrContext> attribExprToTree(JCExpression expr, Env<AttrContext>env, JCTree tree) {
300            JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
301            try {
302                return attr.attribExprToTree(expr, env, tree);
303            } finally {
304                log.useSource(prev);
305            }
306        }
307    
308        /**
309         * Makes a copy of a tree, noting the value resulting from copying a particular leaf.
310         **/
311        static class Copier extends TreeCopier<JCTree> {
312            JCTree leafCopy = null;
313    
314            Copier(TreeMaker M) {
315                super(M);
316            }
317    
318            public <T extends JCTree> T copy(T t, JCTree leaf) {
319                T t2 = super.copy(t, leaf);
320                if (t == leaf)
321                    leafCopy = t2;
322                return t2;
323            }
324        }
325    
326        /**
327         * Gets the original type from the ErrorType object.
328         * @param errorType The errorType for which we want to get the original type.
329         * @returns TypeMirror corresponding to the original type, replaced by the ErrorType.
330         *          noType (type.tag == NONE) is returned if there is no original type.
331         */
332        public TypeMirror getOriginalType(javax.lang.model.type.ErrorType errorType) {
333            if (errorType instanceof com.sun.tools.javac.code.Type.ErrorType) {
334                return ((com.sun.tools.javac.code.Type.ErrorType)errorType).getOriginalType();
335            }
336    
337            return com.sun.tools.javac.code.Type.noType;
338        }
339    }