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