1 /* 2 * Copyright (c) 1997, 2020, 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; 27 28 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.util.ArrayList; 32 import java.util.Collections; 33 import java.util.HashMap; 34 import java.util.HashSet; 35 import java.util.LinkedHashSet; 36 import java.util.List; 37 import java.util.Locale; 38 import java.util.Map; 39 import java.util.Set; 40 import java.util.SortedMap; 41 import java.util.SortedSet; 42 import java.util.TreeMap; 43 import java.util.TreeSet; 44 import java.util.function.Function; 45 46 import javax.lang.model.SourceVersion; 47 import javax.lang.model.element.Element; 48 import javax.lang.model.element.ModuleElement; 49 import javax.lang.model.element.PackageElement; 50 import javax.lang.model.element.TypeElement; 51 import javax.lang.model.util.Elements; 52 import javax.lang.model.util.SimpleElementVisitor14; 53 import javax.tools.JavaFileManager; 54 import javax.tools.JavaFileObject; 55 56 import com.sun.source.tree.CompilationUnitTree; 57 import com.sun.source.util.DocTreePath; 58 import com.sun.source.util.TreePath; 59 import com.sun.tools.javac.util.DefinedBy; 60 import com.sun.tools.javac.util.DefinedBy.Api; 61 import jdk.javadoc.doclet.Doclet; 62 import jdk.javadoc.doclet.DocletEnvironment; 63 import jdk.javadoc.doclet.Reporter; 64 import jdk.javadoc.doclet.StandardDoclet; 65 import jdk.javadoc.doclet.Taglet; 66 import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory; 67 import jdk.javadoc.internal.doclets.toolkit.taglets.TagletManager; 68 import jdk.javadoc.internal.doclets.toolkit.util.Comparators; 69 import jdk.javadoc.internal.doclets.toolkit.util.DocFile; 70 import jdk.javadoc.internal.doclets.toolkit.util.DocFileFactory; 71 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; 72 import jdk.javadoc.internal.doclets.toolkit.util.Extern; 73 import jdk.javadoc.internal.doclets.toolkit.util.Group; 74 import jdk.javadoc.internal.doclets.toolkit.util.MetaKeywords; 75 import jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException; 76 import jdk.javadoc.internal.doclets.toolkit.util.TypeElementCatalog; 77 import jdk.javadoc.internal.doclets.toolkit.util.Utils; 78 import jdk.javadoc.internal.doclets.toolkit.util.Utils.Pair; 79 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberCache; 80 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; 81 import jdk.javadoc.internal.doclint.DocLint; 82 83 /** 84 * Configure the output based on the options. Doclets should sub-class 85 * BaseConfiguration, to configure and add their own options. This class contains 86 * all user options which are supported by the standard doclet. 87 * 88 * <p><b>This is NOT part of any supported API. 89 * If you write code that depends on this, you do so at your own risk. 90 * This code and its internal interfaces are subject to change or 91 * deletion without notice.</b> 92 */ 93 public abstract class BaseConfiguration { 94 /** 95 * The doclet that created this configuration. 96 */ 97 public final Doclet doclet; 98 99 /** 100 * The factory for builders. 101 */ 102 protected BuilderFactory builderFactory; 103 104 /** 105 * The taglet manager. 106 */ 107 public TagletManager tagletManager; 108 109 /** 110 * The meta tag keywords instance. 111 */ 112 public MetaKeywords metakeywords; 113 114 /** 115 * The doclet environment. 116 */ 117 public DocletEnvironment docEnv; 118 119 /** 120 * An utility class for commonly used helpers 121 */ 122 public Utils utils; 123 124 /** 125 * All the temporary accessors to javac internals. 126 */ 127 public WorkArounds workArounds; 128 129 /** 130 * Sourcepath from where to read the source files. Default is classpath. 131 */ 132 public String sourcepath = ""; 133 134 /** 135 * Generate modules documentation if more than one module is present. 136 */ 137 public boolean showModules = false; 138 139 /** 140 * The catalog of classes specified on the command-line 141 */ 142 public TypeElementCatalog typeElementCatalog; 143 144 /** 145 * The package grouping instance. 146 */ 147 public final Group group = new Group(this); 148 149 /** 150 * The tracker of external package links. 151 */ 152 public Extern extern; 153 154 public final Reporter reporter; 155 156 public final Locale locale; 157 getMessages()158 public abstract Messages getMessages(); 159 getDocResources()160 public abstract Resources getDocResources(); 161 162 /** 163 * Returns the version of the {@link #doclet doclet}. 164 * 165 * @return the version 166 */ getDocletVersion()167 public abstract Runtime.Version getDocletVersion(); 168 169 /** 170 * This method should be defined in all those doclets (configurations), 171 * which want to derive themselves from this BaseConfiguration. This method 172 * can be used to finish up the options setup. 173 * 174 * @return true if successful and false otherwise 175 */ 176 finishOptionSettings()177 public abstract boolean finishOptionSettings(); 178 179 public CommentUtils cmtUtils; 180 181 /** 182 * A sorted set of included packages. 183 */ 184 public SortedSet<PackageElement> packages = null; 185 186 public OverviewElement overviewElement; 187 188 public DocFileFactory docFileFactory; 189 190 /** 191 * A sorted map, giving the (specified|included|other) packages for each module. 192 */ 193 public SortedMap<ModuleElement, Set<PackageElement>> modulePackages; 194 195 /** 196 * The list of known modules, that should be documented. 197 */ 198 public SortedSet<ModuleElement> modules; 199 200 protected static final String sharedResourceBundleName = 201 "jdk.javadoc.internal.doclets.toolkit.resources.doclets"; 202 203 VisibleMemberCache visibleMemberCache = null; 204 205 public PropertyUtils propertyUtils = null; 206 207 /** 208 * Constructs the format-independent configuration needed by the doclet. 209 * 210 * @apiNote The {@code doclet} parameter is used when 211 * {@link Taglet#init(DocletEnvironment, Doclet) initializing tags}. 212 * Some doclets (such as the {@link StandardDoclet}), may delegate to another 213 * (such as the {@code HtmlDoclet}). In such cases, the primary doclet (i.e 214 * {@code StandardDoclet}) should be provided here, and not any internal 215 * class like {@code HtmlDoclet}. 216 * 217 * @param doclet the doclet for this run of javadoc 218 * @param locale the locale for the generated documentation 219 * @param reporter the reporter to use for console messages 220 */ BaseConfiguration(Doclet doclet, Locale locale, Reporter reporter)221 public BaseConfiguration(Doclet doclet, Locale locale, Reporter reporter) { 222 this.doclet = doclet; 223 this.locale = locale; 224 this.reporter = reporter; 225 } 226 getOptions()227 public abstract BaseOptions getOptions(); 228 229 private boolean initialized = false; 230 initConfiguration(DocletEnvironment docEnv, Function<String, String> resourceKeyMapper)231 protected void initConfiguration(DocletEnvironment docEnv, 232 Function<String, String> resourceKeyMapper) { 233 if (initialized) { 234 throw new IllegalStateException("configuration previously initialized"); 235 } 236 initialized = true; 237 this.docEnv = docEnv; 238 // Utils needs docEnv, safe to init now. 239 utils = new Utils(this); 240 241 BaseOptions options = getOptions(); 242 if (!options.javafx()) { 243 options.setJavaFX(isJavaFXMode()); 244 } 245 246 getDocResources().setKeyMapper(resourceKeyMapper); 247 248 // Once docEnv and Utils have been initialized, others should be safe. 249 metakeywords = new MetaKeywords(this); 250 cmtUtils = new CommentUtils(this); 251 workArounds = new WorkArounds(this); 252 visibleMemberCache = new VisibleMemberCache(this); 253 propertyUtils = new PropertyUtils(this); 254 255 Splitter specifiedSplitter = new Splitter(docEnv, false); 256 specifiedModuleElements = Collections.unmodifiableSet(specifiedSplitter.mset); 257 specifiedPackageElements = Collections.unmodifiableSet(specifiedSplitter.pset); 258 specifiedTypeElements = Collections.unmodifiableSet(specifiedSplitter.tset); 259 260 Splitter includedSplitter = new Splitter(docEnv, true); 261 includedModuleElements = Collections.unmodifiableSet(includedSplitter.mset); 262 includedPackageElements = Collections.unmodifiableSet(includedSplitter.pset); 263 includedTypeElements = Collections.unmodifiableSet(includedSplitter.tset); 264 } 265 266 /** 267 * Return the builder factory for this doclet. 268 * 269 * @return the builder factory for this doclet. 270 */ getBuilderFactory()271 public BuilderFactory getBuilderFactory() { 272 if (builderFactory == null) { 273 builderFactory = new BuilderFactory(this); 274 } 275 return builderFactory; 276 } 277 getReporter()278 public Reporter getReporter() { 279 return this.reporter; 280 } 281 282 private Set<ModuleElement> specifiedModuleElements; 283 getSpecifiedModuleElements()284 public Set<ModuleElement> getSpecifiedModuleElements() { 285 return specifiedModuleElements; 286 } 287 288 private Set<PackageElement> specifiedPackageElements; 289 getSpecifiedPackageElements()290 public Set<PackageElement> getSpecifiedPackageElements() { 291 return specifiedPackageElements; 292 } 293 294 private Set<TypeElement> specifiedTypeElements; 295 getSpecifiedTypeElements()296 public Set<TypeElement> getSpecifiedTypeElements() { 297 return specifiedTypeElements; 298 } 299 300 private Set<ModuleElement> includedModuleElements; 301 getIncludedModuleElements()302 public Set<ModuleElement> getIncludedModuleElements() { 303 return includedModuleElements; 304 } 305 306 private Set<PackageElement> includedPackageElements; 307 getIncludedPackageElements()308 public Set<PackageElement> getIncludedPackageElements() { 309 return includedPackageElements; 310 } 311 312 private Set<TypeElement> includedTypeElements; 313 getIncludedTypeElements()314 public Set<TypeElement> getIncludedTypeElements() { 315 return includedTypeElements; 316 } 317 initModules()318 private void initModules() { 319 Comparators comparators = utils.comparators; 320 // Build the modules structure used by the doclet 321 modules = new TreeSet<>(comparators.makeModuleComparator()); 322 modules.addAll(getSpecifiedModuleElements()); 323 324 modulePackages = new TreeMap<>(comparators.makeModuleComparator()); 325 for (PackageElement p : packages) { 326 ModuleElement mdle = docEnv.getElementUtils().getModuleOf(p); 327 if (mdle != null && !mdle.isUnnamed()) { 328 Set<PackageElement> s = modulePackages 329 .computeIfAbsent(mdle, m -> new TreeSet<>(comparators.makePackageComparator())); 330 s.add(p); 331 } 332 } 333 334 for (PackageElement p : getIncludedPackageElements()) { 335 ModuleElement mdle = docEnv.getElementUtils().getModuleOf(p); 336 if (mdle != null && !mdle.isUnnamed()) { 337 Set<PackageElement> s = modulePackages 338 .computeIfAbsent(mdle, m -> new TreeSet<>(comparators.makePackageComparator())); 339 s.add(p); 340 } 341 } 342 343 // add entries for modules which may not have exported packages 344 modules.forEach(mdle -> modulePackages.computeIfAbsent(mdle, m -> Collections.emptySet())); 345 346 modules.addAll(modulePackages.keySet()); 347 showModules = !modules.isEmpty(); 348 for (Set<PackageElement> pkgs : modulePackages.values()) { 349 packages.addAll(pkgs); 350 } 351 } 352 initPackages()353 private void initPackages() { 354 packages = new TreeSet<>(utils.comparators.makePackageComparator()); 355 // add all the included packages 356 packages.addAll(includedPackageElements); 357 } 358 359 /* 360 * when this is called all the option have been set, this method, 361 * initializes certain components before anything else is started. 362 */ finishOptionSettings0()363 protected boolean finishOptionSettings0() throws DocletException { 364 BaseOptions options = getOptions(); 365 extern = new Extern(this); 366 initDestDirectory(); 367 for (String link : options.linkList()) { 368 extern.link(link, reporter); 369 } 370 for (Pair<String, String> linkOfflinePair : options.linkOfflineList()) { 371 extern.link(linkOfflinePair.first, linkOfflinePair.second, reporter); 372 } 373 if (!options.noPlatformLinks()) { 374 extern.checkPlatformLinks(options.linkPlatformProperties(), reporter); 375 } 376 typeElementCatalog = new TypeElementCatalog(includedTypeElements, this); 377 initTagletManager(options.customTagStrs()); 378 options.groupPairs().forEach(grp -> { 379 if (showModules) { 380 group.checkModuleGroups(grp.first, grp.second); 381 } else { 382 group.checkPackageGroups(grp.first, grp.second); 383 } 384 }); 385 386 PackageElement unnamedPackage; 387 Elements elementUtils = utils.elementUtils; 388 if (docEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_9) >= 0) { 389 ModuleElement unnamedModule = elementUtils.getModuleElement(""); 390 unnamedPackage = elementUtils.getPackageElement(unnamedModule, ""); 391 } else { 392 unnamedPackage = elementUtils.getPackageElement(""); 393 } 394 overviewElement = new OverviewElement(unnamedPackage, getOverviewPath()); 395 return true; 396 } 397 398 /** 399 * Set the command-line options supported by this configuration. 400 * 401 * @return true if the options are set successfully 402 * @throws DocletException if there is a problem while setting the options 403 */ setOptions()404 public boolean setOptions() throws DocletException { 405 initPackages(); 406 initModules(); 407 return finishOptionSettings0() 408 && finishOptionSettings(); 409 } 410 initDestDirectory()411 private void initDestDirectory() throws DocletException { 412 String destDirName = getOptions().destDirName(); 413 if (!destDirName.isEmpty()) { 414 Messages messages = getMessages(); 415 DocFile destDir = DocFile.createFileForDirectory(this, destDirName); 416 if (!destDir.exists()) { 417 //Create the output directory (in case it doesn't exist yet) 418 messages.notice("doclet.dest_dir_create", destDirName); 419 destDir.mkdirs(); 420 } else if (!destDir.isDirectory()) { 421 throw new SimpleDocletException(messages.getResources().getText( 422 "doclet.destination_directory_not_directory_0", 423 destDir.getPath())); 424 } else if (!destDir.canWrite()) { 425 throw new SimpleDocletException(messages.getResources().getText( 426 "doclet.destination_directory_not_writable_0", 427 destDir.getPath())); 428 } 429 } 430 DocFileFactory.getFactory(this).setDestDir(destDirName); 431 } 432 433 /** 434 * Initialize the taglet manager. The strings to initialize the simple custom tags should 435 * be in the following format: "[tag name]:[location str]:[heading]". 436 * 437 * @param customTagStrs the set two dimensional arrays of strings. These arrays contain 438 * either -tag or -taglet arguments. 439 */ initTagletManager(Set<List<String>> customTagStrs)440 private void initTagletManager(Set<List<String>> customTagStrs) { 441 tagletManager = tagletManager != null ? tagletManager : new TagletManager(this); 442 JavaFileManager fileManager = getFileManager(); 443 Messages messages = getMessages(); 444 try { 445 tagletManager.initTagletPath(fileManager); 446 tagletManager.loadTaglets(fileManager); 447 448 for (List<String> args : customTagStrs) { 449 if (args.get(0).equals("-taglet")) { 450 tagletManager.addCustomTag(args.get(1), fileManager); 451 continue; 452 } 453 List<String> tokens = tokenize(args.get(1), TagletManager.SIMPLE_TAGLET_OPT_SEPARATOR, 3); 454 switch (tokens.size()) { 455 case 1: 456 String tagName = args.get(1); 457 if (tagletManager.isKnownCustomTag(tagName)) { 458 //reorder a standard tag 459 tagletManager.addNewSimpleCustomTag(tagName, null, ""); 460 } else { 461 //Create a simple tag with the heading that has the same name as the tag. 462 StringBuilder heading = new StringBuilder(tagName + ":"); 463 heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0))); 464 tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a"); 465 } 466 break; 467 468 case 2: 469 //Add simple taglet without heading, probably to excluding it in the output. 470 tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(1), ""); 471 break; 472 473 case 3: 474 tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(2), tokens.get(1)); 475 break; 476 477 default: 478 messages.error("doclet.Error_invalid_custom_tag_argument", args.get(1)); 479 } 480 } 481 } catch (IOException e) { 482 messages.error("doclet.taglet_could_not_set_location", e.toString()); 483 } 484 } 485 486 /** 487 * Given a string, return an array of tokens. The separator can be escaped 488 * with the '\' character. The '\' character may also be escaped by the 489 * '\' character. 490 * 491 * @param s the string to tokenize. 492 * @param separator the separator char. 493 * @param maxTokens the maximum number of tokens returned. If the 494 * max is reached, the remaining part of s is appended 495 * to the end of the last token. 496 * @return an array of tokens. 497 */ tokenize(String s, char separator, int maxTokens)498 private List<String> tokenize(String s, char separator, int maxTokens) { 499 List<String> tokens = new ArrayList<>(); 500 StringBuilder token = new StringBuilder(); 501 boolean prevIsEscapeChar = false; 502 for (int i = 0; i < s.length(); i += Character.charCount(i)) { 503 int currentChar = s.codePointAt(i); 504 if (prevIsEscapeChar) { 505 // Case 1: escaped character 506 token.appendCodePoint(currentChar); 507 prevIsEscapeChar = false; 508 } else if (currentChar == separator && tokens.size() < maxTokens - 1) { 509 // Case 2: separator 510 tokens.add(token.toString()); 511 token = new StringBuilder(); 512 } else if (currentChar == '\\') { 513 // Case 3: escape character 514 prevIsEscapeChar = true; 515 } else { 516 // Case 4: regular character 517 token.appendCodePoint(currentChar); 518 } 519 } 520 if (token.length() > 0) { 521 tokens.add(token.toString()); 522 } 523 return tokens; 524 } 525 526 /** 527 * Return true if the given doc-file subdirectory should be excluded and 528 * false otherwise. 529 * 530 * @param docfilesubdir the doc-files subdirectory to check. 531 * @return true if the directory is excluded. 532 */ shouldExcludeDocFileDir(String docfilesubdir)533 public boolean shouldExcludeDocFileDir(String docfilesubdir) { 534 Set<String> excludedDocFileDirs = getOptions().excludedDocFileDirs(); 535 return excludedDocFileDirs.contains(docfilesubdir); 536 } 537 538 /** 539 * Return true if the given qualifier should be excluded and false otherwise. 540 * 541 * @param qualifier the qualifier to check. 542 * @return true if the qualifier should be excluded 543 */ shouldExcludeQualifier(String qualifier)544 public boolean shouldExcludeQualifier(String qualifier) { 545 Set<String> excludedQualifiers = getOptions().excludedQualifiers(); 546 if (excludedQualifiers.contains("all") || 547 excludedQualifiers.contains(qualifier) || 548 excludedQualifiers.contains(qualifier + ".*")) { 549 return true; 550 } else { 551 int index = -1; 552 while ((index = qualifier.indexOf(".", index + 1)) != -1) { 553 if (excludedQualifiers.contains(qualifier.substring(0, index + 1) + "*")) { 554 return true; 555 } 556 } 557 return false; 558 } 559 } 560 561 /** 562 * Return the qualified name of the Element if its qualifier is not excluded. 563 * Otherwise return the unqualified Element name. 564 * 565 * @param te the TypeElement to check. 566 * @return the class name 567 */ getClassName(TypeElement te)568 public String getClassName(TypeElement te) { 569 PackageElement pkg = utils.containingPackage(te); 570 return shouldExcludeQualifier(utils.getPackageName(pkg)) 571 ? utils.getSimpleName(te) 572 : utils.getFullyQualifiedName(te); 573 } 574 575 /** 576 * Return true if the TypeElement element is getting documented, depending upon 577 * -nodeprecated option and the deprecation information. Return true if 578 * -nodeprecated is not used. Return false if -nodeprecated is used and if 579 * either TypeElement element is deprecated or the containing package is deprecated. 580 * 581 * @param te the TypeElement for which the page generation is checked 582 * @return true if it is a generated doc. 583 */ isGeneratedDoc(TypeElement te)584 public boolean isGeneratedDoc(TypeElement te) { 585 boolean nodeprecated = getOptions().noDeprecated(); 586 if (!nodeprecated) { 587 return true; 588 } 589 return !(utils.isDeprecated(te) || utils.isDeprecated(utils.containingPackage(te))); 590 } 591 592 /** 593 * Return the doclet specific instance of a writer factory. 594 * 595 * @return the {@link WriterFactory} for the doclet. 596 */ getWriterFactory()597 public abstract WriterFactory getWriterFactory(); 598 599 /** 600 * Return the Locale for this document. 601 * 602 * @return the current locale 603 */ getLocale()604 public abstract Locale getLocale(); 605 606 /** 607 * Return the path of the overview file and null if it does not exist. 608 * 609 * @return the path of the overview file. 610 */ getOverviewPath()611 public abstract JavaFileObject getOverviewPath(); 612 613 /** 614 * Return the current file manager. 615 * 616 * @return JavaFileManager 617 */ getFileManager()618 public abstract JavaFileManager getFileManager(); 619 showMessage(DocTreePath path, String key)620 public abstract boolean showMessage(DocTreePath path, String key); 621 showMessage(Element e, String key)622 public abstract boolean showMessage(Element e, String key); 623 624 /* 625 * Splits the elements in a collection to its individual 626 * collection. 627 */ 628 private static class Splitter { 629 630 final Set<ModuleElement> mset = new LinkedHashSet<>(); 631 final Set<PackageElement> pset = new LinkedHashSet<>(); 632 final Set<TypeElement> tset = new LinkedHashSet<>(); 633 Splitter(DocletEnvironment docEnv, boolean included)634 Splitter(DocletEnvironment docEnv, boolean included) { 635 636 Set<? extends Element> inset = included 637 ? docEnv.getIncludedElements() 638 : docEnv.getSpecifiedElements(); 639 640 for (Element e : inset) { 641 new SimpleElementVisitor14<Void, Void>() { 642 @Override 643 @DefinedBy(Api.LANGUAGE_MODEL) 644 public Void visitModule(ModuleElement e, Void p) { 645 mset.add(e); 646 return null; 647 } 648 649 @Override 650 @DefinedBy(Api.LANGUAGE_MODEL) 651 public Void visitPackage(PackageElement e, Void p) { 652 pset.add(e); 653 return null; 654 } 655 656 @Override 657 @DefinedBy(Api.LANGUAGE_MODEL) 658 public Void visitType(TypeElement e, Void p) { 659 tset.add(e); 660 return null; 661 } 662 663 @Override 664 @DefinedBy(Api.LANGUAGE_MODEL) 665 protected Void defaultAction(Element e, Void p) { 666 throw new AssertionError("unexpected element: " + e); 667 } 668 669 }.visit(e); 670 } 671 } 672 } 673 674 /** 675 * Returns whether or not to allow JavaScript in comments. 676 * Default is off; can be set true from a command-line option. 677 * 678 * @return the allowScriptInComments 679 */ isAllowScriptInComments()680 public boolean isAllowScriptInComments() { 681 return getOptions().allowScriptInComments(); 682 } 683 getVisibleMemberTable(TypeElement te)684 public synchronized VisibleMemberTable getVisibleMemberTable(TypeElement te) { 685 return visibleMemberCache.getVisibleMemberTable(te); 686 } 687 688 /** 689 * Determines if JavaFX is available in the compilation environment. 690 * @return true if JavaFX is available 691 */ isJavaFXMode()692 public boolean isJavaFXMode() { 693 TypeElement observable = utils.elementUtils.getTypeElement("javafx.beans.Observable"); 694 if (observable == null) { 695 return false; 696 } 697 ModuleElement javafxModule = utils.elementUtils.getModuleOf(observable); 698 return javafxModule == null 699 || javafxModule.isUnnamed() 700 || javafxModule.getQualifiedName().contentEquals("javafx.base"); 701 } 702 703 704 //<editor-fold desc="DocLint support"> 705 706 private DocLint doclint; 707 708 Map<CompilationUnitTree, Boolean> shouldCheck = new HashMap<>(); 709 runDocLint(TreePath path)710 public void runDocLint(TreePath path) { 711 CompilationUnitTree unit = path.getCompilationUnit(); 712 if (doclint != null && shouldCheck.computeIfAbsent(unit, doclint::shouldCheck)) { 713 doclint.scan(path); 714 } 715 } 716 717 /** 718 * Initializes DocLint, if appropriate, depending on options derived 719 * from the doclet command-line options, and the set of custom tags 720 * that should be ignored by DocLint. 721 * 722 * DocLint is not enabled if the option {@code -Xmsgs:none} is given, 723 * and it is not followed by any options to enable any groups. 724 * Note that arguments for {@code -Xmsgs:} can be given individually 725 * in separate {@code -Xmsgs:} options, or in a comma-separated list 726 * for a single option. For example, the following are equivalent: 727 * <ul> 728 * <li>{@code -Xmsgs:all} {@code -Xmsgs:-html} 729 * <li>{@code -Xmsgs:all,-html} 730 * </ul> 731 * 732 * @param opts options for DocLint, derived from the corresponding doclet 733 * command-line options 734 * @param customTagNames the names of custom tags, to be ignored by doclint 735 */ initDocLint(List<String> opts, Set<String> customTagNames)736 public void initDocLint(List<String> opts, Set<String> customTagNames) { 737 List<String> doclintOpts = new ArrayList<>(); 738 739 // basic analysis of -Xmsgs and -Xmsgs: options to see if doclint is enabled 740 Set<String> groups = new HashSet<>(); 741 boolean seenXmsgs = false; 742 for (String opt : opts) { 743 if (opt.equals(DocLint.XMSGS_OPTION)) { 744 groups.add("all"); 745 seenXmsgs = true; 746 } else if (opt.startsWith(DocLint.XMSGS_CUSTOM_PREFIX)) { 747 String[] args = opt.substring(DocLint.XMSGS_CUSTOM_PREFIX.length()) 748 .split(DocLint.SEPARATOR); 749 for (String a : args) { 750 if (a.equals("none")) { 751 groups.clear(); 752 } else if (a.startsWith("-")) { 753 groups.remove(a.substring(1)); 754 } else { 755 groups.add(a); 756 } 757 } 758 seenXmsgs = true; 759 } 760 doclintOpts.add(opt); 761 } 762 763 if (seenXmsgs) { 764 if (groups.isEmpty()) { 765 // no groups enabled; do not init doclint 766 return; 767 } 768 } else { 769 // no -Xmsgs options of any kind, use default 770 doclintOpts.add(DocLint.XMSGS_OPTION); 771 } 772 773 if (!customTagNames.isEmpty()) { 774 String customTags = String.join(DocLint.SEPARATOR, customTagNames); 775 doclintOpts.add(DocLint.XCUSTOM_TAGS_PREFIX + customTags); 776 } 777 778 doclint = new DocLint(); 779 doclint.init(docEnv.getDocTrees(), docEnv.getElementUtils(), docEnv.getTypeUtils(), 780 doclintOpts.toArray(new String[0])); 781 } 782 haveDocLint()783 public boolean haveDocLint() { 784 return (doclint != null); 785 } 786 //</editor-fold> 787 } 788