KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > api > java > source > query > Query


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-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.api.java.source.query;
21
22 import org.netbeans.api.java.source.ElementUtilities;
23 import org.netbeans.api.java.source.query.NodeScanner;
24 import org.netbeans.api.java.source.query.TreeMatcher;
25 import java.util.logging.Level JavaDoc;
26 import java.util.logging.Logger JavaDoc;
27 import javax.lang.model.SourceVersion;
28 import org.netbeans.api.java.source.query.QueryEnvironment;
29 import org.netbeans.modules.java.source.engine.ElapsedTimer;
30 import org.openide.util.NbBundle;
31 import com.sun.source.tree.*;
32 import com.sun.source.util.TreeScanner;
33 import com.sun.source.util.Trees;
34 import javax.lang.model.element.*;
35 import javax.lang.model.type.*;
36 import javax.lang.model.util.Types;
37 import java.text.MessageFormat JavaDoc;
38 import java.util.List JavaDoc;
39 import java.util.Set JavaDoc;
40 import static com.sun.source.tree.Tree.Kind.*;
41
42 /**
43  * An Query is a command that is applied to a JCTree and creates a
44  * ResultSet. The ResultSet is generated asynchronously, so that
45  * results are returned as the command is executing.
46  */

47 public abstract class Query<R,P> extends NodeScanner<R,P> implements Command {
48
49     protected ElementUtilities elements;
50     protected Types types;
51     protected Trees trees;
52     protected SearchResult result = null;
53     protected String JavaDoc queryDescription = null;
54     protected SearchEntry lastAddition;
55     private UseFinder useFinder;
56     
57     static final Logger JavaDoc logger = Logger.getLogger("org.netbeans.modules.java.source");
58
59     /**
60      * For JCTree instances that have no associated source position.
61      */

62     public static final int NOPOS = -2;
63     
64     /**
65      * Initialize any data that is shared across source file processing
66      * invocations.
67      */

68     @Override JavaDoc
69     public void init() {
70         result = new SearchResult(this, getQueryDescription());
71     }
72
73     /**
74      * Attach this Query instance to the specified QueryEnvironment prior
75      * to processing one or more source files.
76      */

77     @Override JavaDoc
78     public void attach(QueryEnvironment env) {
79         super.attach(env);
80         trees = env.getTrees();
81         elements = env.getElementUtilities();
82         types = env.getTypes();
83         result.attach(env);
84     }
85     
86     /**
87      * Release any instance data created by attach() or the processing of
88      * a set of source files. All references to the attached QueryEnvironment
89      * and its source files must be released.
90      */

91     @Override JavaDoc
92     public void release() {
93         super.release();
94         trees = null;
95         elements = null;
96         types = null;
97         //result.release(); // enable when async results are supported
98
}
99     
100     /**
101      * Release any instance data shared by invocations.
102      */

103     @Override JavaDoc
104     public void destroy() {
105         super.destroy();
106         result = null;
107     }
108
109     public void apply() {
110         logStart();
111         ElapsedTimer timer = new ElapsedTimer();
112         apply(getRootNode());
113         logStats(timer.toString());
114         show(result, getQueryDescription());
115     }
116     
117     private void logStart() {
118         String JavaDoc key = this instanceof org.netbeans.api.java.source.transform.Transformer ?
119             "Transformer.running.transformer" : "Query.running.query"; //NOI18N
120
logger.log(Level.FINE, getString(key));
121     }
122     
123     public void apply(Tree t) {
124     if(t != null)
125         t.accept(this, null);
126     }
127
128     private void logStats(String JavaDoc time) {
129         String JavaDoc key = this instanceof org.netbeans.api.java.source.transform.Transformer ?
130             "Query.query.stats" : "Transformer.query.stats"; //NOI18N
131
String JavaDoc statFormat = getString(key);
132
133         if (logger.isLoggable(Level.FINE)) {
134             Runtime JavaDoc rt = Runtime.getRuntime();
135             System.gc();
136             long usedMemory = (rt.totalMemory() - rt.freeMemory()) / 1024;
137             logger.log(Level.FINE, MessageFormat.format(statFormat, time, usedMemory));
138         }
139     }
140     
141     private void showNoResults() {
142         String JavaDoc fmt = getString("Query.noResults");
143         String JavaDoc msg = MessageFormat.format(fmt, queryDescription);
144         logger.log(Level.INFO, msg);
145         env.setStatusMessage(msg);
146     }
147     
148     private String JavaDoc getString(String JavaDoc key) {
149         return NbBundle.getBundle(Query.class).getString(key); //NOI18N
150
}
151     
152     public QueryEnvironment getEnvironment() {
153     return env;
154     }
155
156     /**
157      * Throws an QueryException with the specified object as its cause.
158      */

159     public final void error(Object JavaDoc o) {
160         throw new QueryException(o.toString());
161     }
162     
163     public final void error(QueryException o) {
164         throw o;
165     }
166     
167     public final void error(Throwable JavaDoc t) {
168         throw new QueryException(t);
169     }
170     
171     public final void note(String JavaDoc s) {
172         env.setStatusMessage(s);
173     }
174     
175     public final void show(SearchResult sr, String JavaDoc title) {
176     if (result != null && result.size() > 0)
177             env.setResult(sr, title);
178         else
179             showNoResults();
180     }
181     
182     public final void show(ResultTableModel[] result, String JavaDoc title) {
183     if (result != null && result.length > 0)
184             env.setResult(result, title);
185         else
186             showNoResults();
187     }
188
189     /**
190      * Called by subclasses to replace the default result set. Any result
191      * entries in the default set (normally added via addResult()) are
192      * discarded.
193      */

194     protected void setResult(SearchResult sr) {
195         result = sr;
196         for (SearchEntry se : sr.getResults())
197             logger.log(Level.FINE, asLogMessage(se));
198     }
199
200     public final void addResult(Element e, String JavaDoc msg) {
201         addResult(e, null, msg);
202     }
203
204     public final void addResult(Element e, Tree t, String JavaDoc msg) {
205         result.add(lastAddition = new SearchEntry(this, e, t, model.getPos(t), msg, 0));
206     }
207
208     public final void changeResult(Tree oldt, Tree newt) {
209     if(lastAddition!=null && lastAddition.tree==oldt) {
210         lastAddition.tree = newt;
211     }
212     }
213     
214     public String JavaDoc getQueryDescription() {
215     return queryDescription != null ? queryDescription : "Unnamed Query";
216     }
217     
218     public void setQueryDescription(String JavaDoc description) {
219         queryDescription = description;
220     }
221     
222     public ResultTableModel getResult() {
223         return result;
224     }
225     
226     protected String JavaDoc asLogMessage(SearchEntry se) {
227         return result.asLogMessage(se);
228     }
229     
230     protected Tree getRootNode() {
231     return env.getRootNode();
232     }
233
234     public SearchResult findUses(Element e) {
235     if(useFinder==null) useFinder = new UseFinder(env);
236     return useFinder.find(e, getRootNode());
237     }
238
239     /**
240      * Returns the Tree which defines an Element, or null if the definition
241      * cannot be found.
242      */

243     public Tree getTree(Element e) {
244         return trees.getTree(e);
245     }
246     
247     public boolean isOverridden(ExecutableElement s) {
248 // return elements.isOverridden(s);
249
return false; //XXX
250
}
251     
252     public boolean overrides(ExecutableElement s) {
253         return elements.overridesMethod(s);
254     }
255     
256     public boolean referenced(Tree t) {
257     return referenced(model.getElement(t));
258     }
259     
260     public boolean referenced(Element e) {
261     return elements.referenced(e, getCurrentElement());
262     }
263     
264     public boolean assigned(Element e) {
265     return elements.assigned(e, getCurrentElement());
266     }
267
268     public boolean local(Element e) {
269     return e==null || elements.isLocal(e);
270     }
271     public boolean local(Tree t) {
272     return t instanceof IdentifierTree && local(model.getElement(t));
273     }
274     public boolean parameter(Element e) {
275     return elements.parameter(e, getCurrentElement());
276     }
277     public boolean parameter(Tree t) {
278     return parameter(model.getElement(t));
279     }
280     public boolean assigned(Tree t) {
281     return assigned(model.getElement(t));
282     }
283     public final boolean hasComment(Tree t) {
284     return t!=null && env.getCommentHandler().hasComments(t);
285     }
286
287     /**
288      * Returns true if the Modifiers includes an annotation of the
289      * specified type.
290      */

291     protected boolean hasAnnotation(ModifiersTree mods, TypeMirror annotationType) {
292     java.util.List JavaDoc<? extends AnnotationTree> annotations = mods.getAnnotations();
293         for (AnnotationTree ann : annotations)
294             if (model.getType(ann).equals(annotationType))
295                 return true;
296     return false;
297     }
298     
299     public boolean isConstant(Tree tree) {
300         Element e = model.getElement(tree);
301         if (e == null)
302             return false;
303         Set JavaDoc<Modifier> flags = e.getModifiers();
304         if (flags.contains(Modifier.FINAL))
305             return false;
306         return e.asType() instanceof PrimitiveType ||
307                e.equals(env.getElements().getTypeElement("java.lang.String"));
308     }
309
310     public boolean assignedIn(CharSequence JavaDoc n, List JavaDoc<? extends Tree> statements) {
311         for (Tree t : statements)
312         if(assignedIn(n,t)) return true;
313     return false;
314     }
315     private AssignChecker assignChecker;
316     public boolean assignedIn(CharSequence JavaDoc n, Tree t) {
317     if(assignChecker==null) assignChecker = new AssignChecker();
318     return assignChecker.assignedIn(n,t);
319     }
320     private static class AssignChecker extends TreeScanner<Void JavaDoc,Object JavaDoc> {
321     String JavaDoc name;
322     boolean assigned;
323     public boolean assignedIn(CharSequence JavaDoc n, Tree t) {
324         name = n.toString();
325         assigned = false;
326         scan(t, null);
327         return assigned;
328     }
329         @Override JavaDoc
330     public Void JavaDoc scan(Tree tree, Object JavaDoc p) {
331         if(!assigned)
332         super.scan(tree, p);
333             return null;
334     }
335         @Override JavaDoc
336     public Void JavaDoc visitAssignment(AssignmentTree tree, Object JavaDoc p) {
337         if(!checkTarget(tree.getVariable()))
338                 super.visitAssignment(tree, p);
339             return null;
340     }
341         @Override JavaDoc
342     public Void JavaDoc visitCompoundAssignment(CompoundAssignmentTree tree, Object JavaDoc p) {
343         if(!checkTarget(tree.getVariable()))
344                 super.visitCompoundAssignment(tree, p);
345             return null;
346     }
347     public boolean checkTarget(Tree t) {
348         if(t instanceof IdentifierTree &&
349                ((IdentifierTree)t).getName().toString().equals(name))
350         assigned = true;
351         return assigned;
352     }
353     }
354
355     public boolean declaredIn(CharSequence JavaDoc n, List JavaDoc<? extends Tree> statements) {
356         for (Tree t : statements)
357         if(declaredIn(n,t)) return true;
358     return false;
359     }
360     private DeclarationChecker declareChecker;
361     public boolean declaredIn(CharSequence JavaDoc n, Tree t) {
362     if(declareChecker==null) declareChecker = new DeclarationChecker();
363     return declareChecker.declaredIn(n,t);
364     }
365     private static class DeclarationChecker extends TreeScanner<Void JavaDoc,Object JavaDoc> {
366     String JavaDoc name;
367     boolean declared;
368     public boolean declaredIn(CharSequence JavaDoc n, Tree t) {
369         name = n.toString();
370         declared = false;
371         scan(t, null);
372         return declared;
373     }
374         @Override JavaDoc
375     public Void JavaDoc scan(Tree tree, Object JavaDoc p) {
376         if(!declared)
377         super.scan(tree, p);
378             return null;
379     }
380         @Override JavaDoc
381     public Void JavaDoc visitVariable(VariableTree tree, Object JavaDoc p) {
382         if(!checkTarget(tree))
383                 super.visitVariable(tree, p);
384             return null;
385     }
386     public boolean checkTarget(VariableTree t) {
387         if(t.getName().equals(name))
388         declared = true;
389         return declared;
390     }
391     }
392
393     protected final boolean isInstance(Tree t, Element cs) {
394     if(t==null || cs==null) return false;
395     TypeMirror type = model.getType(t);
396     return type!=null && isSubType(type, cs.asType());
397     }
398
399     public boolean isSubType(TypeMirror _this, TypeMirror _that) {
400         if (_this instanceof NoType || _that instanceof NoType ||
401             _this instanceof ExecutableType || _that instanceof ExecutableType ||
402             _this instanceof NullType || _that instanceof NullType)
403             return false;
404     return types.isSubtype(_this, _that);
405     }
406     
407     /**
408      * Returns the -source compiler setting used to build the model.
409      */

410     public SourceVersion sourceVersion() {
411         return model.sourceVersion();
412     }
413     
414     /**
415      * Returns true if the model was built with a -source level the same or
416      * higher than the specified version.
417      */

418     public boolean sourceLevel(SourceVersion version) {
419         return model.sourceVersion().compareTo(version) >= 0;
420     }
421     
422     /**
423      * Returns true if two trees match.
424      */

425     public final boolean matches(Tree a, Tree b) {
426     return matcher().matches(a,b);
427     }
428
429     /**
430      * Returns true if two tree lists match.
431      */

432     public boolean matches(List JavaDoc<? extends Tree> a, List JavaDoc<? extends Tree> b) {
433     return matcher().matches(a,b);
434     }
435
436     public final boolean matches(CharSequence JavaDoc a, Tree b) {
437     return b instanceof IdentifierTree && ((IdentifierTree)b).getName().equals(a);
438     }
439     public final boolean matches(CharSequence JavaDoc a, CharSequence JavaDoc b) {
440     return a.toString().equals(b.toString());
441     }
442     public final boolean matches(List JavaDoc<Tree> a, List JavaDoc<Tree> b, int len) {
443     return len<=0 ? a.isEmpty() && b.isEmpty()
444         : a.isEmpty() ? b.isEmpty()
445         : !b.isEmpty() && matcher().matches((Tree)a, (Tree)b);
446     }
447
448     private TreeMatcher matcherObj;
449     private final TreeMatcher matcher() {
450     TreeMatcher t = matcherObj;
451     if(t==null) matcherObj = t = new TreeMatcher(env);
452     return t;
453     }
454     
455     /**
456      * Returns true if the tree is an IdentifierTree with the name "null".
457      * Use isNullTree() to test for a tree instance being null.
458      * @see #isNullTree
459      */

460     public static boolean isNull(Tree t) {
461     if(!(t instanceof LiteralTree))
462             return false;
463         return ((LiteralTree)t).getValue() == null;
464     }
465     
466     /**
467      * Returns true if the tree iinstance is null (normally
468      * only used by rules scripts).
469      */

470     public static boolean isNullTree(Tree t) {
471         return t == null;
472     }
473     
474     /**
475      * Return true if the tree is an IdentifierTree defining the string "true",
476      * a Boolean.TRUE literal, or a ParenthesizedExpression surrounding one
477      * of these.
478      */

479     public static boolean isTrue(Tree tree) {
480     if(tree==null) return false;
481     switch(tree.getKind()) {
482             case IDENTIFIER: {
483                 CharSequence JavaDoc nm = ((IdentifierTree)tree).getName();
484                 return "true".contentEquals(nm);
485             }
486             case BOOLEAN_LITERAL:
487                 return ((LiteralTree)tree).getValue()==Boolean.TRUE;
488             case PARENTHESIZED:
489                 return isTrue(((ParenthesizedTree)tree).getExpression());
490     }
491     return false;
492     }
493         
494     /**
495      * Return true if the tree is an IdentifierTree defining the string "false",
496      * a Boolean.FALSE literal, or a ParenthesizedExpression surrounding one
497      * of these.
498      */

499     public static boolean isFalse(Tree tree) {
500     if(tree==null) return false;
501     switch(tree.getKind()) {
502             case IDENTIFIER: {
503                 CharSequence JavaDoc nm = ((IdentifierTree)tree).getName();
504                 return "false".contentEquals(nm);
505             }
506             case BOOLEAN_LITERAL:
507                 return ((LiteralTree)tree).getValue()==Boolean.FALSE;
508             case PARENTHESIZED:
509                 return isFalse(((ParenthesizedTree)tree).getExpression());
510     }
511     return false;
512     }
513     
514     /**
515      * Returns true if the tree is free of side effects.
516      */

517     public static boolean sideEffectFree(Tree t) {
518         if(t==null) return true;
519         if (t instanceof LiteralTree || t instanceof IdentifierTree)
520             return true;
521         if(t instanceof BinaryTree) {
522             BinaryTree b = (BinaryTree) t;
523             return sideEffectFree(b.getLeftOperand()) && sideEffectFree(b.getRightOperand());
524         }
525         Tree.Kind kind = t.getKind();
526         if (t instanceof UnaryTree)
527             return (kind == PLUS || kind == MINUS || kind == LOGICAL_COMPLEMENT || kind == BITWISE_COMPLEMENT)
528                 && sideEffectFree(((UnaryTree)t).getExpression());
529         switch (kind) {
530             default: return false;
531             case PARENTHESIZED: return sideEffectFree(((ParenthesizedTree)t).getExpression());
532             case MEMBER_SELECT: return sideEffectFree(((MemberSelectTree)t).getExpression());
533             case TYPE_CAST: return sideEffectFree(((TypeCastTree)t).getExpression());
534             case INSTANCE_OF: return sideEffectFree(((InstanceOfTree)t).getExpression());
535             case ARRAY_ACCESS: {
536                 ArrayAccessTree ix = (ArrayAccessTree) t;
537                 return sideEffectFree(ix.getExpression()) && sideEffectFree(ix.getIndex());
538             }
539             case CONDITIONAL_EXPRESSION: {
540                 ConditionalExpressionTree c = (ConditionalExpressionTree) t;
541                 return sideEffectFree(c.getCondition()) &&
542                         sideEffectFree(c.getTrueExpression()) &&
543                         sideEffectFree(c.getFalseExpression());
544             }
545         }
546     }
547     
548     /**
549      * Returns true if the list is free of side effects.
550      */

551     public static boolean sideEffectFree(java.util.List JavaDoc<Tree> list) {
552         for (Tree t : list)
553             if (!sideEffectFree(t))
554                 return false;
555         return true;
556     }
557     
558     /**
559      * Returns the element for a specified tree. Null is returned if the
560      * tree type doesn't have an associated element, or if the reference
561      * is not resolved.
562      */

563     public Element getElement(Tree tree) {
564         return model.getElement(tree);
565     }
566     
567     public boolean alreadyDefinedIn(CharSequence JavaDoc name, ExecutableType method, TypeElement enclClass) {
568         return elements.alreadyDefinedIn(name, method, enclClass);
569      }
570     
571     public boolean isMemberOf(Element e, TypeElement type) {
572         return elements.isMemberOf(e, type);
573     }
574     
575     public boolean isDeprecated(Element element) {
576         return env.getElements().isDeprecated(element);
577     }
578     
579     public CharSequence JavaDoc getFullName(Element element) {
580         return elements.getFullName(element);
581     }
582
583     /**
584      * Returns true if the specified tree either throws an exception or
585      * invokes a method which is declared to throw exceptions. No testing
586      * is done to see whether a RuntimeException or Error can be thrown.
587      */

588     public boolean couldThrow(Tree tree) {
589         // scan for a throw statement or method that throws exceptions.
590
TreeScanner<Tree,Tree> scanner = new TreeScanner<Tree,Tree>() {
591             @Override JavaDoc
592             public Tree scan(Tree tree, Tree aThrow) {
593                 return aThrow == null ? super.scan(tree, aThrow) : aThrow;
594             }
595
596             @Override JavaDoc
597             public Tree visitThrow(ThrowTree tree, Tree aThrow) {
598                 return tree;
599             }
600
601             @Override JavaDoc
602             public Tree visitMethodInvocation(MethodInvocationTree tree, Tree aThrow) {
603                 aThrow = super.visitMethodInvocation(tree, aThrow);
604                 if (aThrow == null) {
605                     ExpressionTree method = tree.getMethodSelect();
606                     ExecutableType type = (ExecutableType)model.getType(method);
607                     if (type == null)
608                         throw new QueryException("method not resolved: " + method);
609                     else if (!type.getThrownTypes().isEmpty())
610                         aThrow = tree;
611                 }
612                 return aThrow;
613             }
614         };
615         return scanner.scan(tree, null) != null;
616     }
617     
618     /**
619      * Returns true if the tree is an empty block or statement.
620      */

621     public static boolean isEmpty(Tree t) {
622         if(t==null) return true;
623         switch(t.getKind()) {
624             default:
625                 return false;
626             case BLOCK:
627                 for (StatementTree stat : ((BlockTree)t).getStatements())
628                     if (!isEmpty(stat))
629                         return false;
630                 return true;
631             case EMPTY_STATEMENT:
632                 return true;
633         }
634     }
635     
636     /**
637      * Returns true if the tree represents a TypeElement, such as
638      * "Object" or "java.util.String". This method is not used for
639      * actual ClassTree instances (where instanceof can be used).
640      */

641     public boolean isClassIdentifier(Tree t) {
642         if (t == null)
643             return false;
644         Element el;
645         switch (t.getKind()) {
646             case IDENTIFIER:
647                 el = model.getElement(t);
648                 break;
649             case MEMBER_SELECT:
650                 MemberSelectTree ms = (MemberSelectTree) t;
651                 if(!sideEffectFree(ms.getExpression()))
652                     return false;
653                 el = model.getElement(t);
654                 break;
655             default:
656                 return false;
657         }
658         return el instanceof TypeElement;
659     }
660     
661     /**
662      * Returns the type for a specified tree. Null is returned if the
663      * tree type doesn't have an associated type, or if the type reference
664      * is not resolved.
665      */

666     public TypeMirror getType(Tree tree) {
667         return model.getType(tree);
668     }
669
670     /**
671      * Get the position for a tree node. The position is defined
672      * as the place where the cursor would be placed when printing
673      * an error message for a tree. While most trees define the
674      * start position and this position to be the same, some don't.
675      * For example, method trees define the position as the start
676      * of the method's name, while the start position is the start
677      * of the first modifier token.
678      */

679     public int getPos(Tree tree) {
680         return model.getPos(tree);
681     }
682
683     /**
684      * Returns true if the tree was generated by javac and
685      * not defined in the source code.
686      */

687     public boolean isSynthetic(Tree tree) {
688         return model.isSynthetic(tree);
689     }
690
691     /**
692      * Returns true if the tree has variable declarations. This can only be
693      * true for VariableTree trees and blocks that contain them.
694      */

695     public boolean hasVariableDeclarations(Tree t) {
696         if (t instanceof VariableTree)
697             return true;
698         if (t instanceof BlockTree)
699             for (StatementTree stat : ((BlockTree)t).getStatements())
700                 if (stat != null && stat instanceof VariableTree)
701                     return true;
702     return false;
703     }
704     
705     /**
706      * Returns true if the tree is a statement. This is normally only used by rule
707      * scripts; Java source files can check with a
708      * "<code><i>tree</i> instanceof StatementTree</code> test.
709      */

710     public static boolean isStatement(Tree t) {
711         return t instanceof StatementTree;
712     }
713     
714     /**
715      * Returns true if the tree defines a static class or class member.
716      */

717     public boolean isStatic(Tree tree) {
718         return model.isStatic(tree);
719     }
720     
721     public int getInstanceReferenceCount(Tree t) {
722         return model.getInstanceReferenceCount(t);
723     }
724 }
725
Popular Tags