1/* 2 * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.javadoc.internal.doclets.toolkit.taglets; 27 28import java.io.*; 29import java.lang.reflect.InvocationTargetException; 30import java.util.*; 31 32import javax.lang.model.element.Element; 33import javax.lang.model.element.ExecutableElement; 34import javax.lang.model.element.ModuleElement; 35import javax.lang.model.element.PackageElement; 36import javax.lang.model.element.TypeElement; 37import javax.lang.model.element.VariableElement; 38import javax.lang.model.util.SimpleElementVisitor9; 39import javax.tools.JavaFileManager; 40import javax.tools.StandardJavaFileManager; 41 42import com.sun.source.doctree.DocTree; 43import jdk.javadoc.doclet.Doclet; 44import jdk.javadoc.doclet.DocletEnvironment; 45import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; 46import jdk.javadoc.internal.doclets.toolkit.Messages; 47import jdk.javadoc.internal.doclets.toolkit.Resources; 48 49import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; 50import jdk.javadoc.internal.doclets.toolkit.util.Utils; 51 52import static javax.tools.DocumentationTool.Location.*; 53 54import static com.sun.source.doctree.DocTree.Kind.*; 55 56/** 57 * Manages the {@code Taglet}s used by doclets. 58 * 59 * <p><b>This is NOT part of any supported API. 60 * If you write code that depends on this, you do so at your own risk. 61 * This code and its internal interfaces are subject to change or 62 * deletion without notice.</b> 63 * 64 * @author Jamie Ho 65 */ 66 67public class TagletManager { 68 69 /** 70 * The default separator for the simple tag option. 71 */ 72 public static final char SIMPLE_TAGLET_OPT_SEPARATOR = ':'; 73 74 /** 75 * The alternate separator for simple tag options. Use this 76 * when you want the default separator to be in the name of the 77 * custom tag. 78 */ 79 public static final String ALT_SIMPLE_TAGLET_OPT_SEPARATOR = "-"; 80 81 /** 82 * The map of custom tags. 83 */ 84 private final LinkedHashMap<String,Taglet> customTags; 85 86 /** 87 * The array of custom tags that can appear in modules. 88 */ 89 private List<Taglet> moduleTags; 90 91 /** 92 * The array of custom tags that can appear in packages. 93 */ 94 private List<Taglet> packageTags; 95 96 /** 97 * The array of custom tags that can appear in classes or interfaces. 98 */ 99 private List<Taglet> typeTags; 100 101 /** 102 * The array of custom tags that can appear in fields. 103 */ 104 private List<Taglet> fieldTags; 105 106 /** 107 * The array of custom tags that can appear in constructors. 108 */ 109 private List<Taglet> constructorTags; 110 111 /** 112 * The array of custom tags that can appear in methods. 113 */ 114 private List<Taglet> methodTags; 115 116 /** 117 * The array of custom tags that can appear in the overview. 118 */ 119 private List<Taglet> overviewTags; 120 121 /** 122 * The array of custom tags that can appear in comments. 123 */ 124 private List<Taglet> inlineTags; 125 126 /** 127 * The array of custom tags that can appear in the serialized form. 128 */ 129 private List<Taglet> serializedFormTags; 130 131 private final DocletEnvironment docEnv; 132 private final Doclet doclet; 133 134 private final Messages messages; 135 private final Resources resources; 136 137 /** 138 * Keep track of standard tags. 139 */ 140 private final Set<String> standardTags; 141 142 /** 143 * Keep track of standard tags in lowercase to compare for better 144 * error messages when a tag like @docRoot is mistakenly spelled 145 * lowercase @docroot. 146 */ 147 private final Set<String> standardTagsLowercase; 148 149 /** 150 * Keep track of overriden standard tags. 151 */ 152 private final Set<String> overridenStandardTags; 153 154 /** 155 * Keep track of the tags that may conflict 156 * with standard tags in the future (any custom tag without 157 * a period in its name). 158 */ 159 private final Set<String> potentiallyConflictingTags; 160 161 /** 162 * The set of unseen custom tags. 163 */ 164 private final Set<String> unseenCustomTags; 165 166 /** 167 * True if we do not want to use @since tags. 168 */ 169 private final boolean nosince; 170 171 /** 172 * True if we want to use @version tags. 173 */ 174 private final boolean showversion; 175 176 /** 177 * True if we want to use @author tags. 178 */ 179 private final boolean showauthor; 180 181 /** 182 * True if we want to use JavaFX-related tags (@propertyGetter, 183 * @propertySetter, @propertyDescription, @defaultValue, @treatAsPrivate). 184 */ 185 private final boolean javafx; 186 187 /** 188 * Construct a new <code>TagletManager</code>. 189 * @param nosince true if we do not want to use @since tags. 190 * @param showversion true if we want to use @version tags. 191 * @param showauthor true if we want to use @author tags. 192 * @param javafx indicates whether javafx is active. 193 * @param configuration the configuration for this taglet manager 194 */ 195 public TagletManager(boolean nosince, boolean showversion, 196 boolean showauthor, boolean javafx, 197 BaseConfiguration configuration) { 198 overridenStandardTags = new HashSet<>(); 199 potentiallyConflictingTags = new HashSet<>(); 200 standardTags = new HashSet<>(); 201 standardTagsLowercase = new HashSet<>(); 202 unseenCustomTags = new HashSet<>(); 203 customTags = new LinkedHashMap<>(); 204 this.nosince = nosince; 205 this.showversion = showversion; 206 this.showauthor = showauthor; 207 this.javafx = javafx; 208 this.docEnv = configuration.docEnv; 209 this.doclet = configuration.doclet; 210 this.messages = configuration.getMessages(); 211 this.resources = configuration.getResources(); 212 initStandardTaglets(); 213 initStandardTagsLowercase(); 214 } 215 216 /** 217 * Add a new <code>CustomTag</code>. This is used to add a Taglet from within 218 * a Doclet. No message is printed to indicate that the Taglet is properly 219 * registered because these Taglets are typically added for every execution of the 220 * Doclet. We don't want to see this type of error message every time. 221 * @param customTag the new <code>CustomTag</code> to add. 222 */ 223 public void addCustomTag(Taglet customTag) { 224 if (customTag != null) { 225 String name = customTag.getName(); 226 if (customTags.containsKey(name)) { 227 customTags.remove(name); 228 } 229 customTags.put(name, customTag); 230 checkTagName(name); 231 } 232 } 233 234 public Set<String> getCustomTagNames() { 235 return customTags.keySet(); 236 } 237 238 /** 239 * Add a new <code>Taglet</code>. Print a message to indicate whether or not 240 * the Taglet was registered properly. 241 * @param classname the name of the class representing the custom tag. 242 * @param fileManager the filemanager to load classes and resources. 243 * @param tagletPath the path to the class representing the custom tag. 244 */ 245 public void addCustomTag(String classname, JavaFileManager fileManager, String tagletPath) { 246 try { 247 ClassLoader tagClassLoader; 248 if (!fileManager.hasLocation(TAGLET_PATH)) { 249 List<File> paths = new ArrayList<>(); 250 if (tagletPath != null) { 251 for (String pathname : tagletPath.split(File.pathSeparator)) { 252 paths.add(new File(pathname)); 253 } 254 } 255 if (fileManager instanceof StandardJavaFileManager) { 256 ((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, paths); 257 } 258 } 259 tagClassLoader = fileManager.getClassLoader(TAGLET_PATH); 260 Class<? extends jdk.javadoc.doclet.Taglet> customTagClass = 261 tagClassLoader.loadClass(classname).asSubclass(jdk.javadoc.doclet.Taglet.class); 262 jdk.javadoc.doclet.Taglet instance = customTagClass.getConstructor().newInstance(); 263 instance.init(docEnv, doclet); 264 Taglet newLegacy = new UserTaglet(instance); 265 String tname = newLegacy.getName(); 266 Taglet t = customTags.get(tname); 267 if (t != null) { 268 customTags.remove(tname); 269 } 270 customTags.put(tname, newLegacy); 271 messages.notice("doclet.Notice_taglet_registered", classname); 272 } catch (Exception exc) { 273 messages.error("doclet.Error_taglet_not_registered", exc.getClass().getName(), classname); 274 } 275 } 276 277 /** 278 * Add a new <code>SimpleTaglet</code>. If this tag already exists 279 * and the header passed as an argument is null, move tag to the back of the 280 * list. If this tag already exists and the header passed as an argument is 281 * not null, overwrite previous tag with new one. Otherwise, add new 282 * SimpleTaglet to list. 283 * @param tagName the name of this tag 284 * @param header the header to output. 285 * @param locations the possible locations that this tag 286 * can appear in. 287 */ 288 public void addNewSimpleCustomTag(String tagName, String header, String locations) { 289 if (tagName == null || locations == null) { 290 return; 291 } 292 Taglet tag = customTags.get(tagName); 293 locations = Utils.toLowerCase(locations); 294 if (tag == null || header != null) { 295 customTags.remove(tagName); 296 customTags.put(tagName, new SimpleTaglet(tagName, header, locations)); 297 if (locations != null && locations.indexOf('x') == -1) { 298 checkTagName(tagName); 299 } 300 } else { 301 //Move to back 302 customTags.remove(tagName); 303 customTags.put(tagName, tag); 304 } 305 } 306 307 /** 308 * Given a tag name, add it to the set of tags it belongs to. 309 */ 310 private void checkTagName(String name) { 311 if (standardTags.contains(name)) { 312 overridenStandardTags.add(name); 313 } else { 314 if (name.indexOf('.') == -1) { 315 potentiallyConflictingTags.add(name); 316 } 317 unseenCustomTags.add(name); 318 } 319 } 320 321 /** 322 * Check the taglet to see if it is a legacy taglet. Also 323 * check its name for errors. 324 */ 325 private void checkTaglet(Object taglet) { 326 if (taglet instanceof Taglet) { 327 checkTagName(((Taglet) taglet).getName()); 328 } else if (taglet instanceof jdk.javadoc.doclet.Taglet) { 329 jdk.javadoc.doclet.Taglet legacyTaglet = (jdk.javadoc.doclet.Taglet) taglet; 330 customTags.remove(legacyTaglet.getName()); 331 customTags.put(legacyTaglet.getName(), new UserTaglet(legacyTaglet)); 332 checkTagName(legacyTaglet.getName()); 333 } else { 334 throw new IllegalArgumentException("Given object is not a taglet."); 335 } 336 } 337 338 /** 339 * Given a name of a seen custom tag, remove it from the set of unseen 340 * custom tags. 341 * @param name the name of the seen custom tag. 342 */ 343 public void seenCustomTag(String name) { 344 unseenCustomTags.remove(name); 345 } 346 347 /** 348 * Given an array of <code>Tag</code>s, check for spelling mistakes. 349 * @param utils the utility class to use 350 * @param element the tags holder 351 * @param trees the trees containing the comments 352 * @param areInlineTags true if the array of tags are inline and false otherwise. 353 */ 354 public void checkTags(final Utils utils, Element element, 355 Iterable<? extends DocTree> trees, boolean areInlineTags) { 356 if (trees == null) { 357 return; 358 } 359 CommentHelper ch = utils.getCommentHelper(element); 360 for (DocTree tag : trees) { 361 String name = tag.getKind().tagName; 362 if (name == null) { 363 continue; 364 } 365 if (name.length() > 0 && name.charAt(0) == '@') { 366 name = name.substring(1, name.length()); 367 } 368 if (! (standardTags.contains(name) || customTags.containsKey(name))) { 369 if (standardTagsLowercase.contains(Utils.toLowerCase(name))) { 370 messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTagLowercase", ch.getTagName(tag)); 371 continue; 372 } else { 373 messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTag", ch.getTagName(tag)); 374 continue; 375 } 376 } 377 final Taglet taglet = customTags.get(name); 378 // Check and verify tag usage 379 if (taglet != null) { 380 if (areInlineTags && !taglet.isInlineTag()) { 381 printTagMisuseWarn(ch, taglet, tag, "inline"); 382 } 383 // nothing more to do 384 if (element == null) { 385 return; 386 } 387 new SimpleElementVisitor9<Void, Void>() { 388 @Override 389 public Void visitModule(ModuleElement e, Void p) { 390 if (!taglet.inModule()) { 391 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "module"); 392 } 393 return null; 394 } 395 396 @Override 397 public Void visitPackage(PackageElement e, Void p) { 398 if (!taglet.inPackage()) { 399 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "package"); 400 } 401 return null; 402 } 403 404 @Override 405 public Void visitType(TypeElement e, Void p) { 406 if (!taglet.inType()) { 407 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "class"); 408 } 409 return null; 410 } 411 412 @Override 413 public Void visitExecutable(ExecutableElement e, Void p) { 414 if (utils.isConstructor(e) && !taglet.inConstructor()) { 415 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "constructor"); 416 } else if (!taglet.inMethod()) { 417 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "method"); 418 } 419 return null; 420 } 421 422 @Override 423 public Void visitVariable(VariableElement e, Void p) { 424 if (utils.isField(e) && !taglet.inField()) { 425 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "field"); 426 } 427 return null; 428 } 429 430 @Override 431 public Void visitUnknown(Element e, Void p) { 432 if (utils.isOverviewElement(e) && !taglet.inOverview()) { 433 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "overview"); 434 } 435 return null; 436 } 437 438 @Override 439 protected Void defaultAction(Element e, Void p) { 440 return null; 441 } 442 }.visit(element); 443 } 444 } 445 } 446 447 /** 448 * Given the taglet, the tag and the type of documentation that the tag 449 * was found in, print a tag misuse warning. 450 * @param taglet the taglet representing the misused tag. 451 * @param tag the misused tag. 452 * @param holderType the type of documentation that the misused tag was found in. 453 */ 454 private void printTagMisuseWarn(CommentHelper ch, Taglet taglet, DocTree tag, String holderType) { 455 Set<String> locationsSet = new LinkedHashSet<>(); 456 if (taglet.inOverview()) { 457 locationsSet.add("overview"); 458 } 459 if (taglet.inModule()) { 460 locationsSet.add("module"); 461 } 462 if (taglet.inPackage()) { 463 locationsSet.add("package"); 464 } 465 if (taglet.inType()) { 466 locationsSet.add("class/interface"); 467 } 468 if (taglet.inConstructor()) { 469 locationsSet.add("constructor"); 470 } 471 if (taglet.inField()) { 472 locationsSet.add("field"); 473 } 474 if (taglet.inMethod()) { 475 locationsSet.add("method"); 476 } 477 if (taglet.isInlineTag()) { 478 locationsSet.add("inline text"); 479 } 480 String[] locations = locationsSet.toArray(new String[]{}); 481 if (locations == null || locations.length == 0) { 482 //This known tag is excluded. 483 return; 484 } 485 StringBuilder combined_locations = new StringBuilder(); 486 for (int i = 0; i < locations.length; i++) { 487 if (i > 0) { 488 combined_locations.append(", "); 489 } 490 combined_locations.append(locations[i]); 491 } 492 messages.warning(ch.getDocTreePath(tag), "doclet.tag_misuse", 493 "@" + taglet.getName(), holderType, combined_locations.toString()); 494 } 495 496 /** 497 * Return the array of <code>Taglet</code>s that can 498 * appear in modules. 499 * @return the array of <code>Taglet</code>s that can 500 * appear in modules. 501 */ 502 public List<Taglet> getModuleCustomTaglets() { 503 if (moduleTags == null) { 504 initCustomTaglets(); 505 } 506 return moduleTags; 507 } 508 509 /** 510 * Return the array of <code>Taglet</code>s that can 511 * appear in packages. 512 * @return the array of <code>Taglet</code>s that can 513 * appear in packages. 514 */ 515 public List<Taglet> getPackageCustomTaglets() { 516 if (packageTags == null) { 517 initCustomTaglets(); 518 } 519 return packageTags; 520 } 521 522 /** 523 * Return the array of <code>Taglet</code>s that can 524 * appear in classes or interfaces. 525 * @return the array of <code>Taglet</code>s that can 526 * appear in classes or interfaces. 527 */ 528 public List<Taglet> getTypeCustomTaglets() { 529 if (typeTags == null) { 530 initCustomTaglets(); 531 } 532 return typeTags; 533 } 534 535 /** 536 * Return the array of inline <code>Taglet</code>s that can 537 * appear in comments. 538 * @return the array of <code>Taglet</code>s that can 539 * appear in comments. 540 */ 541 public List<Taglet> getInlineCustomTaglets() { 542 if (inlineTags == null) { 543 initCustomTaglets(); 544 } 545 return inlineTags; 546 } 547 548 /** 549 * Return the array of <code>Taglet</code>s that can 550 * appear in fields. 551 * @return the array of <code>Taglet</code>s that can 552 * appear in field. 553 */ 554 public List<Taglet> getFieldCustomTaglets() { 555 if (fieldTags == null) { 556 initCustomTaglets(); 557 } 558 return fieldTags; 559 } 560 561 /** 562 * Return the array of <code>Taglet</code>s that can 563 * appear in the serialized form. 564 * @return the array of <code>Taglet</code>s that can 565 * appear in the serialized form. 566 */ 567 public List<Taglet> getSerializedFormTaglets() { 568 if (serializedFormTags == null) { 569 initCustomTaglets(); 570 } 571 return serializedFormTags; 572 } 573 574 /** 575 * Returns the custom tags for a given element. 576 * 577 * @param e the element to get custom tags for 578 * @return the array of <code>Taglet</code>s that can 579 * appear in the given element. 580 */ 581 public List<Taglet> getCustomTaglets(Element e) { 582 switch (e.getKind()) { 583 case CONSTRUCTOR: 584 return getConstructorCustomTaglets(); 585 case METHOD: 586 return getMethodCustomTaglets(); 587 case ENUM_CONSTANT: 588 case FIELD: 589 return getFieldCustomTaglets(); 590 case ANNOTATION_TYPE: 591 case INTERFACE: 592 case CLASS: 593 case ENUM: 594 return getTypeCustomTaglets(); 595 case MODULE: 596 return getModuleCustomTaglets(); 597 case PACKAGE: 598 return getPackageCustomTaglets(); 599 case OTHER: 600 return getOverviewCustomTaglets(); 601 default: 602 throw new AssertionError("unknown element: " + e + " ,kind: " + e.getKind()); 603 } 604 } 605 606 /** 607 * Return a List of <code>Taglet</code>s that can 608 * appear in constructors. 609 * @return the array of <code>Taglet</code>s that can 610 * appear in constructors. 611 */ 612 public List<Taglet> getConstructorCustomTaglets() { 613 if (constructorTags == null) { 614 initCustomTaglets(); 615 } 616 return constructorTags; 617 } 618 619 /** 620 * Return a List of <code>Taglet</code>s that can 621 * appear in methods. 622 * @return the array of <code>Taglet</code>s that can 623 * appear in methods. 624 */ 625 public List<Taglet> getMethodCustomTaglets() { 626 if (methodTags == null) { 627 initCustomTaglets(); 628 } 629 return methodTags; 630 } 631 632 /** 633 * Return a List of <code>Taglet</code>s that can 634 * appear in an overview. 635 * @return the array of <code>Taglet</code>s that can 636 * appear in overview. 637 */ 638 public List<Taglet> getOverviewCustomTaglets() { 639 if (overviewTags == null) { 640 initCustomTaglets(); 641 } 642 return overviewTags; 643 } 644 645 /** 646 * Initialize the custom tag Lists. 647 */ 648 private void initCustomTaglets() { 649 650 moduleTags = new ArrayList<>(); 651 packageTags = new ArrayList<>(); 652 typeTags = new ArrayList<>(); 653 fieldTags = new ArrayList<>(); 654 constructorTags = new ArrayList<>(); 655 methodTags = new ArrayList<>(); 656 inlineTags = new ArrayList<>(); 657 overviewTags = new ArrayList<>(); 658 659 for (Taglet current : customTags.values()) { 660 if (current.inModule() && !current.isInlineTag()) { 661 moduleTags.add(current); 662 } 663 if (current.inPackage() && !current.isInlineTag()) { 664 packageTags.add(current); 665 } 666 if (current.inType() && !current.isInlineTag()) { 667 typeTags.add(current); 668 } 669 if (current.inField() && !current.isInlineTag()) { 670 fieldTags.add(current); 671 } 672 if (current.inConstructor() && !current.isInlineTag()) { 673 constructorTags.add(current); 674 } 675 if (current.inMethod() && !current.isInlineTag()) { 676 methodTags.add(current); 677 } 678 if (current.isInlineTag()) { 679 inlineTags.add(current); 680 } 681 if (current.inOverview() && !current.isInlineTag()) { 682 overviewTags.add(current); 683 } 684 } 685 686 //Init the serialized form tags 687 serializedFormTags = new ArrayList<>(); 688 serializedFormTags.add(customTags.get(SERIAL_DATA.tagName)); 689 serializedFormTags.add(customTags.get(THROWS.tagName)); 690 if (!nosince) 691 serializedFormTags.add(customTags.get(SINCE.tagName)); 692 serializedFormTags.add(customTags.get(SEE.tagName)); 693 } 694 695 /** 696 * Initialize standard Javadoc tags for ordering purposes. 697 */ 698 private void initStandardTaglets() { 699 if (javafx) { 700 initJavaFXTaglets(); 701 } 702 703 Taglet temp; 704 addStandardTaglet(new ParamTaglet()); 705 addStandardTaglet(new ReturnTaglet()); 706 addStandardTaglet(new ThrowsTaglet()); 707 addStandardTaglet(new SimpleTaglet(EXCEPTION.tagName, null, 708 SimpleTaglet.METHOD + SimpleTaglet.CONSTRUCTOR)); 709 addStandardTaglet(!nosince, new SimpleTaglet(SINCE.tagName, resources.getText("doclet.Since"), 710 SimpleTaglet.ALL)); 711 addStandardTaglet(showversion, new SimpleTaglet(VERSION.tagName, resources.getText("doclet.Version"), 712 SimpleTaglet.MODULE + SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW)); 713 addStandardTaglet(showauthor, new SimpleTaglet(AUTHOR.tagName, resources.getText("doclet.Author"), 714 SimpleTaglet.MODULE + SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW)); 715 addStandardTaglet(new SimpleTaglet(SERIAL_DATA.tagName, resources.getText("doclet.SerialData"), 716 SimpleTaglet.EXCLUDED)); 717 addStandardTaglet(new SimpleTaglet(HIDDEN.tagName, resources.getText("doclet.Hidden"), 718 SimpleTaglet.FIELD + SimpleTaglet.METHOD + SimpleTaglet.TYPE)); 719 customTags.put((temp = new SimpleTaglet("factory", resources.getText("doclet.Factory"), 720 SimpleTaglet.METHOD)).getName(), temp); 721 addStandardTaglet(new SeeTaglet()); 722 //Standard inline tags 723 addStandardTaglet(new DocRootTaglet()); 724 addStandardTaglet(new InheritDocTaglet()); 725 addStandardTaglet(new ValueTaglet()); 726 addStandardTaglet(new LiteralTaglet()); 727 addStandardTaglet(new CodeTaglet()); 728 addStandardTaglet(new IndexTaglet()); 729 addStandardTaglet(new SummaryTaglet()); 730 731 // Keep track of the names of standard tags for error 732 // checking purposes. The following are not handled above. 733 standardTags.add(DEPRECATED.tagName); 734 standardTags.add(LINK.tagName); 735 standardTags.add(LINK_PLAIN.tagName); 736 standardTags.add(SERIAL.tagName); 737 standardTags.add(SERIAL_FIELD.tagName); 738 } 739 740 /** 741 * Initialize JavaFX-related tags. 742 */ 743 private void initJavaFXTaglets() { 744 addStandardTaglet(new PropertyGetterTaglet()); 745 addStandardTaglet(new PropertySetterTaglet()); 746 addStandardTaglet(new SimpleTaglet("propertyDescription", 747 resources.getText("doclet.PropertyDescription"), 748 SimpleTaglet.FIELD + SimpleTaglet.METHOD)); 749 addStandardTaglet(new SimpleTaglet("defaultValue", resources.getText("doclet.DefaultValue"), 750 SimpleTaglet.FIELD + SimpleTaglet.METHOD)); 751 addStandardTaglet(new SimpleTaglet("treatAsPrivate", null, 752 SimpleTaglet.FIELD + SimpleTaglet.METHOD + SimpleTaglet.TYPE)); 753 } 754 755 void addStandardTaglet(Taglet taglet) { 756 String name = taglet.getName(); 757 customTags.put(name, taglet); 758 standardTags.add(name); 759 } 760 761 void addStandardTaglet(boolean enable, Taglet taglet) { 762 String name = taglet.getName(); 763 if (enable) 764 customTags.put(name, taglet); 765 standardTags.add(name); 766 } 767 768 /** 769 * Initialize lowercase version of standard Javadoc tags. 770 */ 771 private void initStandardTagsLowercase() { 772 for (String standardTag : standardTags) { 773 standardTagsLowercase.add(Utils.toLowerCase(standardTag)); 774 } 775 } 776 777 public boolean isKnownCustomTag(String tagName) { 778 return customTags.containsKey(tagName); 779 } 780 781 /** 782 * Print a list of {@link Taglet}s that might conflict with 783 * standard tags in the future and a list of standard tags 784 * that have been overriden. 785 */ 786 public void printReport() { 787 printReportHelper("doclet.Notice_taglet_conflict_warn", potentiallyConflictingTags); 788 printReportHelper("doclet.Notice_taglet_overriden", overridenStandardTags); 789 printReportHelper("doclet.Notice_taglet_unseen", unseenCustomTags); 790 } 791 792 private void printReportHelper(String noticeKey, Set<String> names) { 793 if (names.size() > 0) { 794 String[] namesArray = names.toArray(new String[] {}); 795 String result = " "; 796 for (int i = 0; i < namesArray.length; i++) { 797 result += "@" + namesArray[i]; 798 if (i + 1 < namesArray.length) { 799 result += ", "; 800 } 801 } 802 messages.notice(noticeKey, result); 803 } 804 } 805 806 /** 807 * Given the name of a tag, return the corresponding taglet. 808 * Return null if the tag is unknown. 809 * 810 * @param name the name of the taglet to retrieve. 811 * @return return the corresponding taglet. Return null if the tag is 812 * unknown. 813 */ 814 public Taglet getTaglet(String name) { 815 if (name.indexOf("@") == 0) { 816 return customTags.get(name.substring(1)); 817 } else { 818 return customTags.get(name); 819 } 820 821 } 822} 823