1 19 package org.netbeans.modules.java.editor.semantic; 20 21 import com.sun.source.tree.AnnotationTree; 22 import com.sun.source.tree.ArrayAccessTree; 23 import com.sun.source.tree.ArrayTypeTree; 24 import com.sun.source.tree.AssertTree; 25 import com.sun.source.tree.AssignmentTree; 26 import com.sun.source.tree.BinaryTree; 27 import com.sun.source.tree.CaseTree; 28 import com.sun.source.tree.CatchTree; 29 import com.sun.source.tree.ClassTree; 30 import com.sun.source.tree.CompilationUnitTree; 31 import com.sun.source.tree.CompoundAssignmentTree; 32 import com.sun.source.tree.ConditionalExpressionTree; 33 import com.sun.source.tree.EnhancedForLoopTree; 34 import com.sun.source.tree.ExpressionStatementTree; 35 import com.sun.source.tree.ExpressionTree; 36 import com.sun.source.tree.IdentifierTree; 37 import com.sun.source.tree.ImportTree; 38 import com.sun.source.tree.InstanceOfTree; 39 import com.sun.source.tree.MemberSelectTree; 40 import com.sun.source.tree.MethodInvocationTree; 41 import com.sun.source.tree.MethodTree; 42 import com.sun.source.tree.NewArrayTree; 43 import com.sun.source.tree.NewClassTree; 44 import com.sun.source.tree.ParameterizedTypeTree; 45 import com.sun.source.tree.ParenthesizedTree; 46 import com.sun.source.tree.ReturnTree; 47 import com.sun.source.tree.ThrowTree; 48 import com.sun.source.tree.Tree; 49 import com.sun.source.tree.Tree.Kind; 50 import com.sun.source.tree.TypeCastTree; 51 import com.sun.source.tree.TypeParameterTree; 52 import com.sun.source.tree.UnaryTree; 53 import com.sun.source.tree.VariableTree; 54 import com.sun.source.util.SourcePositions; 55 import com.sun.source.util.TreePath; 56 import com.sun.source.util.TreePathScanner; 57 import java.awt.Color ; 58 import java.beans.PropertyChangeListener ; 59 import java.io.IOException ; 60 import java.util.ArrayList ; 61 import java.util.Arrays ; 62 import java.util.Collection ; 63 import java.util.Collections ; 64 import java.util.EnumSet ; 65 import java.util.HashMap ; 66 import java.util.HashSet ; 67 import java.util.List ; 68 import java.util.Map ; 69 import java.util.Set ; 70 import java.util.logging.Level ; 71 import java.util.logging.Logger ; 72 import javax.lang.model.element.Element; 73 import javax.lang.model.element.ElementKind; 74 import javax.lang.model.element.ExecutableElement; 75 import javax.lang.model.element.Modifier; 76 import javax.lang.model.type.TypeKind; 77 import javax.swing.text.BadLocationException ; 78 import javax.swing.text.Document ; 79 import javax.swing.text.Position ; 80 import javax.swing.text.StyledDocument ; 81 import org.netbeans.api.java.source.CancellableTask; 82 import org.netbeans.api.java.source.CompilationInfo; 83 import org.netbeans.api.java.source.TreePathHandle; 84 import org.netbeans.api.java.source.support.CancellableTreePathScanner; 85 import org.netbeans.api.timers.TimesCollector; 86 import org.netbeans.editor.BaseDocument; 87 import org.netbeans.modules.editor.highlights.spi.Highlight; 88 import org.netbeans.modules.editor.highlights.spi.Highlighter; 89 import org.netbeans.spi.editor.hints.ChangeInfo; 90 import org.netbeans.spi.editor.hints.ErrorDescription; 91 import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; 92 import org.netbeans.spi.editor.hints.Fix; 93 import org.netbeans.spi.editor.hints.HintsController; 94 import org.netbeans.spi.editor.hints.LazyFixList; 95 import org.netbeans.spi.editor.hints.Severity; 96 import org.openide.ErrorManager; 97 import org.openide.cookies.EditorCookie; 98 import org.openide.filesystems.FileObject; 99 import org.openide.filesystems.FileUtil; 100 import org.openide.loaders.DataObject; 101 import org.openide.text.NbDocument; 102 103 104 108 public class SemanticHighlighter extends ScanningCancellableTask<CompilationInfo> { 109 110 private FileObject file; 111 112 113 SemanticHighlighter(FileObject file) { 114 this.file = file; 115 } 116 117 public Document getDocument() { 118 try { 119 DataObject d = DataObject.find(file); 120 EditorCookie ec = (EditorCookie) d.getCookie(EditorCookie.class); 121 122 if (ec == null) 123 return null; 124 125 return ec.getDocument(); 126 } catch (IOException e) { 127 Logger.getLogger(SemanticHighlighter.class.getName()).log(Level.INFO, "SemanticHighlighter: Cannot find DataObject for file: " + FileUtil.getFileDisplayName(file), e); 128 return null; 129 } 130 } 131 132 public @Override void run(CompilationInfo info) { 133 resume(); 134 135 Document doc = getDocument(); 136 137 if (doc == null) { 138 Logger.getLogger(SemanticHighlighter.class.getName()).log(Level.INFO, "SemanticHighlighter: Cannot get document!"); 139 return ; 140 } 141 142 Set <Highlight> highlights = process(info, doc); 143 144 if (isCancelled()) 145 return; 146 147 Highlighter.getDefault().setHighlights(file, "semantic", highlights); 148 OccurrencesMarkProvider.get(doc).setSematic(highlights); 149 } 150 151 private void removeImport(Document doc, int start, int end) { 152 try { 153 int len = doc.getLength(); 154 155 while (start > 0 && "\t ".indexOf(doc.getText(start - 1, 1).charAt(0)) != (-1)) 156 start--; 157 158 boolean wasNewLine = start == 0 || "\n".equals(doc.getText(start - 1, 1)); 159 160 while (end < len && "\t ".indexOf(doc.getText(end, 1).charAt(0)) != (-1)) 161 end++; 162 163 if (wasNewLine && "\n".equals(doc.getText(end, 1))) 164 end++; 165 166 doc.remove(start, end - start); 167 } catch (BadLocationException e) { 168 ErrorManager.getDefault().notify(e); 169 } 170 } 171 172 private static class FixAllImportsFixList implements LazyFixList { 173 private Fix removeImport; 174 private Fix removeAllUnusedImports; 175 private List <TreePathHandle> allUnusedImports; 176 177 public FixAllImportsFixList(Fix removeImport, Fix removeAllUnusedImports, List <TreePathHandle> allUnusedImports) { 178 this.removeImport = removeImport; 179 this.removeAllUnusedImports = removeAllUnusedImports; 180 this.allUnusedImports = allUnusedImports; 181 } 182 183 public void addPropertyChangeListener(PropertyChangeListener l) { 184 } 185 186 public void removePropertyChangeListener(PropertyChangeListener l) { 187 } 188 189 public boolean probablyContainsFixes() { 190 return true; 191 } 192 193 private List <Fix> fixes; 194 195 public synchronized List <Fix> getFixes() { 196 if (fixes != null) 197 return fixes; 198 199 if (allUnusedImports.size() > 1) { 200 fixes = Arrays.asList(removeImport, removeAllUnusedImports); 201 } else { 202 fixes = Collections.singletonList(removeImport); 203 } 204 205 return fixes; 206 } 207 208 public boolean isComputed() { 209 return true; 210 } 211 } 212 213 Set <Highlight> process(CompilationInfo info, final Document doc) { 214 DetectorVisitor v = new DetectorVisitor(info, doc); 215 216 long start = System.currentTimeMillis(); 217 218 Set <Highlight> result = new HashSet (); 219 List <ErrorDescription> errors = new ArrayList <ErrorDescription>(); 220 221 CompilationUnitTree cu = info.getCompilationUnit(); 222 223 scan(v, cu, null); 224 225 if (isCancelled()) 226 return Collections.emptySet(); 227 228 final List <TreePathHandle> allUnusedImports = new ArrayList <TreePathHandle>(); 229 final Fix removeAllUnusedImports = RemoveUnusedImportFix.create(file, allUnusedImports); 230 231 for (Element el : v.type2Highlight.keySet()) { 232 if (isCancelled()) 233 return Collections.emptySet(); 234 235 final TreePath tree = v.type2Highlight.get(el); 236 237 if (el == null || el.getSimpleName() == null) 238 continue; 239 240 Highlight h = Utilities.createHighlight(cu, info.getTrees().getSourcePositions(), doc, tree, EnumSet.of(ColoringAttributes.UNUSED), Color.GRAY); 241 242 if (h != null) { 243 result.add(h); 244 } 245 246 final long startPos = info.getTrees().getSourcePositions().getStartPosition(cu, tree.getLeaf()); 247 int line = (int) info.getCompilationUnit().getLineMap().getLineNumber(startPos); 248 249 TreePathHandle handle = TreePathHandle.create(tree, info); 250 251 final Fix removeImport = RemoveUnusedImportFix.create(file, handle); 252 253 allUnusedImports.add(handle); 254 errors.add(ErrorDescriptionFactory.createErrorDescription(Severity.VERIFIER, "Unused import", new FixAllImportsFixList(removeImport, removeAllUnusedImports, allUnusedImports), doc, line)); 255 } 256 257 for (Element decl : v.type2Uses.keySet()) { 258 if (isCancelled()) 259 return Collections.emptySet(); 260 261 List <Use> uses = v.type2Uses.get(decl); 262 263 for (Use u : uses) { 264 if (u.spec == null) 265 continue; 266 267 if (u.type.contains(UseTypes.Element) && org.netbeans.modules.java.editor.semantic.Utilities.isPrivateElement(decl)) { 268 if (decl.getKind().isField() || isLocalVariableClosure(decl)) { 269 if (!hasAllTypes(uses, EnumSet.of(UseTypes.READ, UseTypes.WRITE))) { 270 u.spec.add(ColoringAttributes.UNUSED); 271 } 272 } 273 274 if (decl.getKind() == ElementKind.CONSTRUCTOR || decl.getKind() == ElementKind.METHOD) { 275 if (!hasAllTypes(uses, EnumSet.of(UseTypes.EXECUTE))) { 276 u.spec.add(ColoringAttributes.UNUSED); 277 } 278 } 279 280 if (decl.getKind().isClass() || decl.getKind().isInterface()) { 281 if (!hasAllTypes(uses, EnumSet.of(UseTypes.CLASS_USE))) { 282 u.spec.add(ColoringAttributes.UNUSED); 283 } 284 } 285 } 286 287 Collection <ColoringAttributes> c = EnumSet.copyOf(u.spec); 288 Highlight h = Utilities.createHighlight(cu, info.getTrees().getSourcePositions(), doc, u.tree, c, null); 289 290 if (h != null) { 291 result.add(h); 292 } 293 } 294 } 295 296 if (isCancelled()) 297 return Collections.emptySet(); 298 299 ERROR_DESCRIPTION_SETTER.setErrors(doc, errors); 300 301 TimesCollector.getDefault().reportTime(((DataObject) doc.getProperty(Document.StreamDescriptionProperty)).getPrimaryFile(), "semantic", "Semantic", (System.currentTimeMillis() - start)); 302 303 return result; 304 } 305 306 private boolean hasAllTypes(List <Use> uses, Collection <UseTypes> types) { 307 EnumSet e = EnumSet.copyOf(types); 308 309 for (Use u : uses) { 310 if (types.isEmpty()) { 311 return true; 312 } 313 314 types.removeAll(u.type); 315 } 316 317 return types.isEmpty(); 318 } 319 320 private enum UseTypes { 321 READ, WRITE, EXECUTE, Element, CLASS_USE; 322 } 323 324 private static boolean isLocalVariableClosure(Element el) { 325 return el.getKind() == ElementKind.PARAMETER || el.getKind() == ElementKind.LOCAL_VARIABLE || el.getKind() == ElementKind.EXCEPTION_PARAMETER; 326 } 327 328 private static class Use { 329 private Collection <UseTypes> type; 330 private TreePath tree; 331 private Collection <ColoringAttributes> spec; 332 333 public Use(Collection <UseTypes> type, TreePath tree, Collection <ColoringAttributes> spec) { 334 this.type = type; 335 this.tree = tree; 336 this.spec = spec; 337 } 338 339 public String toString() { 340 return "Use: " + type; 341 } 342 } 343 344 private static class DetectorVisitor extends CancellableTreePathScanner<Void , EnumSet <UseTypes>> { 345 346 private org.netbeans.api.java.source.CompilationInfo info; 347 private Document doc; 348 private Map <Element, List <Use>> type2Uses; 349 private Map <Element, TreePath> type2Highlight; 350 352 private SourcePositions sourcePositions; 354 355 private DetectorVisitor(org.netbeans.api.java.source.CompilationInfo info, Document doc) { 356 this.info = info; 357 this.doc = doc; 358 type2Uses = new HashMap <Element, List <Use>>(); 359 this.type2Highlight = new HashMap <Element, TreePath>(); 360 } 362 363 private Highlight createHighlight(CompilationUnitTree cu, SourcePositions sp, TreePath tree, Collection <ColoringAttributes> c, Color es) { 364 return Utilities.createHighlight(cu, sp, doc, tree, c, es); 365 } 366 367 @Override 368 public Void visitAssignment(AssignmentTree tree, EnumSet <UseTypes> d) { 369 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getVariable()), EnumSet.of(UseTypes.WRITE)); 370 371 Tree expr = tree.getExpression(); 372 373 if (expr instanceof IdentifierTree) { 374 TreePath tp = new TreePath(getCurrentPath(), expr); 375 resolveType(tp); 376 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.READ)); 377 } 378 379 scan(tree.getVariable(), EnumSet.of(UseTypes.WRITE)); 380 scan(tree.getExpression(), null); 381 382 return super.visitAssignment(tree, null); 383 } 384 385 @Override 386 public Void visitCompoundAssignment(CompoundAssignmentTree tree, EnumSet <UseTypes> d) { 387 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getVariable()), EnumSet.of(UseTypes.WRITE)); 388 389 Tree expr = tree.getExpression(); 390 391 if (expr instanceof IdentifierTree) { 392 TreePath tp = new TreePath(getCurrentPath(), expr); 393 resolveType(tp); 394 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.READ)); 395 } 396 397 scan(tree.getVariable(), EnumSet.of(UseTypes.WRITE)); 398 scan(tree.getExpression(), null); 399 400 return super.visitCompoundAssignment(tree, null); 401 } 402 403 @Override 404 public Void visitReturn(ReturnTree tree, EnumSet <UseTypes> d) { 405 if (tree.getExpression() instanceof IdentifierTree) { 406 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getExpression()), EnumSet.of(UseTypes.READ)); 407 } 408 409 super.visitReturn(tree, null); 410 return null; 411 } 412 413 @Override 414 public Void visitMemberSelect(MemberSelectTree tree, EnumSet <UseTypes> d) { 415 Tree expr = tree.getExpression(); 416 417 if (expr instanceof IdentifierTree) { 418 TreePath tp = new TreePath(getCurrentPath(), expr); 419 resolveType(tp); 420 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.READ)); 421 } 422 423 Element el = info.getTrees().getElement(getCurrentPath()); 424 425 if (el != null && el.getKind().isField()) { 426 handlePossibleIdentifier(getCurrentPath(), EnumSet.of(UseTypes.READ)); 427 } 428 431 super.visitMemberSelect(tree, null); 432 return null; 433 } 434 435 private void addModifiers(Element decl, Collection <ColoringAttributes> c) { 436 if (decl.getModifiers().contains(Modifier.STATIC)) { 437 c.add(ColoringAttributes.STATIC); 438 } 439 440 if (decl.getModifiers().contains(Modifier.ABSTRACT)) { 441 c.add(ColoringAttributes.ABSTRACT); 442 } 443 444 boolean accessModifier = false; 445 446 if (decl.getModifiers().contains(Modifier.PUBLIC)) { 447 c.add(ColoringAttributes.PUBLIC); 448 accessModifier = true; 449 } 450 451 if (decl.getModifiers().contains(Modifier.PROTECTED)) { 452 c.add(ColoringAttributes.PROTECTED); 453 accessModifier = true; 454 } 455 456 if (decl.getModifiers().contains(Modifier.PRIVATE)) { 457 c.add(ColoringAttributes.PRIVATE); 458 accessModifier = true; 459 } 460 461 if (!accessModifier && !isLocalVariableClosure(decl)) { 462 c.add(ColoringAttributes.PACKAGE_PRIVATE); 463 } 464 465 if (info.getElements().isDeprecated(decl)) { 466 c.add(ColoringAttributes.DEPRECATED); 467 } 468 } 469 470 private Collection <ColoringAttributes> getMethodColoring(ExecutableElement mdecl) { 471 Collection <ColoringAttributes> c = new ArrayList <ColoringAttributes>(); 472 473 addModifiers(mdecl, c); 474 475 if (mdecl.getKind() == ElementKind.CONSTRUCTOR) 476 c.add(ColoringAttributes.CONSTRUCTOR); 477 else 478 c.add(ColoringAttributes.METHOD); 479 480 return c; 481 } 482 483 private Collection <ColoringAttributes> getVariableColoring(Element decl) { 484 Collection <ColoringAttributes> c = new ArrayList <ColoringAttributes>(); 485 486 addModifiers(decl, c); 487 488 if (decl.getKind().isField()) { 489 c.add(ColoringAttributes.FIELD); 490 491 return c; 492 } 493 494 if (decl.getKind() == ElementKind.LOCAL_VARIABLE || decl.getKind() == ElementKind.EXCEPTION_PARAMETER) { 495 c.add(ColoringAttributes.LOCAL_VARIABLE); 496 497 return c; 498 } 499 500 if (decl.getKind() == ElementKind.PARAMETER) { 501 c.add(ColoringAttributes.PARAMETER); 502 503 return c; 504 } 505 506 assert false; 507 508 return null; 509 } 510 511 private static final Set <Kind> LITERALS = EnumSet.of(Kind.BOOLEAN_LITERAL, Kind.CHAR_LITERAL, Kind.DOUBLE_LITERAL, Kind.FLOAT_LITERAL, Kind.INT_LITERAL, Kind.LONG_LITERAL, Kind.STRING_LITERAL); 512 513 private void handlePossibleIdentifier(TreePath expr, Collection <UseTypes> type) { 514 handlePossibleIdentifier(expr, type, null, false); 515 } 516 517 private void handlePossibleIdentifier(TreePath expr, Collection <UseTypes> type, Element decl, boolean providesDecl) { 518 519 if (Utilities.isKeyword(expr.getLeaf())) { 520 return ; 522 } 523 524 if (expr.getLeaf().getKind() == Kind.PRIMITIVE_TYPE) { 525 return ; 527 } 528 529 if (LITERALS.contains(expr.getLeaf().getKind())) { 530 return ; 532 } 533 534 decl = !providesDecl ? info.getTrees().getElement(expr) : decl; 535 536 Collection <ColoringAttributes> c = null; 537 538 543 if (decl != null && (decl.getKind().isField() || isLocalVariableClosure(decl))) { 544 c = getVariableColoring(decl); 545 } 546 547 if (decl != null && decl instanceof ExecutableElement) { 548 c = getMethodColoring((ExecutableElement) decl); 549 } 550 551 if (decl != null && (decl.getKind().isClass() || decl.getKind().isInterface())) { 552 if (type.contains(UseTypes.READ)) { 554 type.remove(UseTypes.READ); 555 type.add(UseTypes.CLASS_USE); 556 } 557 558 c = new ArrayList <ColoringAttributes>(); 559 560 addModifiers(decl, c); 561 } 562 563 if (c != null) { 564 addUse(decl, type, expr, c); 565 } 566 } 567 568 private void addUse(Element decl, Collection <UseTypes> useTypes, TreePath t, Collection <ColoringAttributes> c) { 569 List <Use> uses = type2Uses.get(decl); 570 571 if (uses == null) { 572 type2Uses.put(decl, uses = new ArrayList <Use>()); 573 } 574 575 Use u = new Use(useTypes, t, c); 576 577 uses.add(u); 578 } 579 580 @Override 581 public Void visitTypeCast(TypeCastTree tree, EnumSet <UseTypes> d) { 582 resolveType(new TreePath(getCurrentPath(), tree.getType())); 583 584 Tree expr = tree.getExpression(); 585 586 if (expr instanceof IdentifierTree) { 587 handlePossibleIdentifier(new TreePath(getCurrentPath(), expr), EnumSet.of(UseTypes.READ)); 588 } 589 590 super.visitTypeCast(tree, d); 591 return null; 592 } 593 594 @Override 595 public Void visitInstanceOf(InstanceOfTree tree, EnumSet <UseTypes> d) { 596 Tree expr = tree.getExpression(); 597 598 if (expr instanceof IdentifierTree) { 599 handlePossibleIdentifier(new TreePath(getCurrentPath(), expr), EnumSet.of(UseTypes.READ)); 600 } 601 602 TreePath tp = new TreePath(getCurrentPath(), tree.getType()); 603 resolveType(tp); 604 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.CLASS_USE)); 605 606 super.visitInstanceOf(tree, null); 607 608 return null; 610 } 611 612 @Override 613 public Void visitCompilationUnit(CompilationUnitTree tree, EnumSet <UseTypes> d) { 614 scan(tree.getPackageAnnotations(), d); 615 scan(tree.getImports(), d); 618 scan(tree.getTypeDecls(), d); 619 return null; 620 } 621 622 @Override 623 public Void visitMethodInvocation(MethodInvocationTree tree, EnumSet <UseTypes> d) { 624 Tree possibleIdent = tree.getMethodSelect(); 625 boolean handled = false; 626 627 if (possibleIdent.getKind() == Kind.IDENTIFIER) { 628 String ident = ((IdentifierTree) possibleIdent).getName().toString(); 630 631 if ("super".equals(ident) || "this".equals(ident)) { Element resolved = info.getTrees().getElement(getCurrentPath()); 633 634 addUse(resolved, EnumSet.of(UseTypes.EXECUTE), null, null); 635 handled = true; 636 } 637 } 638 639 if (!handled) { 640 handlePossibleIdentifier(new TreePath(getCurrentPath(), possibleIdent), EnumSet.of(UseTypes.EXECUTE)); 641 } 642 643 for (Tree expr : tree.getArguments()) { 644 if (expr instanceof IdentifierTree) { 645 handlePossibleIdentifier(new TreePath(getCurrentPath(), expr), EnumSet.of(UseTypes.READ)); 646 } 647 } 648 for (Tree expr : tree.getTypeArguments()) { 649 if (expr instanceof IdentifierTree) { 650 resolveType(new TreePath(getCurrentPath(), expr)); 651 } 652 } 653 654 super.visitMethodInvocation(tree, null); 655 return null; 656 } 657 658 @Override 659 public Void visitIdentifier(IdentifierTree tree, EnumSet <UseTypes> d) { 660 668 if (d != null) { 669 handlePossibleIdentifier(getCurrentPath(), d); 670 } 671 super.visitIdentifier(tree, null); 672 return null; 673 } 674 @Override 676 public Void visitMethod(MethodTree tree, EnumSet <UseTypes> d) { 677 handlePossibleIdentifier(getCurrentPath(), EnumSet.of(UseTypes.Element)); 690 691 for (Tree t : tree.getThrows()) { 692 TreePath tp = new TreePath(getCurrentPath(), t); 693 resolveType(tp); 694 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.CLASS_USE)); 695 } 696 697 if (tree.getReturnType() != null) 698 resolveType(new TreePath(getCurrentPath(), tree.getReturnType())); 699 700 EnumSet <UseTypes> paramsUseTypes; 701 702 Element el = info.getTrees().getElement(getCurrentPath()); 703 704 if (el != null && el.getModifiers().contains(Modifier.ABSTRACT)) { 705 paramsUseTypes = EnumSet.of(UseTypes.WRITE, UseTypes.READ); 706 } else { 707 paramsUseTypes = EnumSet.of(UseTypes.WRITE); 708 } 709 710 scan(tree.getModifiers(), null); 711 scan(tree.getReturnType(), EnumSet.of(UseTypes.CLASS_USE)); 712 scan(tree.getTypeParameters(), null); 713 scan(tree.getParameters(), paramsUseTypes); 714 scan(tree.getThrows(), null); 715 scan(tree.getBody(), null); 716 717 return null; 718 } 719 720 @Override 721 public Void visitExpressionStatement(ExpressionStatementTree tree, EnumSet <UseTypes> d) { 722 726 super.visitExpressionStatement(tree, null); 727 return null; 728 } 729 730 @Override 731 public Void visitParenthesized(ParenthesizedTree tree, EnumSet <UseTypes> d) { 732 ExpressionTree expr = tree.getExpression(); 733 734 if (expr instanceof IdentifierTree) { 735 handlePossibleIdentifier(new TreePath(getCurrentPath(), expr), EnumSet.of(UseTypes.READ)); 736 } 737 738 super.visitParenthesized(tree, null); 739 return null; 740 } 741 742 @Override 743 public Void visitEnhancedForLoop(EnhancedForLoopTree tree, EnumSet <UseTypes> d) { 744 scan(tree.getVariable(), EnumSet.of(UseTypes.WRITE)); 745 746 if (tree.getExpression().getKind() == Kind.IDENTIFIER) 747 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getExpression()), EnumSet.of(UseTypes.READ)); 748 749 scan(tree.getExpression(), null); 750 scan(tree.getStatement(), null); 751 752 return null; 753 } 754 755 @Override 756 public Void visitImport(ImportTree tree, EnumSet <UseTypes> d) { 757 if (!tree.isStatic()) { 758 Element decl = info.getTrees().getElement(new TreePath(getCurrentPath(), tree.getQualifiedIdentifier())); 759 760 if (decl != null && decl.asType().getKind() != TypeKind.ERROR) { type2Highlight.put(decl, getCurrentPath()); 762 } 763 } 768 super.visitImport(tree, null); 769 return null; 770 } 771 772 private String getSimple(String fqn) { 773 int lastDot = fqn.lastIndexOf('.'); 774 775 if (lastDot != (-1)) { 776 return fqn.substring(lastDot + 1); 777 } else { 778 return fqn; 779 } 780 } 781 782 @Override 783 public Void visitVariable(VariableTree tree, EnumSet <UseTypes> d) { 784 TreePath type = new TreePath(getCurrentPath(), tree.getType()); 785 786 if (type.getLeaf() instanceof ArrayTypeTree) { 787 type = new TreePath(type, ((ArrayTypeTree) type.getLeaf()).getType()); 788 } 789 790 resolveType(type); 791 792 if (type.getLeaf().getKind() == Kind.IDENTIFIER) 793 handlePossibleIdentifier(type, EnumSet.of(UseTypes.CLASS_USE)); 794 795 Collection <UseTypes> uses = null; 796 boolean isParameter = false; 797 798 if (tree.getInitializer() != null) { 799 uses = EnumSet.of(UseTypes.Element, UseTypes.WRITE); 800 if (tree.getInitializer().getKind() == Kind.IDENTIFIER) 801 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getInitializer()), EnumSet.of(UseTypes.READ)); 802 } else { 803 Element e = info.getTrees().getElement(getCurrentPath()); 804 805 if (e != null && e.getKind() == ElementKind.FIELD) { 806 uses = EnumSet.of(UseTypes.Element, UseTypes.WRITE); 807 } else { 808 uses = EnumSet.of(UseTypes.Element); 809 } 810 } 811 812 if (d != null) { 813 Set <UseTypes> ut = new HashSet (); 814 815 ut.addAll(uses); 816 ut.addAll(d); 817 818 uses = EnumSet.copyOf(ut); 819 } 820 821 handlePossibleIdentifier(getCurrentPath(), uses); 822 823 super.visitVariable(tree, null); 824 return null; 825 } 826 827 private boolean isParameter(VariableTree var, MethodTree decl) { 828 for (VariableTree declVar : decl.getParameters()) { 829 if (var == declVar) 830 return true; 831 } 832 833 return false; 834 } 835 836 @Override 837 public Void visitAnnotation(AnnotationTree tree, EnumSet <UseTypes> d) { 838 TreePath tp = new TreePath(getCurrentPath(), tree.getAnnotationType()); 842 resolveType(tp); 843 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.CLASS_USE)); 844 super.visitAnnotation(tree, EnumSet.noneOf(UseTypes.class)); 845 return null; 847 } 848 849 @Override 850 public Void visitNewClass(NewClassTree tree, EnumSet <UseTypes> d) { 851 TreePath tp; 852 Tree ident = tree.getIdentifier(); 853 854 if (ident.getKind() == Kind.PARAMETERIZED_TYPE) { 855 tp = new TreePath(new TreePath(getCurrentPath(), ident), ((ParameterizedTypeTree) ident).getType()); 856 } else { 857 tp = new TreePath(getCurrentPath(), ident); 858 } 859 860 resolveType(tp); 861 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.EXECUTE), info.getTrees().getElement(getCurrentPath()), true); 862 863 Element clazz = info.getTrees().getElement(tp); 864 865 if (clazz != null) { 866 addUse(clazz, EnumSet.of(UseTypes.CLASS_USE), null, null); 867 } 868 869 for (Tree expr : tree.getArguments()) { 870 if (expr instanceof IdentifierTree) { 871 handlePossibleIdentifier(new TreePath(getCurrentPath(), expr), EnumSet.of(UseTypes.READ)); 872 } 873 } 874 875 super.visitNewClass(tree, null); 876 877 return null; 878 } 879 880 @Override 881 public Void visitParameterizedType(ParameterizedTypeTree tree, EnumSet <UseTypes> d) { 882 if (getCurrentPath().getParentPath().getLeaf().getKind() != Kind.NEW_CLASS) { 883 TreePath tp = new TreePath(getCurrentPath(), tree.getType()); 885 resolveType(tp); 886 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.CLASS_USE)); 887 } 888 889 for (Tree t : tree.getTypeArguments()) { 890 TreePath tp = new TreePath(getCurrentPath(), t); 891 resolveType(tp); 892 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.CLASS_USE)); 893 894 } 899 900 super.visitParameterizedType(tree, null); 901 return null; 902 } 903 904 @Override 905 public Void visitBinary(BinaryTree tree, EnumSet <UseTypes> d) { 906 Tree left = tree.getLeftOperand(); 907 Tree right = tree.getRightOperand(); 908 909 if (left instanceof IdentifierTree) { 910 TreePath tp = new TreePath(getCurrentPath(), left); 911 resolveType(tp); 912 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.READ)); 913 } 914 915 if (right instanceof IdentifierTree) { 916 TreePath tp = new TreePath(getCurrentPath(), right); 917 resolveType(tp); 918 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.READ)); 919 } 920 921 super.visitBinary(tree, null); 922 return null; 923 } 924 925 @Override 926 public Void visitClass(ClassTree tree, EnumSet <UseTypes> d) { 927 Tree extnds = tree.getExtendsClause(); 928 929 if (extnds != null) { 930 TreePath tp = new TreePath(getCurrentPath(), extnds); 931 resolveType(tp); 932 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.CLASS_USE)); 933 } 934 935 for (Tree t : tree.getImplementsClause()) { 936 TreePath tp = new TreePath(getCurrentPath(), t); 937 resolveType(tp); 938 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.CLASS_USE)); 939 } 940 941 for (TypeParameterTree t : tree.getTypeParameters()) { 942 for (Tree bound : t.getBounds()) { 943 TreePath tp = new TreePath(new TreePath(getCurrentPath(), t), bound); 944 resolveType(tp); 945 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.CLASS_USE)); 946 } 947 } 948 949 handlePossibleIdentifier(getCurrentPath(), EnumSet.of(UseTypes.Element)); 950 951 super.visitClass(tree, null); 952 return null; 954 } 955 956 @Override 957 public Void visitUnary(UnaryTree tree, EnumSet <UseTypes> d) { 958 if (tree.getExpression() instanceof IdentifierTree) { 959 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getExpression()), EnumSet.of(UseTypes.READ)); 960 } 961 super.visitUnary(tree, d); 962 return null; 963 } 964 965 @Override 966 public Void visitArrayAccess(ArrayAccessTree tree, EnumSet <UseTypes> d) { 967 if (tree.getExpression() != null && tree.getExpression().getKind() == Kind.IDENTIFIER) { 968 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getExpression()), EnumSet.of(UseTypes.READ)); 969 } 970 971 if (tree.getIndex() instanceof IdentifierTree) { 972 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getIndex()), EnumSet.of(UseTypes.READ)); 973 } 974 975 super.visitArrayAccess(tree, null); 976 return null; 977 } 978 979 @Override 980 public Void visitNewArray(NewArrayTree tree, EnumSet <UseTypes> d) { 981 if (tree.getType() != null) 982 resolveType(new TreePath(getCurrentPath(), tree.getType())); 983 984 scan(tree.getType(), null); 985 scan(tree.getDimensions(), EnumSet.of(UseTypes.READ)); 986 scan(tree.getInitializers(), EnumSet.of(UseTypes.READ)); 987 988 return null; 989 } 990 991 @Override 992 public Void visitCatch(CatchTree tree, EnumSet <UseTypes> d) { 993 scan(tree.getParameter(), EnumSet.of(UseTypes.WRITE)); 994 scan(tree.getBlock(), null); 995 return null; 996 } 997 998 @Override 999 public Void visitConditionalExpression(ConditionalExpressionTree node, EnumSet <UseTypes> p) { 1000 return super.visitConditionalExpression(node, EnumSet.of(UseTypes.READ)); 1001 } 1002 1003 @Override 1004 public Void visitAssert(AssertTree tree, EnumSet <UseTypes> p) { 1005 if (tree.getCondition().getKind() == Kind.IDENTIFIER) 1006 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getCondition()), EnumSet.of(UseTypes.READ)); 1007 if (tree.getDetail() != null && tree.getDetail().getKind() == Kind.IDENTIFIER) 1008 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getDetail()), EnumSet.of(UseTypes.READ)); 1009 1010 return super.visitAssert(tree, null); 1011 } 1012 1013 @Override 1014 public Void visitCase(CaseTree tree, EnumSet <UseTypes> p) { 1015 if (tree.getExpression() != null && tree.getExpression().getKind() == Kind.IDENTIFIER) { 1016 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getExpression()), EnumSet.of(UseTypes.READ)); 1017 } 1018 1019 return super.visitCase(tree, null); 1020 } 1021 1022 @Override 1023 public Void visitThrow(ThrowTree tree, EnumSet <UseTypes> p) { 1024 if (tree.getExpression() != null && tree.getExpression().getKind() == Kind.IDENTIFIER) { 1025 handlePossibleIdentifier(new TreePath(getCurrentPath(), tree.getExpression()), EnumSet.of(UseTypes.READ)); 1026 } 1027 1028 return super.visitThrow(tree, p); 1029 } 1030 1031 @Override 1032 public Void visitTypeParameter(TypeParameterTree tree, EnumSet <UseTypes> p) { 1033 for (Tree bound : tree.getBounds()) { 1034 if (bound.getKind() == Kind.IDENTIFIER) { 1035 TreePath tp = new TreePath(getCurrentPath(), bound); 1036 1037 handlePossibleIdentifier(tp, EnumSet.of(UseTypes.CLASS_USE)); 1038 resolveType(tp); 1039 } 1040 } 1041 return super.visitTypeParameter(tree, p); 1042 } 1043 1044 private void resolveType(TreePath type) { 1045 FirstIdentTypeVisitor v = new FirstIdentTypeVisitor(); 1046 1047 v.scan(type, null); 1048 1049 if (v.first == null) 1050 return ; 1051 1052 Element decl = info.getTrees().getElement(v.first); 1053 1054 if (decl == null) { 1055 1058 return ; 1059 } 1060 1061 type2Highlight.remove(decl); 1062 } 1063 1064 private static class FirstIdentTypeVisitor extends TreePathScanner<Void , Void > { 1065 private TreePath first = null; 1066 1067 public Void visitIdentifier(IdentifierTree tree, Void d) { 1068 if (first == null) { 1069 first = getCurrentPath(); 1070 } 1071 1072 return super.visitIdentifier(tree, null); 1073 } 1074 1075 } 1076 } 1077 1078 public static interface ErrorDescriptionSetter { 1079 1080 public void setErrors(Document doc, List <ErrorDescription> errors); 1081 1082 } 1083 1084 static ErrorDescriptionSetter ERROR_DESCRIPTION_SETTER = new ErrorDescriptionSetter() { 1085 1086 public void setErrors(Document doc, List <ErrorDescription> errors) { 1087 HintsController.setErrors(doc, "semantic-highlighter", errors); 1088 } 1089 1090 }; 1091 1092} 1093 | Popular Tags |