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 @SuppressWarnings("deprecation") 256 Object instance = customTagClass.newInstance(); 257 Taglet newLegacy = new UserTaglet((jdk.javadoc.doclet.taglet.Taglet)instance); 258 String tname = newLegacy.getName(); 259 Taglet t = customTags.get(tname); 260 if (t != null) { 261 customTags.remove(tname); 262 } 263 customTags.put(tname, newLegacy); 264 message.notice("doclet.Notice_taglet_registered", classname); 265 } catch (Exception exc) { 266 message.error("doclet.Error_taglet_not_registered", exc.getClass().getName(), classname); 267 } 268 } 269 270 /** 271 * Add a new <code>SimpleTaglet</code>. If this tag already exists 272 * and the header passed as an argument is null, move tag to the back of the 273 * list. If this tag already exists and the header passed as an argument is 274 * not null, overwrite previous tag with new one. Otherwise, add new 275 * SimpleTaglet to list. 276 * @param tagName the name of this tag 277 * @param header the header to output. 278 * @param locations the possible locations that this tag 279 * can appear in. 280 */ 281 public void addNewSimpleCustomTag(String tagName, String header, String locations) { 282 if (tagName == null || locations == null) { 283 return; 284 } 285 Taglet tag = customTags.get(tagName); 286 locations = Utils.toLowerCase(locations); 287 if (tag == null || header != null) { 288 customTags.remove(tagName); 289 customTags.put(tagName, new SimpleTaglet(tagName, header, locations)); 290 if (locations != null && locations.indexOf('x') == -1) { 291 checkTagName(tagName); 292 } 293 } else { 294 //Move to back 295 customTags.remove(tagName); 296 customTags.put(tagName, tag); 297 } 298 } 299 300 /** 301 * Given a tag name, add it to the set of tags it belongs to. 302 */ 303 private void checkTagName(String name) { 304 if (standardTags.contains(name)) { 305 overridenStandardTags.add(name); 306 } else { 307 if (name.indexOf('.') == -1) { 308 potentiallyConflictingTags.add(name); 309 } 310 unseenCustomTags.add(name); 311 } 312 } 313 314 /** 315 * Check the taglet to see if it is a legacy taglet. Also 316 * check its name for errors. 317 */ 318 private void checkTaglet(Object taglet) { 319 if (taglet instanceof Taglet) { 320 checkTagName(((Taglet) taglet).getName()); 321 } else if (taglet instanceof jdk.javadoc.doclet.taglet.Taglet) { 322 jdk.javadoc.doclet.taglet.Taglet legacyTaglet = (jdk.javadoc.doclet.taglet.Taglet) taglet; 323 customTags.remove(legacyTaglet.getName()); 324 customTags.put(legacyTaglet.getName(), new UserTaglet(legacyTaglet)); 325 checkTagName(legacyTaglet.getName()); 326 } else { 327 throw new IllegalArgumentException("Given object is not a taglet."); 328 } 329 } 330 331 /** 332 * Given a name of a seen custom tag, remove it from the set of unseen 333 * custom tags. 334 * @param name the name of the seen custom tag. 335 */ 336 public void seenCustomTag(String name) { 337 unseenCustomTags.remove(name); 338 } 339 340 /** 341 * Given an array of <code>Tag</code>s, check for spelling mistakes. 342 * @param utils the utility class to use 343 * @param element the tags holder 344 * @param trees the trees containing the comments 345 * @param areInlineTags true if the array of tags are inline and false otherwise. 346 */ 347 public void checkTags(final Utils utils, Element element, 348 Iterable<? extends DocTree> trees, boolean areInlineTags) { 349 if (trees == null) { 350 return; 351 } 352 CommentHelper ch = utils.getCommentHelper(element); 353 for (DocTree tag : trees) { 354 String name = tag.getKind().tagName; 355 if (name == null) { 356 continue; 357 } 358 if (name.length() > 0 && name.charAt(0) == '@') { 359 name = name.substring(1, name.length()); 360 } 361 if (! (standardTags.contains(name) || customTags.containsKey(name))) { 362 if (standardTagsLowercase.contains(Utils.toLowerCase(name))) { 363 message.warning(ch.getDocTreePath(tag), "doclet.UnknownTagLowercase", ch.getTagName(tag)); 364 continue; 365 } else { 366 message.warning(ch.getDocTreePath(tag), "doclet.UnknownTag", ch.getTagName(tag)); 367 continue; 368 } 369 } 370 final Taglet taglet = customTags.get(name); 371 // Check and verify tag usage 372 if (taglet != null) { 373 if (areInlineTags && !taglet.isInlineTag()) { 374 printTagMisuseWarn(ch, taglet, tag, "inline"); 375 } 376 // nothing more to do 377 if (element == null) { 378 return; 379 } 380 new SimpleElementVisitor9<Void, Void>() { 381 @Override @DefinedBy(Api.LANGUAGE_MODEL) 382 public Void visitModule(ModuleElement e, Void p) { 383 if (!taglet.inModule()) { 384 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "module"); 385 } 386 return null; 387 } 388 389 @Override @DefinedBy(Api.LANGUAGE_MODEL) 390 public Void visitPackage(PackageElement e, Void p) { 391 if (!taglet.inPackage()) { 392 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "package"); 393 } 394 return null; 395 } 396 397 @Override @DefinedBy(Api.LANGUAGE_MODEL) 398 public Void visitType(TypeElement e, Void p) { 399 if (!taglet.inType()) { 400 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "class"); 401 } 402 return null; 403 } 404 405 @Override @DefinedBy(Api.LANGUAGE_MODEL) 406 public Void visitExecutable(ExecutableElement e, Void p) { 407 if (utils.isConstructor(e) && !taglet.inConstructor()) { 408 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "constructor"); 409 } else if (!taglet.inMethod()) { 410 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "method"); 411 } 412 return null; 413 } 414 415 @Override @DefinedBy(Api.LANGUAGE_MODEL) 416 public Void visitVariable(VariableElement e, Void p) { 417 if (utils.isField(e) && !taglet.inField()) { 418 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "field"); 419 } 420 return null; 421 } 422 423 @Override @DefinedBy(Api.LANGUAGE_MODEL) 424 public Void visitUnknown(Element e, Void p) { 425 if (utils.isOverviewElement(e) && !taglet.inOverview()) { 426 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "overview"); 427 } 428 return null; 429 } 430 431 @Override @DefinedBy(Api.LANGUAGE_MODEL) 432 protected Void defaultAction(Element e, Void p) { 433 return null; 434 } 435 }.visit(element); 436 } 437 } 438 } 439 440 /** 441 * Given the taglet, the tag and the type of documentation that the tag 442 * was found in, print a tag misuse warning. 443 * @param taglet the taglet representing the misused tag. 444 * @param tag the misused tag. 445 * @param holderType the type of documentation that the misused tag was found in. 446 */ 447 private void printTagMisuseWarn(CommentHelper ch, Taglet taglet, DocTree tag, String holderType) { 448 Set<String> locationsSet = new LinkedHashSet<>(); 449 if (taglet.inOverview()) { 450 locationsSet.add("overview"); 451 } 452 if (taglet.inModule()) { 453 locationsSet.add("module"); 454 } 455 if (taglet.inPackage()) { 456 locationsSet.add("package"); 457 } 458 if (taglet.inType()) { 459 locationsSet.add("class/interface"); 460 } 461 if (taglet.inConstructor()) { 462 locationsSet.add("constructor"); 463 } 464 if (taglet.inField()) { 465 locationsSet.add("field"); 466 } 467 if (taglet.inMethod()) { 468 locationsSet.add("method"); 469 } 470 if (taglet.isInlineTag()) { 471 locationsSet.add("inline text"); 472 } 473 String[] locations = locationsSet.toArray(new String[]{}); 474 if (locations == null || locations.length == 0) { 475 //This known tag is excluded. 476 return; 477 } 478 StringBuilder combined_locations = new StringBuilder(); 479 for (int i = 0; i < locations.length; i++) { 480 if (i > 0) { 481 combined_locations.append(", "); 482 } 483 combined_locations.append(locations[i]); 484 } 485 message.warning(ch.getDocTreePath(tag), "doclet.tag_misuse", 486 "@" + taglet.getName(), holderType, combined_locations.toString()); 487 } 488 489 /** 490 * Return the array of <code>Taglet</code>s that can 491 * appear in modules. 492 * @return the array of <code>Taglet</code>s that can 493 * appear in modules. 494 */ 495 public List<Taglet> getModuleCustomTaglets() { 496 if (moduleTags == null) { 497 initCustomTaglets(); 498 } 499 return moduleTags; 500 } 501 502 /** 503 * Return the array of <code>Taglet</code>s that can 504 * appear in packages. 505 * @return the array of <code>Taglet</code>s that can 506 * appear in packages. 507 */ 508 public List<Taglet> getPackageCustomTaglets() { 509 if (packageTags == null) { 510 initCustomTaglets(); 511 } 512 return packageTags; 513 } 514 515 /** 516 * Return the array of <code>Taglet</code>s that can 517 * appear in classes or interfaces. 518 * @return the array of <code>Taglet</code>s that can 519 * appear in classes or interfaces. 520 */ 521 public List<Taglet> getTypeCustomTaglets() { 522 if (typeTags == null) { 523 initCustomTaglets(); 524 } 525 return typeTags; 526 } 527 528 /** 529 * Return the array of inline <code>Taglet</code>s that can 530 * appear in comments. 531 * @return the array of <code>Taglet</code>s that can 532 * appear in comments. 533 */ 534 public List<Taglet> getInlineCustomTaglets() { 535 if (inlineTags == null) { 536 initCustomTaglets(); 537 } 538 return inlineTags; 539 } 540 541 /** 542 * Return the array of <code>Taglet</code>s that can 543 * appear in fields. 544 * @return the array of <code>Taglet</code>s that can 545 * appear in field. 546 */ 547 public List<Taglet> getFieldCustomTaglets() { 548 if (fieldTags == null) { 549 initCustomTaglets(); 550 } 551 return fieldTags; 552 } 553 554 /** 555 * Return the array of <code>Taglet</code>s that can 556 * appear in the serialized form. 557 * @return the array of <code>Taglet</code>s that can 558 * appear in the serialized form. 559 */ 560 public List<Taglet> getSerializedFormTaglets() { 561 if (serializedFormTags == null) { 562 initCustomTaglets(); 563 } 564 return serializedFormTags; 565 } 566 567 /** 568 * Returns the custom tags for a given element. 569 * 570 * @param e the element to get custom tags for 571 * @return the array of <code>Taglet</code>s that can 572 * appear in the given element. 573 */ 574 public List<Taglet> getCustomTaglets(Element e) { 575 switch (e.getKind()) { 576 case CONSTRUCTOR: 577 return getConstructorCustomTaglets(); 578 case METHOD: 579 return getMethodCustomTaglets(); 580 case ENUM_CONSTANT: 581 case FIELD: 582 return getFieldCustomTaglets(); 583 case ANNOTATION_TYPE: 584 case INTERFACE: 585 case CLASS: 586 case ENUM: 587 return getTypeCustomTaglets(); 588 case MODULE: 589 return getModuleCustomTaglets(); 590 case PACKAGE: 591 return getPackageCustomTaglets(); 592 case OTHER: 593 return getOverviewCustomTaglets(); 594 default: 595 throw new AssertionError("unknown element: " + e + " ,kind: " + e.getKind()); 596 } 597 } 598 599 /** 600 * Return a List of <code>Taglet</code>s that can 601 * appear in constructors. 602 * @return the array of <code>Taglet</code>s that can 603 * appear in constructors. 604 */ 605 public List<Taglet> getConstructorCustomTaglets() { 606 if (constructorTags == null) { 607 initCustomTaglets(); 608 } 609 return constructorTags; 610 } 611 612 /** 613 * Return a List of <code>Taglet</code>s that can 614 * appear in methods. 615 * @return the array of <code>Taglet</code>s that can 616 * appear in methods. 617 */ 618 public List<Taglet> getMethodCustomTaglets() { 619 if (methodTags == null) { 620 initCustomTaglets(); 621 } 622 return methodTags; 623 } 624 625 /** 626 * Return a List of <code>Taglet</code>s that can 627 * appear in an overview. 628 * @return the array of <code>Taglet</code>s that can 629 * appear in overview. 630 */ 631 public List<Taglet> getOverviewCustomTaglets() { 632 if (overviewTags == null) { 633 initCustomTaglets(); 634 } 635 return overviewTags; 636 } 637 638 /** 639 * Initialize the custom tag Lists. 640 */ 641 private void initCustomTaglets() { 642 643 moduleTags = new ArrayList<>(); 644 packageTags = new ArrayList<>(); 645 typeTags = new ArrayList<>(); 646 fieldTags = new ArrayList<>(); 647 constructorTags = new ArrayList<>(); 648 methodTags = new ArrayList<>(); 649 inlineTags = new ArrayList<>(); 650 overviewTags = new ArrayList<>(); 651 652 for (Taglet current : customTags.values()) { 653 if (current.inModule() && !current.isInlineTag()) { 654 moduleTags.add(current); 655 } 656 if (current.inPackage() && !current.isInlineTag()) { 657 packageTags.add(current); 658 } 659 if (current.inType() && !current.isInlineTag()) { 660 typeTags.add(current); 661 } 662 if (current.inField() && !current.isInlineTag()) { 663 fieldTags.add(current); 664 } 665 if (current.inConstructor() && !current.isInlineTag()) { 666 constructorTags.add(current); 667 } 668 if (current.inMethod() && !current.isInlineTag()) { 669 methodTags.add(current); 670 } 671 if (current.isInlineTag()) { 672 inlineTags.add(current); 673 } 674 if (current.inOverview() && !current.isInlineTag()) { 675 overviewTags.add(current); 676 } 677 } 678 679 //Init the serialized form tags 680 serializedFormTags = new ArrayList<>(); 681 serializedFormTags.add(customTags.get(SERIAL_DATA.tagName)); 682 serializedFormTags.add(customTags.get(THROWS.tagName)); 683 if (!nosince) 684 serializedFormTags.add(customTags.get(SINCE.tagName)); 685 serializedFormTags.add(customTags.get(SEE.tagName)); 686 } 687 688 /** 689 * Initialize standard Javadoc tags for ordering purposes. 690 */ 691 private void initStandardTaglets() { 692 if (javafx) { 693 initJavaFXTaglets(); 694 } 695 696 Taglet temp; 697 addStandardTaglet(new ParamTaglet()); 698 addStandardTaglet(new ReturnTaglet()); 699 addStandardTaglet(new ThrowsTaglet()); 700 addStandardTaglet(new SimpleTaglet(EXCEPTION.tagName, null, 701 SimpleTaglet.METHOD + SimpleTaglet.CONSTRUCTOR)); 702 addStandardTaglet(!nosince, new SimpleTaglet(SINCE.tagName, message.getText("doclet.Since"), 703 SimpleTaglet.ALL)); 704 addStandardTaglet(showversion, new SimpleTaglet(VERSION.tagName, message.getText("doclet.Version"), 705 SimpleTaglet.MODULE + SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW)); 706 addStandardTaglet(showauthor, new SimpleTaglet(AUTHOR.tagName, message.getText("doclet.Author"), 707 SimpleTaglet.MODULE + SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW)); 708 addStandardTaglet(new SimpleTaglet(SERIAL_DATA.tagName, message.getText("doclet.SerialData"), 709 SimpleTaglet.EXCLUDED)); 710 addStandardTaglet(new SimpleTaglet(HIDDEN.tagName, message.getText("doclet.Hidden"), 711 SimpleTaglet.FIELD + SimpleTaglet.METHOD + SimpleTaglet.TYPE)); 712 customTags.put((temp = new SimpleTaglet("factory", message.getText("doclet.Factory"), 713 SimpleTaglet.METHOD)).getName(), temp); 714 addStandardTaglet(new SeeTaglet()); 715 //Standard inline tags 716 addStandardTaglet(new DocRootTaglet()); 717 addStandardTaglet(new InheritDocTaglet()); 718 addStandardTaglet(new ValueTaglet()); 719 addStandardTaglet(new LiteralTaglet()); 720 addStandardTaglet(new CodeTaglet()); 721 addStandardTaglet(new IndexTaglet()); 722 723 // Keep track of the names of standard tags for error 724 // checking purposes. The following are not handled above. 725 standardTags.add(DEPRECATED.tagName); 726 standardTags.add(LINK.tagName); 727 standardTags.add(LINK_PLAIN.tagName); 728 standardTags.add(SERIAL.tagName); 729 standardTags.add(SERIAL_FIELD.tagName); 730 } 731 732 /** 733 * Initialize JavaFX-related tags. 734 */ 735 private void initJavaFXTaglets() { 736 addStandardTaglet(new PropertyGetterTaglet()); 737 addStandardTaglet(new PropertySetterTaglet()); 738 addStandardTaglet(new SimpleTaglet("propertyDescription", 739 message.getText("doclet.PropertyDescription"), 740 SimpleTaglet.FIELD + SimpleTaglet.METHOD)); 741 addStandardTaglet(new SimpleTaglet("defaultValue", message.getText("doclet.DefaultValue"), 742 SimpleTaglet.FIELD + SimpleTaglet.METHOD)); 743 addStandardTaglet(new SimpleTaglet("treatAsPrivate", null, 744 SimpleTaglet.FIELD + SimpleTaglet.METHOD + SimpleTaglet.TYPE)); 745 } 746 747 void addStandardTaglet(Taglet taglet) { 748 String name = taglet.getName(); 749 customTags.put(name, taglet); 750 standardTags.add(name); 751 } 752 753 void addStandardTaglet(boolean enable, Taglet taglet) { 754 String name = taglet.getName(); 755 if (enable) 756 customTags.put(name, taglet); 757 standardTags.add(name); 758 } 759 760 /** 761 * Initialize lowercase version of standard Javadoc tags. 762 */ 763 private void initStandardTagsLowercase() { 764 for (String standardTag : standardTags) { 765 standardTagsLowercase.add(Utils.toLowerCase(standardTag)); 766 } 767 } 768 769 public boolean isKnownCustomTag(String tagName) { 770 return customTags.containsKey(tagName); 771 } 772 773 /** 774 * Print a list of {@link Taglet}s that might conflict with 775 * standard tags in the future and a list of standard tags 776 * that have been overriden. 777 */ 778 public void printReport() { 779 printReportHelper("doclet.Notice_taglet_conflict_warn", potentiallyConflictingTags); 780 printReportHelper("doclet.Notice_taglet_overriden", overridenStandardTags); 781 printReportHelper("doclet.Notice_taglet_unseen", unseenCustomTags); 782 } 783 784 private void printReportHelper(String noticeKey, Set<String> names) { 785 if (names.size() > 0) { 786 String[] namesArray = names.toArray(new String[] {}); 787 String result = " "; 788 for (int i = 0; i < namesArray.length; i++) { 789 result += "@" + namesArray[i]; 790 if (i + 1 < namesArray.length) { 791 result += ", "; 792 } 793 } 794 message.notice(noticeKey, result); 795 } 796 } 797 798 /** 799 * Given the name of a tag, return the corresponding taglet. 800 * Return null if the tag is unknown. 801 * 802 * @param name the name of the taglet to retrieve. 803 * @return return the corresponding taglet. Return null if the tag is 804 * unknown. 805 */ 806 public Taglet getTaglet(String name) { 807 if (name.indexOf("@") == 0) { 808 return customTags.get(name.substring(1)); 809 } else { 810 return customTags.get(name); 811 } 812 813 } 814 }