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