1 19 20 package org.netbeans.modules.javadoc.hints; 21 22 import com.sun.javadoc.AnnotationTypeElementDoc; 23 import com.sun.javadoc.AnnotationTypeElementDoc; 24 import com.sun.javadoc.ClassDoc; 25 import com.sun.javadoc.Doc; 26 import com.sun.javadoc.ExecutableMemberDoc; 27 import com.sun.javadoc.MethodDoc; 28 import com.sun.javadoc.ParamTag; 29 import com.sun.javadoc.Tag; 30 import com.sun.javadoc.ThrowsTag; 31 import com.sun.source.tree.ClassTree; 32 import com.sun.source.tree.CompilationUnitTree; 33 import com.sun.source.tree.ErroneousTree; 34 import com.sun.source.tree.ExpressionTree; 35 import com.sun.source.tree.MethodTree; 36 import com.sun.source.tree.Tree; 37 import com.sun.source.tree.TypeParameterTree; 38 import com.sun.source.tree.VariableTree; 39 import com.sun.source.util.TreePath; 40 import com.sun.source.util.TreePathScanner; 41 import java.awt.EventQueue ; 42 import java.beans.PropertyChangeListener ; 43 import java.io.IOException ; 44 import java.util.ArrayList ; 45 import java.util.Collections ; 46 import java.util.HashMap ; 47 import java.util.List ; 48 import java.util.Map ; 49 import java.util.Set ; 50 import java.util.logging.Level ; 51 import java.util.logging.Logger ; 52 import javax.lang.model.SourceVersion; 53 import javax.lang.model.element.AnnotationMirror; 54 import javax.lang.model.element.Element; 55 import javax.lang.model.element.ElementKind; 56 import javax.lang.model.element.ExecutableElement; 57 import javax.lang.model.element.Modifier; 58 import javax.lang.model.element.TypeElement; 59 import javax.lang.model.element.TypeParameterElement; 60 import javax.lang.model.type.TypeKind; 61 import javax.lang.model.type.TypeMirror; 62 import javax.swing.text.BadLocationException ; 63 import javax.swing.text.Document ; 64 import javax.swing.text.Position ; 65 import javax.swing.text.StyledDocument ; 66 import org.netbeans.api.editor.guards.GuardedSection; 67 import org.netbeans.api.editor.guards.GuardedSectionManager; 68 import org.netbeans.api.java.lexer.JavaTokenId; 69 import org.netbeans.api.java.queries.SourceLevelQuery; 70 import org.netbeans.api.java.source.CancellableTask; 71 import org.netbeans.api.java.source.Comment; 72 import org.netbeans.api.java.source.CompilationInfo; 73 import org.netbeans.api.java.source.ElementHandle; 74 import org.netbeans.api.java.source.JavaSource; 75 import org.netbeans.api.java.source.SourceUtils; 76 import org.netbeans.api.java.source.WorkingCopy; 77 import org.netbeans.api.lexer.TokenSequence; 78 import org.netbeans.modules.javadoc.hints.JavadocUtilities.TagHandle; 79 import org.netbeans.spi.editor.hints.ChangeInfo; 80 import org.netbeans.spi.editor.hints.ErrorDescription; 81 import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; 82 import org.netbeans.spi.editor.hints.Fix; 83 import org.netbeans.spi.editor.hints.HintsController; 84 import org.netbeans.spi.editor.hints.LazyFixList; 85 import org.netbeans.spi.editor.hints.Severity; 86 import org.openide.cookies.EditorCookie; 87 import org.openide.cookies.LineCookie; 88 import org.openide.filesystems.FileObject; 89 import org.openide.loaders.DataObject; 90 import org.openide.text.Line; 91 import org.openide.text.NbDocument; 92 import org.openide.util.NbBundle; 93 94 109 public final class JavadocHintProvider implements CancellableTask<CompilationInfo> { 110 111 private static final Severity hintSeverity = Severity.WARNING; 112 private static final int NOPOS = -2; private final FileObject file; 114 private boolean cancel = false; 115 116 private static int CREATE_JAVADOC_HINT_LIMIT = Integer.MAX_VALUE; 119 private static int FIX_JAVADOC_HINT_LIMIT = Integer.MAX_VALUE; 121 122 private static Access access; 123 124 125 public JavadocHintProvider(FileObject file) { 126 this.file = file; 127 } 128 129 public void cancel() { 130 this.cancel = true; 131 } 132 133 boolean isCanceled() { 134 return cancel; 135 } 136 137 public void run(CompilationInfo javac) throws Exception { 138 readSettings(); 139 if (CREATE_JAVADOC_HINT_LIMIT <= 0 && FIX_JAVADOC_HINT_LIMIT <= 0) { 140 return; 141 } 142 143 Document doc = javac.getDocument(); 144 if (doc == null) { 145 return; 146 } 147 List <ErrorDescription> errors = new ArrayList <ErrorDescription>(); 148 Analyzer an = new Analyzer(javac, doc); 149 try { 150 an.scan(javac.getCompilationUnit(), errors); 151 } catch (CancelException ex) { 152 return; 154 } 155 HintsController.setErrors(file, "javadoc", errors); 156 } 157 158 private static void readSettings() { 160 if (access != null) { 161 return; 162 } 163 String s = System.getProperty("org.netbeans.modules.javadoc.hints.MissingJavadocLimit"); try { 165 if (s != null) { 166 CREATE_JAVADOC_HINT_LIMIT = Integer.parseInt(s); 167 } 168 } catch (NumberFormatException ex) { 169 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 170 } 171 172 s = System.getProperty("org.netbeans.modules.javadoc.hints.FixJavadocTagLimit"); try { 174 if (s != null) { 175 FIX_JAVADOC_HINT_LIMIT = Integer.parseInt(s); 176 } 177 } catch (NumberFormatException ex) { 178 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 179 } 180 181 s = System.getProperty("org.netbeans.modules.javadoc.hints.Visibility"); access = Access.resolve(s); 185 } 186 187 private static SourceVersion resolveSourceVersion(FileObject file) { 188 String sourceLevel = SourceLevelQuery.getSourceLevel(file); 189 if (sourceLevel == null) { 190 return SourceVersion.latest(); 191 } else if (sourceLevel.startsWith("1.6")) { 192 return SourceVersion.RELEASE_6; 193 } else if (sourceLevel.startsWith("1.5")) { 194 return SourceVersion.RELEASE_5; 195 } else if (sourceLevel.startsWith("1.4")) { 196 return SourceVersion.RELEASE_4; 197 } else if (sourceLevel.startsWith("1.3")) { 198 return SourceVersion.RELEASE_3; 199 } else if (sourceLevel.startsWith("1.2")) { 200 return SourceVersion.RELEASE_2; 201 } else if (sourceLevel.startsWith("1.1")) { 202 return SourceVersion.RELEASE_1; 203 } else if (sourceLevel.startsWith("1.0")) { 204 return SourceVersion.RELEASE_1; 205 } 206 207 return SourceVersion.latest(); 208 209 } 210 211 private final class Analyzer extends TreePathScanner<Void , List <ErrorDescription>> { 212 213 private final CompilationInfo javac; 214 private final SourceVersion spec; 215 private final FixAll fixAll = new FixAll(); 216 private final Document doc; 217 private int createJavadocHintCounter = CREATE_JAVADOC_HINT_LIMIT; 218 private int fixJavadocHintCounter = FIX_JAVADOC_HINT_LIMIT; 219 220 Analyzer(CompilationInfo javac, Document doc) { 221 this.javac = javac; 222 this.doc = doc; 223 this.spec = resolveSourceVersion(javac.getFileObject()); 224 } 225 226 @Override 227 public Void visitCompilationUnit(CompilationUnitTree node, List <ErrorDescription> arg1) { 228 return scan(node.getTypeDecls(), arg1); 229 } 230 231 @Override 232 public Void visitClass(ClassTree node, List <ErrorDescription> arg1) { 233 if (access.isAccesible(node.getModifiers().getFlags())) { 234 processNode(node, arg1); 235 return scan(node.getMembers(), arg1); 237 } 238 return null; 239 } 240 241 @Override 242 public Void visitMethod(MethodTree node, List <ErrorDescription> arg1) { 243 Tree clazz = getCurrentPath().getParentPath().getLeaf(); 244 if (clazz.getKind() == Tree.Kind.CLASS && 245 (javac.getTreeUtilities().isInterface((ClassTree) clazz) || 246 javac.getTreeUtilities().isAnnotation((ClassTree) clazz) || 247 access.isAccesible(node.getModifiers().getFlags()))) { 248 processNode(node, arg1); 249 } 250 return null; 251 } 252 253 @Override 254 public Void visitVariable(VariableTree node, List <ErrorDescription> arg1) { 255 if (access.isAccesible(node.getModifiers().getFlags())) { 256 processNode(node, arg1); 257 } 258 return null; 259 } 260 261 @Override 262 public Void visitErroneous(ErroneousTree node, 263 List <ErrorDescription> p) { 264 return null; 266 } 267 268 void processNode(Tree node, List <ErrorDescription> errors) { 269 checkTaskState(); 270 271 if (javac.getTreeUtilities().isSynthetic(getCurrentPath())) { 272 return; 273 } 274 Element elm = javac.getTrees().getElement(getCurrentPath()); 276 277 if (elm == null) { 278 Logger.getLogger(JavadocHintProvider.class.getName()).log( 279 Level.INFO, "Cannot resolve element for " + node + " in " + file); return; 281 } else if (isGuarded(node)) { 282 return; 283 } 284 285 String jdText = javac.getElements().getDocComment(elm); 286 if (jdText == null) { 288 if (createJavadocHintCounter <= 0 || JavadocUtilities.hasInheritedDoc(javac, elm)) { 289 return; 290 } 291 292 try { 293 Position [] positions = createSignaturePositions(node); 294 ErrorDescription err = ErrorDescriptionFactory.createErrorDescription( 295 hintSeverity, 296 NbBundle.getMessage(JavadocHintProvider.class, "MISSING_JAVADOC_DESC"), createGenerateFixes(elm), 298 doc, 299 positions[0], 300 positions[1]); 301 errors.add(err); 302 if (--createJavadocHintCounter <= 0) { 303 ErrorDescription warning = ErrorDescriptionFactory.createErrorDescription( 304 Severity.WARNING, 305 NbBundle.getMessage(JavadocHintProvider.class, "OUT_OF_MISSING_JD_LIMIT_DESC", CREATE_JAVADOC_HINT_LIMIT), doc, 307 positions[0], 308 positions[1]); 309 errors.add(warning); 310 } 311 } catch (BadLocationException ex) { 312 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 313 } 314 } else { 315 if (fixJavadocHintCounter <= 0) { 316 return; 317 } 318 319 try { 320 Doc jDoc = javac.getElementUtilities().javaDocFor(elm); 321 if (jDoc.isMethod() || jDoc.isConstructor()) { 322 ExecutableMemberDoc methDoc = (ExecutableMemberDoc) jDoc; 323 ExecutableElement methodEl = (ExecutableElement) elm; 324 MethodTree methodTree = (MethodTree) node; 325 processParameters(methodEl, methodTree, methDoc, errors); 326 processReturn(methodEl, methodTree, methDoc, errors); 327 processThrows(methodEl, methodTree, methDoc, errors); 328 } else if(jDoc.isClass() || jDoc.isInterface()) { 329 TypeElement classEl = (TypeElement) elm; 330 ClassDoc classDoc = (ClassDoc) jDoc; 331 ClassTree classTree = (ClassTree) node; 332 processTypeParameters(classEl, classTree, classDoc, errors); 333 } else if (jDoc.isAnnotationType()) { 334 processAnnTypeParameters(elm, node, jDoc, errors); 335 } else if (jDoc.isAnnotationTypeElement()) { 336 AnnotationTypeElementDoc annDoc = (AnnotationTypeElementDoc) jDoc; 337 ExecutableElement methodEl = (ExecutableElement) elm; 338 MethodTree methodTree = (MethodTree) node; 339 processAnnTypeParameters(methodEl, methodTree, annDoc, errors); 340 processReturn(methodEl, methodTree, annDoc, errors); 341 processAnnTypeThrows(methodEl, methodTree, annDoc, errors); 342 } 343 344 processDeprecatedAnnotation(elm, jDoc, errors); 345 } catch (OutOfLimitException ex) { 346 } 348 349 } 350 } 351 352 private void processDeprecatedAnnotation(Element elm, Doc jDoc, List <ErrorDescription> errors) { 353 if (SourceVersion.RELEASE_5.compareTo(spec) > 0) { 354 return; 356 } 357 358 Tag[] deprTags = jDoc.tags("@deprecated"); AnnotationMirror annMirror = JavadocUtilities.findDeprecated(javac, elm); 360 361 if (annMirror != null) { 362 if (deprTags.length == 0) { 364 try { 366 Position [] poss = createPositions(javac.getTrees().getTree(elm, annMirror)); 367 ErrorDescription err = ErrorDescriptionFactory.createErrorDescription( 368 hintSeverity, 369 NbBundle.getMessage(JavadocHintProvider.class, "MISSING_DEPRECATED_DESC"), Collections.<Fix>singletonList(AddTagFix.createAddDeprecatedTagFix(elm, file, spec)), 371 doc, poss[0], poss[1]); 372 addTagHint(errors, err); 373 } catch (BadLocationException ex) { 374 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 375 } 376 } else if (deprTags.length > 1) { 377 boolean isFirst = true; 379 for (Tag tag : deprTags) { 380 if (isFirst) { 381 isFirst = false; 382 continue; 383 } 384 addRemoveTagFix(tag, 385 NbBundle.getMessage(JavadocHintProvider.class, "DUPLICATE_DEPRECATED_DESC"), elm, errors); 387 } 388 } 389 } else { 390 if (deprTags.length > 1) { 392 boolean isFirst = true; 394 for (Tag tag : deprTags) { 395 if (isFirst) { 396 isFirst = false; 397 continue; 398 } 399 addRemoveTagFix(tag, 400 NbBundle.getMessage(JavadocHintProvider.class, "DUPLICATE_DEPRECATED_DESC"), elm, errors); 402 } 403 } 404 if (deprTags.length > 0) { 405 } 408 } 409 } 410 411 private void processReturn(ExecutableElement exec, MethodTree node, ExecutableMemberDoc jdoc, List <ErrorDescription> errors) { 412 final TypeMirror returnType = exec.getReturnType(); 413 final Tree returnTree = node.getReturnType(); 414 final Tag[] tags = jdoc.tags("@return"); 416 if (returnType.getKind() == TypeKind.VOID) { 417 for (int i = 0; i < tags.length; i++) { 419 Tag tag = tags[i]; 420 addRemoveTagFix(tag, 421 NbBundle.getMessage(JavadocHintProvider.class, 422 jdoc.isMethod()? "WRONG_RETURN_DESC": "WRONG_CONSTRUCTOR_RETURN_DESC"), exec, errors); 424 } 425 } else { 426 for (int i = 0; i < tags.length; i++) { 427 Tag tag = tags[i]; 429 if (i > 0) { 430 addRemoveTagFix(tag, 431 NbBundle.getMessage(JavadocHintProvider.class, "DUPLICATE_RETURN_DESC"), exec, errors); 433 } 434 } 435 } 436 437 if (returnType.getKind() != TypeKind.VOID && tags.length == 0 && 438 JavadocUtilities.findReturnTag(javac, (MethodDoc) jdoc, true) == null) { 439 try { 441 Position [] poss = createPositions(returnTree); 442 ErrorDescription err = ErrorDescriptionFactory.createErrorDescription( 443 hintSeverity, 444 NbBundle.getMessage(JavadocHintProvider.class, "MISSING_RETURN_DESC"), Collections.<Fix>singletonList(AddTagFix.createAddReturnTagFix(exec, file, spec)), 446 doc, poss[0], poss[1]); 447 addTagHint(errors, err); 448 } catch (BadLocationException ex) { 449 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 450 } 451 } 452 453 } 454 455 private void processThrows(ExecutableElement exec, MethodTree node, ExecutableMemberDoc jdoc, List <ErrorDescription> errors) { 456 final List <? extends ExpressionTree> throwz = node.getThrows(); 457 final ThrowsTag[] tags = jdoc.throwsTags(); 458 459 Map <String , ThrowsTag> tagNames = new HashMap <String , ThrowsTag>(); 460 for (ThrowsTag throwsTag : tags) { 461 com.sun.javadoc.Type tagType = throwsTag.exceptionType(); 462 String tagFQN = null; 463 if (tagType != null) { tagFQN = throwsTag.exceptionType().qualifiedTypeName(); 465 } else { 466 tagFQN = throwsTag.exceptionName(); 467 } 468 if (tagNames.containsKey(tagFQN)) { 469 addRemoveTagFix(throwsTag, 471 NbBundle.getMessage(JavadocHintProvider.class, "DUPLICATE_THROWS_DESC", throwsTag.name(), throwsTag.exceptionName()), exec, errors); 473 } else { 474 tagNames.put(tagFQN, throwsTag); 475 } 476 } 477 478 int index = 0; 480 for (ExpressionTree throwTree : throwz) { 481 ++index; 482 TreePath path = new TreePath(getCurrentPath(), throwTree); 483 Element el = javac.getTrees().getElement(path); 484 TypeElement tel = (TypeElement) el; 485 boolean exists = tagNames.remove(tel.getQualifiedName().toString()) != null; 486 if (!exists && (jdoc.isConstructor() || 487 jdoc.isMethod() && 488 JavadocUtilities.findThrowsTag(javac, (MethodDoc) jdoc, tel.getQualifiedName().toString(), true) == null)) { 489 try { 491 Position [] poss = createPositions(throwTree); 492 ErrorDescription err = ErrorDescriptionFactory.createErrorDescription( 493 hintSeverity, 494 NbBundle.getMessage(JavadocHintProvider.class, "MISSING_THROWS_DESC", tel.getQualifiedName().toString()), Collections.<Fix>singletonList(AddTagFix.createAddThrowsTagFix(exec, tel.getQualifiedName().toString(), index, file, spec)), 496 doc, poss[0], poss[1]); 497 addTagHint(errors, err); 498 } catch (BadLocationException ex) { 499 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 500 } 501 } 502 } 503 504 TypeMirror rtException = javac.getElements().getTypeElement("java.lang.RuntimeException").asType(); 506 for (ThrowsTag throwsTag : tagNames.values()) { 508 com.sun.javadoc.Type throwsType = throwsTag.exceptionType(); 510 Doc throwClassDoc = null; 511 if (throwsType != null) { 512 throwClassDoc = throwsType.asClassDoc(); 513 } 514 if (throwClassDoc != null) { 515 Element throwEl = javac.getElementUtilities().elementFor(throwClassDoc); 516 if (throwEl != null && javac.getTypes().isSubtype(throwEl.asType(), rtException)) { 517 break; 519 } 520 } 521 addRemoveTagFix(throwsTag, 522 NbBundle.getMessage(JavadocHintProvider.class, "UNKNOWN_THROWABLE_DESC", throwsTag.name(), throwsTag.exceptionName()), exec, errors); 524 } 525 526 } 527 528 private void processAnnTypeThrows(ExecutableElement exec, MethodTree node, AnnotationTypeElementDoc jdoc, List <ErrorDescription> errors) { 529 Tag[] tags = jdoc.tags("@throws"); 532 for (Tag tag : tags) { 533 ThrowsTag throwsTag = (ThrowsTag) tag; 535 addRemoveTagFix(throwsTag, 536 NbBundle.getMessage(JavadocHintProvider.class, "ILLEGAL_ANNOTATION_TYPE_THROWS_DESC", throwsTag.name(), 538 throwsTag.exceptionName()), 539 exec, errors); 540 } 541 } 542 543 private void processAnnTypeParameters(Element elm, Tree node, Doc jdoc, List <ErrorDescription> errors) { 544 final Tag[] tags = jdoc.tags("@param"); 546 for (Tag tag : tags) { 547 ParamTag paramTag = (ParamTag) tag; 549 addRemoveTagFix(paramTag, 550 NbBundle.getMessage(JavadocHintProvider.class, "ILLEGAL_ANNOTATION_TYPE_PARAM_DESC", paramTag.parameterName()), elm, errors); 552 } 553 } 554 555 private void processParameters(ExecutableElement exec, MethodTree node, ExecutableMemberDoc jdoc, List <ErrorDescription> errors) { 556 final List <? extends VariableTree> params = node.getParameters(); 557 final Tag[] tags = jdoc.tags("@param"); 560 Map <String , ParamTag> tagNames = new HashMap <String , ParamTag>(); 561 for (Tag tag : tags) { 563 ParamTag paramTag = (ParamTag) tag; 564 if (paramTag.isTypeParameter()) { 565 continue; 569 } 570 571 if (tagNames.containsKey(paramTag.parameterName())) { 572 addRemoveTagFix(paramTag, 574 NbBundle.getMessage(JavadocHintProvider.class, "DUPLICATE_PARAM_DESC", paramTag.parameterName()), exec, errors); 576 } else { 577 tagNames.put(paramTag.parameterName(), paramTag); 578 } 579 } 580 581 for (VariableTree param : params) { 583 boolean exists = tagNames.remove(param.getName().toString()) != null; 584 if (!exists && (jdoc.isConstructor() || 585 jdoc.isMethod() && 586 JavadocUtilities.findParamTag(javac, (MethodDoc) jdoc, param.getName().toString(), true) == null)) { 587 try { 589 Position [] poss = createPositions(param); 590 ErrorDescription err = ErrorDescriptionFactory.createErrorDescription( 591 hintSeverity, 592 NbBundle.getMessage(JavadocHintProvider.class, "MISSING_PARAM_DESC", param.getName()), Collections.<Fix>singletonList(AddTagFix.createAddParamTagFix(exec, param.getName().toString(), file, spec)), 594 doc, poss[0], poss[1]); 595 addTagHint(errors, err); 596 } catch (BadLocationException ex) { 597 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 598 } 599 } 600 } 601 602 for (ParamTag paramTag : tagNames.values()) { 604 boolean isTypeParam = false; 606 for (TypeParameterElement typeParameterElement : exec.getTypeParameters()) { 607 if (paramTag.parameterName().equals(typeParameterElement.getSimpleName().toString())) { 608 isTypeParam = true; 609 break; 610 } 611 } 612 if (isTypeParam) { 613 continue; 614 } 615 617 addRemoveTagFix(paramTag, 619 NbBundle.getMessage(JavadocHintProvider.class, "UNKNOWN_PARAM_DESC", paramTag.parameterName()), exec, errors); 621 } 622 623 } 624 625 private void processTypeParameters(TypeElement elm, ClassTree node, ClassDoc jdoc, List <ErrorDescription> errors) { 626 final List <? extends TypeParameterTree> params = node.getTypeParameters(); 627 final Tag[] tags = jdoc.tags("@param"); 630 Map <String , ParamTag> tagNames = new HashMap <String , ParamTag>(); 631 for (Tag tag : tags) { 633 ParamTag paramTag = (ParamTag) tag; 634 if (tagNames.containsKey(paramTag.parameterName())) { 635 addRemoveTagFix(paramTag, 637 NbBundle.getMessage(JavadocHintProvider.class, "DUPLICATE_TYPEPARAM_DESC", paramTag.parameterName()), elm, errors); 639 } else { 640 tagNames.put(paramTag.parameterName(), paramTag); 641 } 642 } 643 644 for (TypeParameterTree param : params) { 646 boolean exists = tagNames.remove(param.getName().toString()) != null; 647 if (!exists ) { 649 try { 651 Position [] poss = createPositions(param); 652 ErrorDescription err = ErrorDescriptionFactory.createErrorDescription( 653 hintSeverity, 654 NbBundle.getMessage(JavadocHintProvider.class, "MISSING_TYPEPARAM_DESC", param.getName()), Collections.<Fix>singletonList(AddTagFix.createAddTypeParamTagFix(elm, param.getName().toString(), file, spec)), 656 doc, poss[0], poss[1]); 657 addTagHint(errors, err); 658 } catch (BadLocationException ex) { 659 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 660 } 661 } 662 } 663 664 for (ParamTag paramTag : tagNames.values()) { 666 addRemoveTagFix(paramTag, 668 NbBundle.getMessage(JavadocHintProvider.class, "UNKNOWN_TYPEPARAM_DESC", paramTag.parameterName()), elm, errors); 670 } 671 } 672 673 Position [] createPositions(Tree t) throws BadLocationException { 674 final Position [] poss = new Position [2]; 675 final int start = (int) javac.getTrees().getSourcePositions(). 676 getStartPosition(javac.getCompilationUnit(), t); 677 final int end = (int) javac.getTrees().getSourcePositions(). 678 getEndPosition(javac.getCompilationUnit(), t); 679 680 poss[0] = doc.createPosition(start); 682 poss[1] = doc.createPosition(end); 683 return poss; 684 } 685 686 689 Position [] createSignaturePositions(final Tree t) throws BadLocationException { 690 final Position [] pos = new Position [2]; 691 final BadLocationException [] blex = new BadLocationException [1]; 692 NbDocument.runAtomic((StyledDocument ) doc, new Runnable () { 693 public void run() { 694 try { 695 TokenSequence<JavaTokenId> tseq = null; 696 if (t.getKind() == Tree.Kind.METHOD) { tseq = JavadocUtilities.findMethodNameToken(javac, (ClassTree) getCurrentPath().getParentPath().getLeaf(), (MethodTree) t); 698 } else if (t.getKind() == Tree.Kind.CLASS) { 699 tseq = JavadocUtilities.findClassNameToken(javac, (ClassTree) t); 700 } else if (Tree.Kind.VARIABLE == t.getKind()) { 701 tseq = JavadocUtilities.findVariableNameToken(javac, (VariableTree) t, 702 javac.getTreeUtilities().isEnum((ClassTree) getCurrentPath().getParentPath().getLeaf())); 703 } 704 705 if (tseq != null) { 706 pos[0] = doc.createPosition(tseq.offset()); 707 pos[1] = doc.createPosition(tseq.offset() + tseq.token().length()); 708 return; 709 } 710 711 assert true: t.toString(); 712 } catch (BadLocationException ex) { 713 blex[0] = ex; 714 } 715 } 716 }); 717 if (blex[0] != null) 718 throw (BadLocationException ) new BadLocationException (blex[0].getMessage(), blex[0].offsetRequested()).initCause(blex[0]); 719 return pos; 720 } 721 722 private boolean isGuarded(Tree node) { 723 GuardedSectionManager guards = GuardedSectionManager.getInstance((StyledDocument ) doc); 724 if (guards != null) { 725 try { 726 final int startOff = (int) javac.getTrees().getSourcePositions(). 727 getStartPosition(javac.getCompilationUnit(), node); 728 final Position startPos = doc.createPosition(startOff); 729 730 for (GuardedSection guard : guards.getGuardedSections()) { 731 if (guard.contains(startPos, false)) { 732 return true; 733 } 734 } 735 } catch (BadLocationException ex) { 736 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 737 return true; 739 } 740 } 741 return false; 742 } 743 744 private void addRemoveTagFix(Tag tag, String description, Element elm, List <ErrorDescription> errors) { 745 try { 746 Position [] poss = JavadocUtilities.findTagNameBounds(javac, doc, tag); 747 if (poss == null) { 748 throw new BadLocationException ("no position for " + tag, -1); } 750 ErrorDescription err = ErrorDescriptionFactory.createErrorDescription( 751 hintSeverity, 752 description, 753 Collections.<Fix>singletonList(new RemoveTagFix(tag.name(), TagHandle.create(tag), ElementHandle.create(elm), file, spec)), 754 doc, poss[0], poss[1]); 755 addTagHint(errors, err); 756 } catch (BadLocationException ex) { 757 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 758 } 759 } 760 761 JavadocLazyFixList createGenerateFixes(Element elm) { 762 List <Fix> fixes = new ArrayList <Fix>(3); 763 ElementHandle handle = ElementHandle.create(elm); 764 765 String description; 766 if (elm.getKind() == ElementKind.CONSTRUCTOR) { 767 description = elm.getEnclosingElement().getSimpleName().toString(); 768 } else { 769 description = elm.getSimpleName().toString(); 770 } 771 772 JavadocLazyFixList fixList = new JavadocLazyFixList(fixes, fixAll); 773 774 GenerateJavadocFix jdFix = new GenerateJavadocFix(description, handle, javac.getFileObject(), this.spec); 775 776 fixes.add(jdFix); 777 fixAll.addFix(jdFix); 778 779 781 return fixList; 786 } 787 788 private void addTagHint(List <ErrorDescription> errors, ErrorDescription desc) { 789 errors.add(desc); 790 checkTaskState(); 791 if (--fixJavadocHintCounter <= 0) { 792 try { 793 ErrorDescription warning = ErrorDescriptionFactory.createErrorDescription( 794 Severity.WARNING, 795 NbBundle.getMessage(JavadocHintProvider.class, "OUT_OF_TAG_FIXES_LIMIT_DESC", FIX_JAVADOC_HINT_LIMIT), doc, 797 desc.getRange().getBegin().getPosition(), 798 desc.getRange().getEnd().getPosition()); 799 errors.add(warning); 800 } catch (IOException ex) { 801 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.INFO, ex.getMessage(), ex); 802 } 803 throw new OutOfLimitException(); 804 } 805 } 806 807 private void checkTaskState() { 808 if (isCanceled()) { 809 throw new CancelException(); 810 } 811 } 812 } 813 814 private static final class JavadocLazyFixList implements LazyFixList { 815 816 private List <Fix> contexFixes; 817 private FixAll fixAll; 818 819 public JavadocLazyFixList(List <Fix> contexFixes, FixAll fixAll) { 820 this.contexFixes = contexFixes; 821 this.fixAll = fixAll; 822 } 823 824 public void addPropertyChangeListener(PropertyChangeListener l) { 825 } 826 827 public void removePropertyChangeListener(PropertyChangeListener l) { 828 } 829 830 public boolean probablyContainsFixes() { 831 return true; 832 } 833 834 public List <Fix> getFixes() { 835 if (fixAll.isReady()) { 836 contexFixes.add(fixAll); 837 } 838 return contexFixes; 839 } 840 841 public boolean isComputed() { 842 return true; 843 } 844 845 } 846 847 private static final class FixAll implements Fix { 848 849 private List <GenerateJavadocFix> allJavadocFixes = new ArrayList <GenerateJavadocFix>(); 850 851 public void addFix(GenerateJavadocFix f) { 852 allJavadocFixes.add(f); 853 } 854 855 public boolean isReady() { 856 return allJavadocFixes.size() > 1; 857 } 858 859 public String getText() { 860 return NbBundle.getMessage(JavadocHintProvider.class, "FIX_ALL_HINT"); } 862 863 public ChangeInfo implement() { 864 for (GenerateJavadocFix javadocFix : allJavadocFixes) { 865 javadocFix.implement(false); 866 } 867 868 return null; 869 } 870 871 } 872 873 private static final class GenerateJavadocFix implements Fix { 874 private String name; 875 private final ElementHandle handle; 876 private final FileObject file; 877 private Position position; 878 private final SourceVersion spec; 879 880 GenerateJavadocFix(String name, ElementHandle handle, FileObject file, SourceVersion spec) { 881 this.name = name; 882 this.handle = handle; 883 this.file = file; 884 this.spec = spec; 885 } 886 887 public String getText() { 888 return NbBundle.getMessage(JavadocHintProvider.class, "MISSING_JAVADOC_HINT", name); } 890 891 public ChangeInfo implement() { 892 return implement(true); 893 } 894 895 public ChangeInfo implement(final boolean open) { 896 final String [] javadocForDocument = new String [1]; 897 final Document [] docs = new Document [1]; 898 JavaSource js = JavaSource.forFileObject(file); 899 try { 900 js.runModificationTask(new CancellableTask<WorkingCopy>() { 901 public void cancel() { 902 } 903 904 public void run(WorkingCopy wc) throws Exception { 905 wc.toPhase(JavaSource.Phase.RESOLVED); 906 Element elm = handle.resolve(wc); 907 Tree t = null; 908 if (elm != null) { 909 t = SourceUtils.treeFor(wc, elm); 910 } 911 if (t != null) { 912 JavadocGenerator gen = new JavadocGenerator(GenerateJavadocFix.this.spec); 913 String javadocTxt = gen.generateComment(elm, wc); 914 Comment javadoc = Comment.create(Comment.Style.JAVADOC, NOPOS, NOPOS, 0, javadocTxt); 915 wc.getTreeMaker().addComment(t, javadoc, true); 916 917 javadocForDocument[0] = javadocTxt; 919 docs[0] = wc.getDocument(); 920 if (docs[0] == null) { 921 return; 922 } 923 position = docs[0].createPosition((int) wc.getTrees().getSourcePositions().getStartPosition(wc.getCompilationUnit(), t)); 924 } 925 } 926 927 }).commit(); 928 929 } catch (IOException ex) { 930 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.SEVERE, ex.getMessage(), ex); 931 } 932 933 try { 935 if (docs[0] == null) { 936 return null; 938 } 939 940 NbDocument.runAtomicAsUser((StyledDocument ) docs[0], new Runnable () { 941 public void run() { 942 try { 943 String tab = JavadocGenerator.guessIndentation(docs[0], position); 944 String iJavadoc = JavadocGenerator.indentJavadoc(javadocForDocument[0], tab); 945 docs[0].insertString(position.getOffset(), iJavadoc, null); 946 int offset = iJavadoc.indexOf("\n"); 949 offset = iJavadoc.indexOf("\n", offset + 1); 951 offset = position.getOffset() + offset - iJavadoc.length(); 953 if (open) doOpen(file, offset); 954 } catch (BadLocationException ex) { 955 ex.printStackTrace(); 956 } 957 } 958 }); 959 } catch (BadLocationException ex) { 960 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.SEVERE, ex.getMessage(), ex); 961 } 962 return null; 963 } 964 } 965 966 private static final class RemoveTagFix implements Fix, CancellableTask<WorkingCopy> { 967 968 private String tagName; 969 private final TagHandle tagHandle; 970 private final ElementHandle handle; 971 private final FileObject file; 972 private final SourceVersion spec; 973 974 private Position [] tagBounds; 975 private Document doc; 976 977 RemoveTagFix(String tagName, TagHandle tagHandle, ElementHandle elmHandle, FileObject file, SourceVersion spec) { 978 this.tagName = tagName; 979 this.tagHandle = tagHandle; 980 this.handle = elmHandle; 981 this.file = file; 982 this.spec = spec; 983 } 984 985 public String getText() { 986 return NbBundle.getMessage(JavadocHintProvider.class, "REMOVE_TAG_HINT", tagName); } 988 989 public ChangeInfo implement() { 990 return implement(true); 991 } 992 993 private void removeTag(final CompilationInfo ci, Element elm) throws IOException , BadLocationException { 994 final Doc jdoc = ci.getElementUtilities().javaDocFor(elm); 995 if (jdoc != null) { 996 final Tag tag = tagHandle.resolve(jdoc); 997 if (tag == null) { 998 return; 999 } 1000 1001 final Document doc = ci.getDocument(); 1002 if (doc == null) { 1003 return; 1004 } 1005 NbDocument.runAtomicAsUser((StyledDocument ) doc, new Runnable () { 1006 public void run() { 1007 try { 1008 tagBounds = JavadocUtilities.findTagBounds(ci, doc, tag); 1009 } catch (BadLocationException ex) { 1010 Logger.getLogger(JavadocHintProvider.class.getName()). 1011 log(Level.SEVERE, ex.getMessage(), ex); 1012 } 1013 } 1014 }); 1015 } 1016 } 1017 1018 private void removeTag() throws BadLocationException { 1019 if (tagBounds == null || doc == null) { 1020 return; 1021 } 1022 NbDocument.runAtomicAsUser((StyledDocument ) doc, new Runnable () { 1023 public void run() { 1024 try { 1025 doc.remove(tagBounds[0].getOffset(), tagBounds[1].getOffset() - tagBounds[0].getOffset()); 1026 } catch (BadLocationException ex) { 1027 Logger.getLogger(JavadocHintProvider.class.getName()). 1028 log(Level.SEVERE, ex.getMessage(), ex); 1029 } 1030 } 1031 }); 1032 } 1033 1034 public ChangeInfo implement(final boolean open) { 1035 JavaSource js = JavaSource.forFileObject(file); 1036 try { 1037 js.runModificationTask(this).commit(); 1038 removeTag(); 1040 } catch (BadLocationException ex) { 1041 Logger.getLogger(JavadocHintProvider.class.getName()). 1042 log(Level.SEVERE, ex.getMessage(), ex); 1043 } catch (IOException ex) { 1044 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.SEVERE, ex.getMessage(), ex); 1045 } 1046 1047 return null; 1048 } 1049 1050 public void cancel() { 1051 } 1052 1053 public void run(WorkingCopy wc) throws Exception { 1054 wc.toPhase(JavaSource.Phase.RESOLVED); 1055 Element elm = handle.resolve(wc); 1056 Tree t = null; 1057 if (elm != null) { 1058 t = SourceUtils.treeFor(wc, elm); 1059 } 1060 if (t != null) { 1061 removeTag(wc, elm); 1062 doc = wc.getDocument(); 1063 } 1064 } 1065 1066 } 1067 1068 private static final class AddTagFix implements Fix, CancellableTask<WorkingCopy> { 1069 1070 private enum Kind {PARAM, RETURN, THROWS, TYPEPARAM, DEPRECATED} 1071 private final ElementHandle methodHandle; 1072 private final String paramName; 1073 1074 private final int index; 1075 private final FileObject file; 1076 private final SourceVersion spec; 1077 private final String descKey; 1078 private final Kind kind; 1079 1080 private Position insertPosition; 1081 String insertJavadoc; 1082 private int openOffset; 1083 Document doc; 1084 1085 private AddTagFix(ElementHandle methodHandle, String paramName, int index, 1086 FileObject file, SourceVersion spec, String descKey, Kind tagKind) { 1087 this.methodHandle = methodHandle; 1088 this.paramName = paramName; 1089 this.index = index; 1090 this.file = file; 1091 this.spec = spec; 1092 this.descKey = descKey; 1093 this.kind = tagKind; 1094 } 1095 1096 public static Fix createAddParamTagFix(ExecutableElement elm, 1097 String paramName, FileObject file, SourceVersion spec) { 1098 return new AddTagFix(ElementHandle.create(elm), paramName, -1, file, spec, "MISSING_PARAM_HINT", Kind.PARAM); } 1100 1101 public static Fix createAddTypeParamTagFix(TypeElement elm, 1102 String paramName, FileObject file, SourceVersion spec) { 1103 return new AddTagFix(ElementHandle.create(elm), paramName, -1, file, spec, "MISSING_TYPEPARAM_HINT", Kind.TYPEPARAM); } 1105 1106 public static Fix createAddReturnTagFix(ExecutableElement elm, 1107 FileObject file, SourceVersion spec) { 1108 return new AddTagFix(ElementHandle.create(elm), "", -1, file, spec, "MISSING_RETURN_HINT", Kind.RETURN); } 1110 1111 public static Fix createAddThrowsTagFix(ExecutableElement elm, 1112 String fqn, int throwIndex, FileObject file, SourceVersion spec) { 1113 return new AddTagFix(ElementHandle.create(elm), fqn, throwIndex, file, spec, "MISSING_THROWS_HINT", Kind.THROWS); } 1115 1116 public static Fix createAddDeprecatedTagFix(Element elm, 1117 FileObject file, SourceVersion spec) { 1118 return new AddTagFix(ElementHandle.create(elm), "", -1, file, spec, "MISSING_DEPRECATED_HINT", Kind.DEPRECATED); } 1120 1121 public String getText() { 1122 return NbBundle.getMessage(JavadocHintProvider.class, descKey, this.paramName); 1123 } 1124 1125 public ChangeInfo implement() { 1126 JavaSource js = JavaSource.forFileObject(file); 1127 try { 1128 js.runModificationTask(this).commit(); 1129 if (doc == null || insertPosition == null || insertJavadoc == null) { 1130 return null; 1131 } 1132 int open = insertPosition.getOffset() + openOffset; 1133 insertJavadoc(); 1134 doOpen(file, open); 1135 } catch (BadLocationException ex) { 1136 Logger.getLogger(JavadocHintProvider.class.getName()). 1137 log(Level.SEVERE, ex.getMessage(), ex); 1138 } catch (IOException ex) { 1139 Logger.getLogger(JavadocHintProvider.class.getName()). 1140 log(Level.SEVERE, ex.getMessage(), ex); 1141 } 1142 return null; 1143 } 1144 1145 public void run(final WorkingCopy wc) throws Exception { 1146 wc.toPhase(JavaSource.Phase.RESOLVED); 1147 final Element elm = methodHandle.resolve(wc); 1148 if (elm == null) { 1149 return; 1150 } 1151 1152 final Doc jdoc = wc.getElementUtilities().javaDocFor(elm); 1153 doc = wc.getDocument(); 1154 if (doc == null) { 1155 return; 1156 } 1157 1158 NbDocument.runAtomicAsUser((StyledDocument ) doc, new Runnable () { 1159 public void run() { 1160 try { 1161 computeInsertPositionAndJavadoc(wc, elm, jdoc); 1162 } catch (BadLocationException ex) { 1163 Logger.getLogger(JavadocHintProvider.class.getName()). 1164 log(Level.SEVERE, ex.getMessage(), ex); 1165 } 1166 } 1167 }); 1168 } 1169 1170 private void computeInsertPositionAndJavadoc(CompilationInfo wc, Element elm, Doc jdoc) throws BadLocationException { 1171 boolean[] isLastTag = new boolean[1]; 1173 switch (this.kind) { 1174 case PARAM: 1175 insertPosition = getParamInsertPosition(wc, doc, (ExecutableElement) elm, jdoc, isLastTag); 1176 insertJavadoc = "@param " + paramName + " "; break; 1178 case TYPEPARAM: 1179 insertPosition = getTypeParamInsertPosition(wc, doc, (TypeElement) elm, jdoc, isLastTag); 1180 insertJavadoc = "@param " + paramName + " "; break; 1182 case RETURN: 1183 insertPosition = getReturnInsertPosition(wc, doc, jdoc, isLastTag); 1184 insertJavadoc = "@return "; break; 1186 case THROWS: 1187 insertPosition = getThrowsInsertPosition(wc, doc, (ExecutableMemberDoc) jdoc, isLastTag); 1188 insertJavadoc = "@throws " + paramName + " "; break; 1190 case DEPRECATED: 1191 insertPosition = getDeprecatedInsertPosition(wc, doc, jdoc, isLastTag); 1192 insertJavadoc = "@deprecated "; break; 1194 default: 1195 throw new IllegalStateException (); 1196 } 1197 1198 Position [] jdBounds = JavadocUtilities.findDocBounds(wc, doc, jdoc); 1202 int jdBeginLine = NbDocument.findLineNumber((StyledDocument ) doc, jdBounds[0].getOffset()); 1203 int jdEndLine = NbDocument.findLineNumber((StyledDocument ) doc, jdBounds[1].getOffset()); 1204 int insertLine = NbDocument.findLineNumber((StyledDocument ) doc, insertPosition.getOffset()); 1205 1206 String indentation = JavadocGenerator.guessJavadocIndentation(wc, doc, jdoc); if (jdBeginLine == insertLine && insertLine == jdEndLine) { 1208 insertJavadoc = '\n' + indentation + "* " + insertJavadoc; openOffset = insertJavadoc.length(); 1211 insertJavadoc += '\n' + indentation; 1212 } else if (insertLine == jdEndLine && !isLastTag[0]) { 1213 openOffset = 2 + insertJavadoc.length(); 1215 insertJavadoc = "* " + insertJavadoc + '\n' + indentation; } else if (isLastTag[0]) { 1217 insertJavadoc = '\n' + indentation + "* " + insertJavadoc; openOffset = insertJavadoc.length(); 1220 } else { 1221 openOffset = insertJavadoc.length(); 1223 insertJavadoc = insertJavadoc + '\n' + indentation + "* "; } 1225 } 1226 1227 private void insertJavadoc() throws BadLocationException { 1228 NbDocument.runAtomicAsUser((StyledDocument ) doc, new Runnable () { 1229 public void run() { 1230 try { 1231 doc.insertString(insertPosition.getOffset(), insertJavadoc, null); 1233 } catch (BadLocationException ex) { 1234 Logger.getLogger(JavadocHintProvider.class.getName()). 1235 log(Level.SEVERE, ex.getMessage(), ex); 1236 } 1237 } 1238 }); 1239 } 1240 1241 public void cancel() { 1242 } 1243 1244 private Position getDeprecatedInsertPosition(CompilationInfo wc, Document doc, Doc jdoc, boolean[] isLastTag) throws BadLocationException { 1245 return getTagInsertPosition(wc, doc, jdoc, null, false, isLastTag); 1247 } 1248 1249 private Position getTypeParamInsertPosition(CompilationInfo wc, Document doc, TypeElement elm, Doc jdoc, boolean[] isLastTag) throws BadLocationException { 1250 Tag[] tags = jdoc.tags("@param"); Tag where = null; 1253 boolean insertBefore = true; 1254 if (tags.length > 0) { 1255 int index = findParamIndex(elm.getTypeParameters(), paramName); 1256 where = index < tags.length? tags[index]: tags[tags.length - 1]; 1257 insertBefore = index < tags.length; 1258 } else { 1259 tags = jdoc.tags(); 1261 if (tags.length > 0) { 1262 where = tags[0]; 1263 } 1264 } 1265 return getTagInsertPosition(wc, doc, jdoc, where, insertBefore, isLastTag); 1266 } 1267 1268 private Position getThrowsInsertPosition(CompilationInfo wc, Document doc, ExecutableMemberDoc jdoc, boolean[] isLastTag) throws BadLocationException { 1269 Tag[] tags = jdoc.throwsTags(); Tag where = null; 1273 boolean insertBefore = true; 1274 if (tags.length > 0) { 1275 int index = this.index; 1276 where = index < tags.length? tags[index]: tags[tags.length - 1]; 1277 insertBefore = index < tags.length; 1278 } else { 1279 tags = jdoc.tags("@return"); if (tags.length == 0) { 1282 tags = jdoc.tags("@param"); } 1284 if (tags.length == 0) { 1285 tags = jdoc.tags(); 1286 } else { 1287 insertBefore = false; 1289 } 1290 if (tags.length > 0) { 1291 where = tags[0]; 1292 } 1293 } 1294 return getTagInsertPosition(wc, doc, jdoc, where, insertBefore, isLastTag); 1295 } 1296 1297 private Position getReturnInsertPosition(CompilationInfo wc, Document doc, Doc jdoc, boolean[] isLastTag) throws BadLocationException { 1298 Tag[] tags = jdoc.tags("@param"); Tag where = null; 1301 boolean insertBefore = true; 1302 if (tags.length > 0) { 1303 where = tags[tags.length - 1]; 1304 insertBefore = false; 1305 } else { 1306 tags = jdoc.tags(); 1308 if (tags.length > 0) { 1309 where = tags[0]; 1310 } 1311 } 1312 return getTagInsertPosition(wc, doc, jdoc, where, insertBefore, isLastTag); 1313 } 1314 1315 private Position getParamInsertPosition(CompilationInfo wc, Document doc, ExecutableElement elm, Doc jdoc, boolean[] isLastTag) throws BadLocationException { 1316 Tag[] tags = jdoc.tags("@param"); Tag where = null; 1320 boolean insertBefore = true; 1321 if (tags.length > 0) { 1322 int index = findParamIndex(elm.getParameters(), paramName); 1323 where = index < tags.length? tags[index]: tags[tags.length - 1]; 1324 insertBefore = index < tags.length; 1325 } else { 1326 tags = jdoc.tags(); 1328 if (tags.length > 0) { 1329 where = tags[0]; 1330 } 1331 } 1332 return getTagInsertPosition(wc, doc, jdoc, where, insertBefore, isLastTag); 1333 } 1334 1335 private Position getTagInsertPosition(CompilationInfo wc, Document doc, Doc jdoc, Tag where, boolean insertBefore, boolean[] isLastTag) throws BadLocationException { 1336 Position [] bounds = null; 1338 if (where != null) { 1339 bounds = JavadocUtilities.findTagBounds(wc, doc, where, isLastTag); 1340 if (insertBefore) { 1341 isLastTag[0] = false; 1342 } 1343 } else { 1344 bounds = JavadocUtilities.findLastTokenBounds(wc, doc, jdoc); 1346 insertBefore = false; 1347 isLastTag[0] = false; 1348 } 1349 1350 return insertBefore? bounds[0]: bounds[1]; 1351 } 1352 1353 private int findParamIndex(List <? extends Element> params, String name) { 1354 int i = 0; 1355 for (Element param : params) { 1356 if (name.contentEquals(param.getSimpleName())) { 1357 return i; 1358 } 1359 i++; 1360 } 1361 throw new IllegalArgumentException ("Unknown param: " + name); } 1363 } 1364 1365 private static void doOpen(final FileObject fo, final int offset) { 1366 EventQueue.invokeLater(new Runnable () { 1367 public void run() { 1368 doOpenImpl(fo, offset); 1369 } 1370 }); 1371 } 1372 1373 private static boolean doOpenImpl(FileObject fo, int offset) { 1374 try { 1375 DataObject od = DataObject.find(fo); 1376 EditorCookie ec = (EditorCookie) od.getCookie(EditorCookie.class); 1377 LineCookie lc = (LineCookie) od.getCookie(LineCookie.class); 1378 1379 if (ec != null && lc != null && offset != -1) { 1380 StyledDocument doc = ec.openDocument(); 1381 if (doc != null) { 1382 int line = NbDocument.findLineNumber(doc, offset); 1383 int lineOffset = NbDocument.findLineOffset(doc, line); 1384 int column = offset - lineOffset; 1385 1386 if (line != -1) { 1387 Line l = lc.getLineSet().getCurrent(line); 1388 1389 if (l != null) { 1390 l.show(Line.SHOW_GOTO, column); 1391 return true; 1392 } 1393 } 1394 } 1395 } 1396 } catch (IOException ex) { 1397 Logger.getLogger(JavadocHintProvider.class.getName()).log(Level.SEVERE, ex.getMessage(), ex); 1398 } 1399 return false; 1400 } 1401 1402 1405 private enum Access { 1406 PUBLIC, PROTECTED, PACKAGE, PRIVATE; 1407 1408 1411 public static Access resolve(String s) { 1412 if (s != null) { 1413 s = s.trim().toLowerCase(); 1414 if ("public".equals(s)) { return Access.PUBLIC; 1416 } else if ("protected".equals(s)) { return Access.PROTECTED; 1418 } else if ("private".equals(s)) { return Access.PRIVATE; 1420 } else if ("package".equals(s)) { return Access.PACKAGE; 1422 } 1423 } 1424 return Access.PROTECTED; 1425 } 1426 1427 public boolean isAccesible(Set <Modifier> flags) { 1428 switch(this) { 1429 case PRIVATE: 1430 return true; 1431 case PACKAGE: 1432 return !flags.contains(Modifier.PRIVATE); 1433 case PROTECTED: 1434 return flags.contains(Modifier.PUBLIC) || flags.contains(Modifier.PROTECTED); 1435 case PUBLIC: 1436 return flags.contains(Modifier.PUBLIC); 1437 default: 1438 throw new IllegalStateException (); 1439 } 1440 } 1441 } 1442 1447 private static final class CancelException extends RuntimeException { 1448 @Override 1449 public synchronized Throwable fillInStackTrace() { 1450 return null; 1451 } 1452 } 1453 1454 1460 private static final class OutOfLimitException extends RuntimeException { 1461 @Override 1462 public synchronized Throwable fillInStackTrace() { 1463 return null; 1464 } 1465 } 1466} 1467 | Popular Tags |