KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > source > builder > ASTService


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.java.source.builder;
20
21 import org.netbeans.modules.java.source.engine.ASTModel;
22 import org.netbeans.modules.java.source.engine.TreeFinder;
23 import org.netbeans.modules.java.source.engine.RootTree;
24 import java.util.ArrayList JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.Stack JavaDoc;
28 import javax.lang.model.SourceVersion;
29 import javax.lang.model.element.Element;
30 import javax.lang.model.type.TypeMirror;
31 import javax.tools.JavaFileObject;
32 import org.netbeans.api.java.source.*;
33 import org.netbeans.modules.java.source.engine.RootTree;
34 import org.netbeans.modules.java.source.engine.TreeFinder;
35 import org.netbeans.modules.java.source.engine.ReattributionException;
36
37 import com.sun.source.tree.*;
38 import com.sun.source.util.TreeScanner;
39
40 import com.sun.tools.javac.code.*;
41 import com.sun.tools.javac.code.Symbol.*;
42 import com.sun.tools.javac.tree.JCTree;
43 import com.sun.tools.javac.tree.JCTree.*;
44 import com.sun.tools.javac.tree.TreeInfo;
45 import com.sun.tools.javac.util.*;
46 import java.util.Collections JavaDoc;
47 import org.netbeans.api.java.source.transform.UndoEntry;
48 import org.netbeans.api.java.source.transform.UndoList;
49
50 import static com.sun.tools.javac.tree.JCTree.*;
51
52 /**
53  * A javac abstract syntax tree which maps all nodes to a single root.
54  */

55 public final class ASTService implements ASTModel {
56     
57     private RootTree root;
58     private UndoList undoList;
59     private TreeFactory treeFactory;
60     private Name.Table names;
61     private Symtab symtab;
62     private ElementsService elements;
63     private Source source;
64     private Map JavaDoc<JavaFileObject, Map JavaDoc<JCTree, Integer JavaDoc>> endPosTables;
65     
66     // Debugging flag that verifies tree changes are correct after translation.
67
private boolean reattribute = Boolean.getBoolean("jackpot.always.attribute"); //NOI18N
68

69     private static final Context.Key<ASTService> treeKey = new Context.Key<ASTService>();
70     
71     public static synchronized ASTService instance(Context context) {
72         ASTService instance = context.get(treeKey);
73         if (instance == null)
74             instance = new ASTService(context);
75         return instance;
76     }
77     
78     /**
79      * Create a new Trees, using an existing root node.
80      */

81     protected ASTService(Context context) {
82         context.put(treeKey, this);
83         undoList = UndoListService.instance(context);
84         treeFactory = TreeFactory.instance(context);
85         names = Name.Table.instance(context);
86         symtab = Symtab.instance(context);
87         elements = ElementsService.instance(context);
88         source = Source.instance(context);
89         endPosTables = new HashMap JavaDoc<JavaFileObject, Map JavaDoc<JCTree, Integer JavaDoc>>();
90     }
91     
92     /**
93      * Return the current root tree.
94      */

95     public Tree getRoot() {
96         return root;
97     }
98     
99     /**
100      * Replace the current root tree.
101      */

102     public void setRoot(final RootTree tree) throws ReattributionException {
103         if (tree == root)
104             return;
105         
106         /* FIXME: port reattribution
107         try {
108             if (reattribute) {
109                 if (env instanceof ModifiableCommandEnvironment) {
110                     Context newContext = Reattributer.reattribute(env, newRoot);
111                     if (false) // turn off attribution resetting.
112                         setContext(newContext);
113                     else
114                         model.setRoot((RootTree)newRoot);
115                 }
116                 else
117                     throw new UnsupportedOperationException("Unmodifiable environment context");
118             } else
119                 model.setRoot((RootTree)newRoot);
120             env.getUndoList().setEndCommand(true);
121         } catch (ReattributionException e) {
122             UndoList undoList = env.getUndoList();
123             if (!undoList.atEndCommand())
124                 // undo changes made by this transformer
125                 undoList.undo();
126             error(e);
127         }
128          */

129         
130         undoList.addAndApply(new UndoEntry() {
131             private final RootTree old = root;
132             @Override JavaDoc
133             public void undo() {
134                 root = old;
135             }
136             @Override JavaDoc
137             public void redo() {
138                 root = tree;
139             }
140             @Override JavaDoc
141             public <T> T getOld(T o) {
142                 return (o == tree) ? (T)old : null;
143             }
144         });
145     }
146
147     /*FIXME: reattribution support
148     private void setContext(final Context newContext) {
149         final Context oldContext = getContext();
150         if (newContext == oldContext)
151             return;
152         UndoEntry u = new UndoEntry() {
153             private final Context old = oldContext;
154             @Override
155             public void undo() {
156                 setContextImpl(old);
157             }
158             @Override
159             public void redo() {
160                 setContextImpl(newContext);
161             }
162             @Override
163             public <T> T getOld(T o) {
164                 return (o == newContext) ? (T)old : null;
165             }
166         };
167     undoList.add(u); // UndoLists are shared between contexts
168     u.redo(); // actually set the context
169     }
170     
171     private void setContextImpl(Context newContext) {
172         ((ModifiableCommandEnvironment)env).setContext(newContext);
173     }
174      */

175     
176     /**
177      * Finds the defining tree for a symbol.
178      */

179     public Tree find(final Element s) {
180         if (s == null)
181             return null;
182         final JCTree[] rtn = new JCTree[1];
183         new TreeScanner<Void JavaDoc,Object JavaDoc>() {
184             boolean found = false;
185             @Override JavaDoc
186                     public Void JavaDoc scan(Tree tree, Object JavaDoc p) {
187                 if(!found && tree != null) {
188                     found = TreeInfo.symbolFor((JCTree)tree) == s;
189                     if (found)
190                         rtn[0] = (JCTree)tree;
191                     else
192                         super.scan(tree, null);
193                 }
194                 return null;
195             }
196         }.scan(root, null);
197         return rtn[0];
198     }
199     
200     /**
201      * Finds the tree associated with a specified source file name.
202      */

203     public CompilationUnitTree findTopLevel(final String JavaDoc sourceFile) {
204         final CompilationUnitTree[] rtn = new CompilationUnitTree[1];
205         new TreeScanner<Void JavaDoc,Object JavaDoc>() {
206             @Override JavaDoc
207                     public Void JavaDoc visitCompilationUnit(CompilationUnitTree t, Object JavaDoc p) {
208                 if (rtn[0] == null && t.getSourceFile().toUri().getPath().endsWith(sourceFile))
209                     rtn[0] = (JCCompilationUnit)t;
210                 else
211                     super.visitCompilationUnit(t, p);
212                 return null;
213             }
214         }.scan(root, null);
215         return rtn[0];
216     }
217     
218     /**
219      * Return the JCCompilationUnit parent of a specified tree.
220      *
221      * @return the JCCompilationUnit, or null if tree is a PackageDef.
222      */

223     public CompilationUnitTree getTopLevel(Tree tree) {
224         if (tree == null)
225             return null;
226         Tree[] path = makePath(root, tree);
227         for (int i = 0; i < path.length; i++)
228             if (path[i] instanceof CompilationUnitTree)
229                 return (CompilationUnitTree)path[i];
230         assert tree instanceof RootTree;
231         return null;
232     }
233     
234     /**
235      * Returns the element for a specified tree. Null is returned if the
236      * tree type doesn't have an associated element, or if the reference
237      * is not resolved.
238      */

239     public Element getElement(Tree tree) {
240         if (tree == null)
241             return null;
242         switch (tree.getKind()) {
243             case COMPILATION_UNIT: return ((JCCompilationUnit)tree).packge;
244             case CLASS: return ((JCClassDecl)tree).sym;
245             case METHOD: return ((JCMethodDecl)tree).sym;
246             case VARIABLE: return ((JCVariableDecl)tree).sym;
247             case MEMBER_SELECT: return ((JCFieldAccess)tree).sym;
248             case IDENTIFIER: return ((JCIdent)tree).sym;
249             case NEW_CLASS: return ((JCNewClass)tree).constructor;
250             default:
251                 return null;
252         }
253     }
254     
255     public TypeMirror getType(Tree tree) {
256         if (tree == null || tree instanceof RootTree)
257             return null;
258         TypeMirror type = ((JCTree)tree).type;
259         if (type == null) {
260             Element e = getElement(tree);
261             if (e != null)
262                 type = e.asType();
263         }
264         return type;
265     }
266     
267     /**
268      * Sets the element associated with a Tree. This should only be done
269      * either on trees created by TreeMaker or clone(), and never on original
270      * trees.
271      *
272      * @see org.netbeans.api.java.source.TreeMaker
273      * @see #clone
274      */

275     public void setElement(Tree tree, Element element) {
276         switch (((JCTree)tree).tag) {
277             case TOPLEVEL:
278                 ((JCCompilationUnit)tree).packge = (Symbol.PackageSymbol)element;
279                 break;
280             case CLASSDEF:
281                 ((JCClassDecl)tree).sym = (Symbol.ClassSymbol)element;
282                 break;
283             case METHODDEF:
284                 ((JCMethodDecl)tree).sym = (Symbol.MethodSymbol)element;
285                 break;
286             case VARDEF:
287                 ((JCVariableDecl)tree).sym = (Symbol.VarSymbol)element;
288                 break;
289             case SELECT:
290                 ((JCFieldAccess)tree).sym = (Symbol)element;
291                 break;
292             case IDENT:
293                 ((JCIdent)tree).sym = (Symbol)element;
294                 break;
295             case NEWCLASS:
296                 ((JCNewClass)tree).constructor = (Symbol)element;
297                 break;
298             default:
299                 throw new IllegalArgumentException JavaDoc("invalid tree type: " + tree.getKind());
300         }
301     }
302     
303     /**
304      * Sets the TypeMirror associated with a Tree. This should only be done
305      * either on trees created by TreeMaker or clone(), and never on original
306      * trees.
307      *
308      * @see org.netbeans.api.java.source.TreeMaker
309      * @see #clone
310      */

311     public void setType(Tree tree, TypeMirror type) {
312         ((JCTree)tree).type = (Type)type;
313     }
314     
315     /**
316      * Returns true if this is an identifier for "this".
317      */

318     public boolean isThis(IdentifierTree t) {
319     return t instanceof IdentifierTree && isThis(((JCIdent)t).name);
320     }
321
322     private static boolean isThis(Name nm) {
323     return nm==nm.table._this;
324     }
325
326     /**
327      * Returns true if this is an element for "this".
328      */

329     public boolean isThis(Element e) {
330     return e != null ? isThis(((Symbol)e).name) : false;
331     }
332
333     public boolean isSynthetic(Tree tree) {
334         if (tree == null)
335             return false;
336         long flags = 0L;
337         JCTree t = (JCTree)tree;
338         switch (t.tag) {
339           case JCTree.CLASSDEF:
340             flags = ((JCClassDecl)t).mods.flags;
341             break;
342           case JCTree.METHODDEF:
343             flags = ((JCMethodDecl)t).mods.flags;
344             break;
345           case JCTree.VARDEF:
346             flags = ((JCVariableDecl)t).mods.flags;
347             break;
348           case JCTree.BLOCK:
349             if (t.pos == Position.NOPOS)
350                 return true;
351             flags = ((JCBlock)t).flags;
352             break;
353           case JCTree.MODIFIERS:
354             if (t.pos == Position.NOPOS)
355                 return true;
356         }
357         return (flags & Flags.SYNTHETIC) != 0L;
358     }
359
360     /**
361      * Returns a tree path from a specified root tree to a specified
362      * target tree. If the target is not a child of the root tree,
363      * then a zero-length array is returned.
364      */

365     public Tree[] makePath(final Tree root, final Tree target) {
366         final Stack JavaDoc<Tree> stack = new Stack JavaDoc<Tree>();
367         root.accept(new TreeFinder(target) {
368             @Override JavaDoc
369             public Boolean JavaDoc scan(Tree tree, Object JavaDoc o) {
370                 super.scan(tree, o);
371                 if (found)
372                     stack.push(tree);
373                 return found;
374             }
375         }, null);
376         Tree[] path = new Tree[stack.size()];
377         for (int i = 0; i < path.length; i++)
378             path[i] = stack.pop();
379         return path;
380     }
381     
382     /**
383      * Get the position for a tree node.
384      */

385     public int getPos(Tree tree) {
386         if (tree == null)
387         return Position.NOPOS;
388         return ((JCTree)tree).pos;
389     }
390
391     /**
392      * Get the start position for a tree node.
393      */

394     public int getStartPos(Tree tree) {
395     if (tree == null)
396         return Position.NOPOS;
397     switch(((JCTree)tree).tag) {
398             case(JCTree.APPLY):
399                 return getStartPos(((JCMethodInvocation)tree).meth);
400             case(JCTree.ASSIGN):
401                 return getStartPos(((JCAssign)tree).lhs);
402             case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
403             case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
404             case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
405             case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
406                 return getStartPos(((JCAssignOp)tree).lhs);
407             case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
408             case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
409             case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
410             case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
411             case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
412             case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
413             case(JCTree.MOD):
414                 return getStartPos(((JCBinary)tree).lhs);
415             case(JCTree.CLASSDEF): {
416                 JCClassDecl node = (JCClassDecl)tree;
417                 if (node.mods.pos != Position.NOPOS)
418                     return node.mods.pos;
419                 break;
420             }
421             case(JCTree.CONDEXPR):
422                 return getStartPos(((JCConditional)tree).cond);
423             case(JCTree.EXEC):
424                 return getStartPos(((JCExpressionStatement)tree).expr);
425             case(JCTree.INDEXED):
426                 return getStartPos(((JCArrayAccess)tree).indexed);
427             case(JCTree.METHODDEF): {
428                 JCMethodDecl node = (JCMethodDecl)tree;
429                 if (node.mods.pos != Position.NOPOS)
430                     return node.mods.pos;
431                 if (node.restype != null) // true for constructors
432
return getStartPos(node.restype);
433                 return node.pos;
434             }
435             case(JCTree.SELECT):
436                 return getStartPos(((JCFieldAccess)tree).selected);
437             case(JCTree.TYPEAPPLY):
438                 return getStartPos(((JCTypeApply)tree).clazz);
439             case(JCTree.TYPEARRAY):
440                 return getStartPos(((JCArrayTypeTree)tree).elemtype);
441             case(JCTree.TYPETEST):
442                 return getStartPos(((JCInstanceOf)tree).expr);
443             case(JCTree.POSTINC):
444             case(JCTree.POSTDEC):
445                 return getStartPos(((JCUnary)tree).arg);
446             case(JCTree.VARDEF): {
447                 JCVariableDecl node = (JCVariableDecl)tree;
448                 if (node.mods.pos != Position.NOPOS)
449                     return node.mods.pos;
450                 return getStartPos(node.vartype);
451             }
452     }
453     return ((JCTree)tree).pos;
454     }
455             
456     /**
457      * Get the end position for a tree node.
458      */

459     public int getEndPos(Tree tree, CompilationUnitTree topLevel) {
460         Map JavaDoc<JCTree,Integer JavaDoc> endPositions =
461             topLevel != null ? endPosTables.get(topLevel.getSourceFile()) : null;
462     if (tree == null || endPositions == null)
463         return Position.NOPOS;
464
465     Integer JavaDoc mapPos = endPositions.get(tree);
466     if (mapPos != null)
467         return mapPos;
468
469         JCTree t = (JCTree)tree;
470     switch(t.tag) {
471         case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG):
472         case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG):
473         case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG):
474         case(JCTree.DIV_ASG): case(JCTree.MOD_ASG):
475         return getEndPos(((JCAssignOp)tree).rhs, topLevel);
476         case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR):
477         case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ):
478         case(JCTree.NE): case(JCTree.LT): case(JCTree.GT):
479         case(JCTree.LE): case(JCTree.GE): case(JCTree.SL):
480         case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS):
481         case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV):
482         case(JCTree.MOD):
483         return getEndPos(((JCBinary)tree).rhs, topLevel);
484         case(JCTree.CASE):
485         return getEndPos(((JCCase)tree).stats.last(), topLevel);
486         case(JCTree.CATCH):
487         return getEndPos(((JCCatch)tree).body, topLevel);
488         case(JCTree.EXEC):
489                 return getEndPos(((JCExpressionStatement)tree).expr, topLevel);
490         case(JCTree.CONDEXPR):
491         return getEndPos(((JCConditional)tree).falsepart, topLevel);
492         case(JCTree.FORLOOP):
493         if (tree instanceof JCForLoop) {
494             return getEndPos(((JCForLoop)tree).body, topLevel);
495         } else {
496             return getEndPos(((JCEnhancedForLoop)tree).body, topLevel);
497         }
498         case(JCTree.IDENT):
499         return t.pos + ((JCIdent)tree).name.len;
500         case(JCTree.IF): {
501         JCIf node = (JCIf)tree;
502         if (node.elsepart == null) {
503             return getEndPos(node.thenpart, topLevel);
504         } else {
505             return getEndPos(node.elsepart, topLevel);
506         }
507         }
508             case(JCTree.FOREACHLOOP):
509                 return getEndPos(((JCEnhancedForLoop)tree).body, topLevel);
510         case(JCTree.LABELLED):
511         return getEndPos(((JCLabeledStatement)tree).body, topLevel);
512         case(JCTree.MODIFIERS):
513         return getEndPos(((JCModifiers)tree).annotations.last(), topLevel);
514         case(JCTree.SELECT): {
515         JCFieldAccess select = (JCFieldAccess)tree;
516         return getEndPos(select.selected, topLevel) + 1 /*'.'*/ + select.name.len;
517         }
518         case(JCTree.SYNCHRONIZED):
519         return getEndPos(((JCSynchronized)tree).body, topLevel);
520         case(JCTree.TOPLEVEL):
521         return getEndPos(((JCCompilationUnit)tree).defs.last(), topLevel);
522         case(JCTree.TRY): {
523         JCTry node = (JCTry)tree;
524         if (node.finalizer == null) {
525             return getEndPos(node.catchers.last(), topLevel);
526         } else {
527             return getEndPos(node.finalizer, topLevel);
528         }
529         }
530         case(JCTree.TYPECAST):
531         return getEndPos(((JCTypeCast)tree).expr, topLevel);
532         case(JCTree.TYPETEST):
533         return getEndPos(((JCInstanceOf)tree).clazz, topLevel);
534         case(JCTree.WILDCARD):
535         return getEndPos(((JCWildcard)tree).inner, topLevel);
536         case(JCTree.POS):
537         case(JCTree.NEG):
538         case(JCTree.NOT):
539         case(JCTree.COMPL):
540         case(JCTree.PREINC):
541         case(JCTree.PREDEC):
542         return getEndPos(((JCUnary)tree).arg, topLevel);
543         case(JCTree.WHILELOOP):
544         return getEndPos(((JCWhileLoop)tree).body, topLevel);
545     }
546     return Position.NOPOS;
547     }
548
549     // Private methods
550

551     private Tree findChild(Tree tree, Symbol s) {
552         for (Tree child : getChildren(tree)) {
553             if (getElement(child) == s)
554                 return child;
555         }
556         return null;
557     }
558     
559     /**
560      * Find a child symbol based on name and optional parameter types.
561      *
562      * @param s the parent symbol
563      * @param child the name of the child
564      * @param parameters the parameter type list, if the child is a method;
565      * if it is not, then this parameter is null.
566      */

567     private Symbol findChild(Symbol s, String JavaDoc child, String JavaDoc[] parameters) {
568         com.sun.tools.javac.code.Scope scope = s.members();
569         com.sun.tools.javac.code.Scope.Entry e = scope.lookup(names.fromString(child));
570         if (e != null && parameters != null) {
571             // search for method with same parameter types
572
while (e.scope == scope) {
573                 if (e.sym instanceof MethodSymbol) {
574                     MethodSymbol meth = (MethodSymbol)e.sym;
575                     if (compareParams(meth.params(), parameters))
576                         return meth;
577                 }
578                 e = e.next();
579             }
580             return null;
581         }
582     return e != null ? e.sym : null;
583     }
584        
585     private boolean compareParams(List JavaDoc<VarSymbol> p1, String JavaDoc[] p2) {
586         if (p1.size() != p2.length)
587             return false;
588         int i = 0;
589         for (VarSymbol var : p1) {
590             String JavaDoc s1 = var.type.toString();
591             String JavaDoc s2 = p2[i++];
592             if (!s1.equals(s2))
593                 return false;
594         }
595         return true;
596     }
597     
598     public boolean isStatic(Tree tree) {
599         if (tree == null)
600             return false;
601         Symbol sym = (Symbol)getElement(tree);
602         return sym != null ? (sym.flags() & Flags.STATIC) != 0 : false;
603     }
604     
605     /**
606      * Returns how many references to instance variables or methods there are
607      * in a given tree.
608      */

609     public int getInstanceReferenceCount(Tree t) {
610         if (t == null)
611             return 0;
612         return elements.getCharacterization(getElement(t)).getThisUseCount();
613     }
614     
615     public void setPos(Tree tree, int newPos) {
616         ((JCTree)tree).pos = newPos;
617     }
618     
619     public SourceVersion sourceVersion() {
620         return Source.toSourceVersion(source);
621     }
622     
623     public void setEndPosTable(JavaFileObject name, Map JavaDoc<JCTree, Integer JavaDoc> table) {
624         endPosTables.put(name, table);
625     }
626
627     public java.util.List JavaDoc<? extends Tree> getChildren(Tree tree) {
628         if (tree instanceof RootTree)
629             return ((RootTree)tree).getCompilationUnits();
630         if (tree instanceof CompilationUnitTree)
631             return ((CompilationUnitTree)tree).getTypeDecls();
632         if (tree instanceof ClassTree)
633             return ((ClassTree)tree).getMembers();
634         return Collections.emptyList();
635     }
636 }
637
Popular Tags