1 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 ; 26 import java.util.logging.Logger ; 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 ; 38 import java.util.List ; 39 import java.util.Set ; 40 import static com.sun.source.tree.Tree.Kind.*; 41 42 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 queryDescription = null; 54 protected SearchEntry lastAddition; 55 private UseFinder useFinder; 56 57 static final Logger logger = Logger.getLogger("org.netbeans.modules.java.source"); 58 59 62 public static final int NOPOS = -2; 63 64 68 @Override 69 public void init() { 70 result = new SearchResult(this, getQueryDescription()); 71 } 72 73 77 @Override 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 91 @Override 92 public void release() { 93 super.release(); 94 trees = null; 95 elements = null; 96 types = null; 97 } 99 100 103 @Override 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 key = this instanceof org.netbeans.api.java.source.transform.Transformer ? 119 "Transformer.running.transformer" : "Query.running.query"; 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 time) { 129 String key = this instanceof org.netbeans.api.java.source.transform.Transformer ? 130 "Query.query.stats" : "Transformer.query.stats"; String statFormat = getString(key); 132 133 if (logger.isLoggable(Level.FINE)) { 134 Runtime 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 fmt = getString("Query.noResults"); 143 String msg = MessageFormat.format(fmt, queryDescription); 144 logger.log(Level.INFO, msg); 145 env.setStatusMessage(msg); 146 } 147 148 private String getString(String key) { 149 return NbBundle.getBundle(Query.class).getString(key); } 151 152 public QueryEnvironment getEnvironment() { 153 return env; 154 } 155 156 159 public final void error(Object 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 t) { 168 throw new QueryException(t); 169 } 170 171 public final void note(String s) { 172 env.setStatusMessage(s); 173 } 174 175 public final void show(SearchResult sr, String 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 title) { 183 if (result != null && result.length > 0) 184 env.setResult(result, title); 185 else 186 showNoResults(); 187 } 188 189 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 msg) { 201 addResult(e, null, msg); 202 } 203 204 public final void addResult(Element e, Tree t, String 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 getQueryDescription() { 215 return queryDescription != null ? queryDescription : "Unnamed Query"; 216 } 217 218 public void setQueryDescription(String description) { 219 queryDescription = description; 220 } 221 222 public ResultTableModel getResult() { 223 return result; 224 } 225 226 protected String 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 243 public Tree getTree(Element e) { 244 return trees.getTree(e); 245 } 246 247 public boolean isOverridden(ExecutableElement s) { 248 return false; } 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 291 protected boolean hasAnnotation(ModifiersTree mods, TypeMirror annotationType) { 292 java.util.List <? 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 <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 n, List <? 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 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 ,Object > { 321 String name; 322 boolean assigned; 323 public boolean assignedIn(CharSequence n, Tree t) { 324 name = n.toString(); 325 assigned = false; 326 scan(t, null); 327 return assigned; 328 } 329 @Override 330 public Void scan(Tree tree, Object p) { 331 if(!assigned) 332 super.scan(tree, p); 333 return null; 334 } 335 @Override 336 public Void visitAssignment(AssignmentTree tree, Object p) { 337 if(!checkTarget(tree.getVariable())) 338 super.visitAssignment(tree, p); 339 return null; 340 } 341 @Override 342 public Void visitCompoundAssignment(CompoundAssignmentTree tree, Object 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 n, List <? 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 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 ,Object > { 366 String name; 367 boolean declared; 368 public boolean declaredIn(CharSequence n, Tree t) { 369 name = n.toString(); 370 declared = false; 371 scan(t, null); 372 return declared; 373 } 374 @Override 375 public Void scan(Tree tree, Object p) { 376 if(!declared) 377 super.scan(tree, p); 378 return null; 379 } 380 @Override 381 public Void visitVariable(VariableTree tree, Object 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 410 public SourceVersion sourceVersion() { 411 return model.sourceVersion(); 412 } 413 414 418 public boolean sourceLevel(SourceVersion version) { 419 return model.sourceVersion().compareTo(version) >= 0; 420 } 421 422 425 public final boolean matches(Tree a, Tree b) { 426 return matcher().matches(a,b); 427 } 428 429 432 public boolean matches(List <? extends Tree> a, List <? extends Tree> b) { 433 return matcher().matches(a,b); 434 } 435 436 public final boolean matches(CharSequence a, Tree b) { 437 return b instanceof IdentifierTree && ((IdentifierTree)b).getName().equals(a); 438 } 439 public final boolean matches(CharSequence a, CharSequence b) { 440 return a.toString().equals(b.toString()); 441 } 442 public final boolean matches(List <Tree> a, List <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 460 public static boolean isNull(Tree t) { 461 if(!(t instanceof LiteralTree)) 462 return false; 463 return ((LiteralTree)t).getValue() == null; 464 } 465 466 470 public static boolean isNullTree(Tree t) { 471 return t == null; 472 } 473 474 479 public static boolean isTrue(Tree tree) { 480 if(tree==null) return false; 481 switch(tree.getKind()) { 482 case IDENTIFIER: { 483 CharSequence 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 499 public static boolean isFalse(Tree tree) { 500 if(tree==null) return false; 501 switch(tree.getKind()) { 502 case IDENTIFIER: { 503 CharSequence 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 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 551 public static boolean sideEffectFree(java.util.List <Tree> list) { 552 for (Tree t : list) 553 if (!sideEffectFree(t)) 554 return false; 555 return true; 556 } 557 558 563 public Element getElement(Tree tree) { 564 return model.getElement(tree); 565 } 566 567 public boolean alreadyDefinedIn(CharSequence 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 getFullName(Element element) { 580 return elements.getFullName(element); 581 } 582 583 588 public boolean couldThrow(Tree tree) { 589 TreeScanner<Tree,Tree> scanner = new TreeScanner<Tree,Tree>() { 591 @Override 592 public Tree scan(Tree tree, Tree aThrow) { 593 return aThrow == null ? super.scan(tree, aThrow) : aThrow; 594 } 595 596 @Override 597 public Tree visitThrow(ThrowTree tree, Tree aThrow) { 598 return tree; 599 } 600 601 @Override 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 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 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 666 public TypeMirror getType(Tree tree) { 667 return model.getType(tree); 668 } 669 670 679 public int getPos(Tree tree) { 680 return model.getPos(tree); 681 } 682 683 687 public boolean isSynthetic(Tree tree) { 688 return model.isSynthetic(tree); 689 } 690 691 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 710 public static boolean isStatement(Tree t) { 711 return t instanceof StatementTree; 712 } 713 714 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 |