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 import java.io.*;
29 import java.lang.ref.*;
30 import java.util.*;
31
32 import javax.lang.model.element.Element;
33 import javax.lang.model.element.ModuleElement;
34 import javax.lang.model.element.PackageElement;
35 import javax.lang.model.element.TypeElement;
36 import javax.lang.model.util.SimpleElementVisitor14;
37 import javax.tools.JavaFileManager;
38 import javax.tools.JavaFileObject;
39
40 import com.sun.source.util.DocTreePath;
41 import com.sun.tools.javac.util.DefinedBy;
42 import com.sun.tools.javac.util.DefinedBy.Api;
43 import jdk.javadoc.doclet.Doclet;
44 import jdk.javadoc.doclet.DocletEnvironment;
45 import jdk.javadoc.doclet.Reporter;
46 import jdk.javadoc.doclet.StandardDoclet;
47 import jdk.javadoc.doclet.Taglet;
48 import jdk.javadoc.internal.doclets.formats.html.HtmlDoclet;
49 import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory;
50 import jdk.javadoc.internal.doclets.toolkit.taglets.TagletManager;
51 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
52 import jdk.javadoc.internal.doclets.toolkit.util.DocFileFactory;
53 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
54 import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
55 import jdk.javadoc.internal.doclets.toolkit.util.Extern;
56 import jdk.javadoc.internal.doclets.toolkit.util.Group;
57 import jdk.javadoc.internal.doclets.toolkit.util.MetaKeywords;
58 import jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException;
59 import jdk.javadoc.internal.doclets.toolkit.util.TypeElementCatalog;
60 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
61 import jdk.javadoc.internal.doclets.toolkit.util.Utils.Pair;
62 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberCache;
63 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
64
65 import static javax.tools.Diagnostic.Kind.*;
66
67 /**
68 * Configure the output based on the options. Doclets should sub-class
69 * BaseConfiguration, to configure and add their own options. This class contains
70 * all user options which are supported by the standard doclet.
71 * <p>
72 * <p><b>This is NOT part of any supported API.
73 * If you write code that depends on this, you do so at your own risk.
74 * This code and its internal interfaces are subject to change or
83 /**
84 * The factory for builders.
85 */
86 protected BuilderFactory builderFactory;
87
88 /**
89 * The taglet manager.
90 */
91 public TagletManager tagletManager;
92
93 /**
94 * The path to the builder XML input file.
95 */
96 public String builderXMLPath;
97
98 /**
99 * The default path to the builder XML.
100 */
101 public static final String DEFAULT_BUILDER_XML = "resources/doclet.xml";
102
103 /**
104 * The path to Taglets
105 */
106 public String tagletpath = null;
107
108 /**
109 * This is true if option "-serialwarn" is used. Default value is false to
110 * suppress excessive warnings about serial tag.
111 */
112 public boolean serialwarn = false;
113
114 /**
115 * The specified amount of space between tab stops.
116 */
117 public int sourcetab;
118
119 public String tabSpaces;
120
121 /**
122 * True if we should generate browsable sources.
123 */
124 public boolean linksource = false;
125
126 /**
127 * True if command line option "-nosince" is used. Default value is
128 * false.
129 */
130 public boolean nosince = false;
131
132 /**
133 * True if we should recursively copy the doc-file subdirectories
134 */
135 public boolean copydocfilesubdirs = false;
136
137 /**
138 * Maintain backward compatibility with previous javadoc version
139 */
140 public boolean backwardCompatibility = true;
141
142 /**
143 * True if user wants to add member names as meta keywords.
144 * Set to false because meta keywords are ignored in general
145 * by most Internet search engines.
146 */
147 public boolean keywords = false;
148
149 /**
150 * The meta tag keywords instance.
151 */
152 public final MetaKeywords metakeywords;
153
154 /**
155 * The set of doc-file subdirectories to exclude
156 */
157 protected Set<String> excludedDocFileDirs;
158
159 /**
160 * The set of qualifiers to exclude
161 */
162 protected Set<String> excludedQualifiers;
163
164 /**
165 * The doclet environment.
166 */
167 public DocletEnvironment docEnv;
168
169 /**
170 * An utility class for commonly used helpers
171 */
172 public Utils utils;
173
174 /**
175 * All the temporary accessors to javac internals.
176 */
177 public WorkArounds workArounds;
178
179 /**
180 * Destination directory name, in which doclet will generate the entire
181 * documentation. Default is current directory.
182 */
183 public String destDirName = "";
184
185 /**
186 * Destination directory name, in which doclet will copy the doc-files to.
187 */
188 public String docFileDestDirName = "";
189
190 /**
191 * Encoding for this document. Default is default encoding for this
192 * platform.
193 */
194 public String docencoding = null;
195
196 /**
197 * True if user wants to suppress descriptions and tags.
198 */
199 public boolean nocomment = false;
200
201 /**
202 * Encoding for this document. Default is default encoding for this
203 * platform.
204 */
205 public String encoding = null;
206
207 /**
208 * Generate author specific information for all the classes if @author
209 * tag is used in the doc comment and if -author option is used.
210 * <code>showauthor</code> is set to true if -author option is used.
211 * Default is don't show author information.
212 */
213 public boolean showauthor = false;
214
215 /**
216 * Generate documentation for JavaFX getters and setters automatically
217 * by copying it from the appropriate property definition.
218 */
219 public boolean javafx = false;
220
221 /**
222 * Generate version specific information for the all the classes
223 * if @version tag is used in the doc comment and if -version option is
224 * used. <code>showversion</code> is set to true if -version option is
225 * used.Default is don't show version information.
226 */
227 public boolean showversion = false;
228
229 /**
230 * Allow JavaScript in doc comments.
231 */
232 private boolean allowScriptInComments = false;
233
234 /**
235 * Sourcepath from where to read the source files. Default is classpath.
236 */
237 public String sourcepath = "";
238
239 /**
240 * Generate modules documentation if more than one module is present.
241 */
242 public boolean showModules = false;
243
244 /**
245 * Don't generate deprecated API information at all, if -nodeprecated
246 * option is used. <code>nodeprecated</code> is set to true if
247 * -nodeprecated option is used. Default is generate deprecated API
248 * information.
249 */
250 public boolean nodeprecated = false;
251
252 /**
253 * The catalog of classes specified on the command-line
254 */
255 public TypeElementCatalog typeElementCatalog;
256
257 /**
258 * True if user wants to suppress time stamp in output.
259 * Default is false.
260 */
261 public boolean notimestamp = false;
262
263 /**
264 * The package grouping instance.
265 */
266 public final Group group = new Group(this);
267
268 /**
269 * The tracker of external package links.
270 */
271 public Extern extern;
272
273 public Reporter reporter;
274
275 public Locale locale;
276
277 /**
278 * Suppress all messages
279 */
280 public boolean quiet = false;
281
282 /**
283 * Specifies whether those methods that override a super-type's method
284 * with no changes to the API contract should be summarized in the
285 * footnote section.
286 */
287 public boolean summarizeOverriddenMethods = false;
288
289 // A list containing urls
290 private final List<String> linkList = new ArrayList<>();
291
292 // A list of pairs containing urls and package list
293 private final List<Pair<String, String>> linkOfflineList = new ArrayList<>();
294
295 public boolean dumpOnError = false;
296
297 private List<Pair<String, String>> groupPairs;
298
299 public abstract Messages getMessages();
300
301 public abstract Resources getResources();
302
303 /**
304 * Returns a string identifying the version of the doclet.
305 *
306 * @return a version string
307 */
308 public abstract String getDocletVersion();
309
310 /**
311 * This method should be defined in all those doclets (configurations),
312 * which want to derive themselves from this BaseConfiguration. This method
313 * can be used to finish up the options setup.
314 *
315 * @return true if successful and false otherwise
316 */
317
324 */
325 public SortedSet<PackageElement> packages = null;
326
327 public OverviewElement overviewElement;
328
329 public DocFileFactory docFileFactory;
330
331 /**
332 * A sorted map, giving the (specified|included|other) packages for each module.
333 */
334 public SortedMap<ModuleElement, Set<PackageElement>> modulePackages;
335
336 /**
337 * The list of known modules, that should be documented.
338 */
339 public SortedSet<ModuleElement> modules;
340
341 protected static final String sharedResourceBundleName =
342 "jdk.javadoc.internal.doclets.toolkit.resources.doclets";
343
344 /**
345 * Primarily used to disable strict checks in the regression
346 * tests allowing those tests to be executed successfully, for
347 * instance, with OpenJDK builds which may not contain FX libraries.
348 */
349 public boolean disableJavaFxStrictChecks = false;
350
351 /**
352 * Show taglets (internal debug switch)
353 */
354 public boolean showTaglets = false;
355
356 VisibleMemberCache visibleMemberCache = null;
357
358 public PropertyUtils propertyUtils = null;
359
360 /**
361 * Constructs the configurations needed by the doclet.
362 *
363 * @apiNote
364 * The {@code doclet} parameter is used when {@link Taglet#init(DocletEnvironment, Doclet)
365 * initializing tags}.
366 * Some doclets (such as the {@link StandardDoclet), may delegate to another
367 * (such as the {@link HtmlDoclet}). In such cases, the primary doclet (i.e
368 * {@code StandardDoclet}) should be provided here, and not any internal
369 * class like {@code HtmlDoclet}.
370 *
371 * @param doclet the doclet for this run of javadoc
372 */
373 public BaseConfiguration(Doclet doclet) {
374 this.doclet = doclet;
375 excludedDocFileDirs = new HashSet<>();
376 excludedQualifiers = new HashSet<>();
377 setTabWidth(DocletConstants.DEFAULT_TAB_STOP_LENGTH);
378 metakeywords = new MetaKeywords(this);
379 groupPairs = new ArrayList<>(0);
380 }
381
382 private boolean initialized = false;
383
384 protected void initConfiguration(DocletEnvironment docEnv) {
385 if (initialized) {
386 throw new IllegalStateException("configuration previously initialized");
387 }
388 initialized = true;
389 this.docEnv = docEnv;
390 // Utils needs docEnv, safe to init now.
391 utils = new Utils(this);
392
393 if (!javafx) {
394 javafx = isJavaFXMode();
395 }
396
397 // Once docEnv and Utils have been initialized, others should be safe.
398 cmtUtils = new CommentUtils(this);
399 workArounds = new WorkArounds(this);
400 visibleMemberCache = new VisibleMemberCache(this);
401 propertyUtils = new PropertyUtils(this);
402
403 Splitter specifiedSplitter = new Splitter(docEnv, false);
404 specifiedModuleElements = Collections.unmodifiableSet(specifiedSplitter.mset);
405 specifiedPackageElements = Collections.unmodifiableSet(specifiedSplitter.pset);
406 specifiedTypeElements = Collections.unmodifiableSet(specifiedSplitter.tset);
407
408 Splitter includedSplitter = new Splitter(docEnv, true);
409 includedModuleElements = Collections.unmodifiableSet(includedSplitter.mset);
410 includedPackageElements = Collections.unmodifiableSet(includedSplitter.pset);
411 includedTypeElements = Collections.unmodifiableSet(includedSplitter.tset);
412 }
413
414 /**
415 * Return the builder factory for this doclet.
416 *
417 * @return the builder factory for this doclet.
488 }
489
490 // add entries for modules which may not have exported packages
491 modules.forEach((ModuleElement mdle) -> {
492 modulePackages.computeIfAbsent(mdle, m -> Collections.emptySet());
493 });
494
495 modules.addAll(modulePackages.keySet());
496 showModules = !modules.isEmpty();
497 for (Set<PackageElement> pkgs : modulePackages.values()) {
498 packages.addAll(pkgs);
499 }
500 }
501
502 private void initPackages() {
503 packages = new TreeSet<>(utils.makePackageComparator());
504 // add all the included packages
505 packages.addAll(includedPackageElements);
506 }
507
508 public Set<Doclet.Option> getSupportedOptions() {
509 Resources resources = getResources();
510 Doclet.Option[] options = {
511 new Option(resources, "-author") {
512 @Override
513 public boolean process(String opt, List<String> args) {
514 showauthor = true;
515 return true;
516 }
517 },
518 new Option(resources, "-d", 1) {
519 @Override
520 public boolean process(String opt, List<String> args) {
521 destDirName = addTrailingFileSep(args.get(0));
522 return true;
523 }
524 },
525 new Option(resources, "-docencoding", 1) {
526 @Override
527 public boolean process(String opt, List<String> args) {
528 docencoding = args.get(0);
529 return true;
530 }
531 },
532 new Option(resources, "-docfilessubdirs") {
533 @Override
534 public boolean process(String opt, List<String> args) {
535 copydocfilesubdirs = true;
536 return true;
537 }
538 },
539 new Hidden(resources, "-encoding", 1) {
540 @Override
541 public boolean process(String opt, List<String> args) {
542 encoding = args.get(0);
543 return true;
544 }
545 },
546 new Option(resources, "-excludedocfilessubdir", 1) {
547 @Override
548 public boolean process(String opt, List<String> args) {
549 addToSet(excludedDocFileDirs, args.get(0));
550 return true;
551 }
552 },
553 new Option(resources, "-group", 2) {
554 @Override
555 public boolean process(String opt, List<String> args) {
556 groupPairs.add(new Pair<>(args.get(0), args.get(1)));
557 return true;
558 }
559 },
560 new Option(resources, "--javafx -javafx") {
561 @Override
562 public boolean process(String opt, List<String> args) {
563 javafx = true;
564 return true;
565 }
566 },
567 new Option(resources, "-keywords") {
568 @Override
569 public boolean process(String opt, List<String> args) {
570 keywords = true;
571 return true;
572 }
573 },
574 new Option(resources, "-link", 1) {
575 @Override
576 public boolean process(String opt, List<String> args) {
577 linkList.add(args.get(0));
578 return true;
579 }
580 },
581 new Option(resources, "-linksource") {
582 @Override
583 public boolean process(String opt, List<String> args) {
584 linksource = true;
585 return true;
586 }
587 },
588 new Option(resources, "-linkoffline", 2) {
589 @Override
590 public boolean process(String opt, List<String> args) {
591 linkOfflineList.add(new Pair<>(args.get(0), args.get(1)));
592 return true;
593 }
594 },
595 new Option(resources, "-nocomment") {
596 @Override
597 public boolean process(String opt, List<String> args) {
598 nocomment = true;
599 return true;
600 }
601 },
602 new Option(resources, "-nodeprecated") {
603 @Override
604 public boolean process(String opt, List<String> args) {
605 nodeprecated = true;
606 return true;
607 }
608 },
609 new Option(resources, "-nosince") {
610 @Override
611 public boolean process(String opt, List<String> args) {
612 nosince = true;
613 return true;
614 }
615 },
616 new Option(resources, "-notimestamp") {
617 @Override
618 public boolean process(String opt, List<String> args) {
619 notimestamp = true;
620 return true;
621 }
622 },
623 new Option(resources, "-noqualifier", 1) {
624 @Override
625 public boolean process(String opt, List<String> args) {
626 addToSet(excludedQualifiers, args.get(0));
627 return true;
628 }
629 },
630 new Option(resources, "--override-methods", 1) {
631 @Override
632 public boolean process(String opt, List<String> args) {
633 String o = args.get(0);
634 switch (o) {
635 case "summary":
636 summarizeOverriddenMethods = true;
637 break;
638 case "detail":
639 summarizeOverriddenMethods = false;
640 break;
641 default:
642 reporter.print(ERROR,
643 getResources().getText("doclet.Option_invalid",o, "--override-methods"));
644 return false;
645 }
646 return true;
647 }
648 },
649 new Hidden(resources, "-quiet") {
650 @Override
651 public boolean process(String opt, List<String> args) {
652 quiet = true;
653 return true;
654 }
655 },
656 new Option(resources, "-serialwarn") {
657 @Override
658 public boolean process(String opt, List<String> args) {
659 serialwarn = true;
660 return true;
661 }
662 },
663 new Option(resources, "-sourcetab", 1) {
664 @Override
665 public boolean process(String opt, List<String> args) {
666 linksource = true;
667 try {
668 setTabWidth(Integer.parseInt(args.get(0)));
669 } catch (NumberFormatException e) {
670 //Set to -1 so that warning will be printed
671 //to indicate what is valid argument.
672 sourcetab = -1;
673 }
674 if (sourcetab <= 0) {
675 getMessages().warning("doclet.sourcetab_warning");
676 setTabWidth(DocletConstants.DEFAULT_TAB_STOP_LENGTH);
677 }
678 return true;
679 }
680 },
681 new Option(resources, "-tag", 1) {
682 @Override
683 public boolean process(String opt, List<String> args) {
684 ArrayList<String> list = new ArrayList<>();
685 list.add(opt);
686 list.add(args.get(0));
687 customTagStrs.add(list);
688 return true;
689 }
690 },
691 new Option(resources, "-taglet", 1) {
692 @Override
693 public boolean process(String opt, List<String> args) {
694 ArrayList<String> list = new ArrayList<>();
695 list.add(opt);
696 list.add(args.get(0));
697 customTagStrs.add(list);
698 return true;
699 }
700 },
701 new Option(resources, "-tagletpath", 1) {
702 @Override
703 public boolean process(String opt, List<String> args) {
704 tagletpath = args.get(0);
705 return true;
706 }
707 },
708 new Option(resources, "-version") {
709 @Override
710 public boolean process(String opt, List<String> args) {
711 showversion = true;
712 return true;
713 }
714 },
715 new Hidden(resources, "--dump-on-error") {
716 @Override
717 public boolean process(String opt, List<String> args) {
718 dumpOnError = true;
719 return true;
720 }
721 },
722 new Option(resources, "--allow-script-in-comments") {
723 @Override
724 public boolean process(String opt, List<String> args) {
725 allowScriptInComments = true;
726 return true;
727 }
728 },
729 new Hidden(resources, "--disable-javafx-strict-checks") {
730 @Override
731 public boolean process(String opt, List<String> args) {
732 disableJavaFxStrictChecks = true;
733 return true;
734 }
735 },
736 new Hidden(resources, "--show-taglets") {
737 @Override
738 public boolean process(String opt, List<String> args) {
739 showTaglets = true;
740 return true;
741 }
742 }
743 };
744 Set<Doclet.Option> set = new TreeSet<>();
745 set.addAll(Arrays.asList(options));
746 return set;
747 }
748
749 final LinkedHashSet<List<String>> customTagStrs = new LinkedHashSet<>();
750
751 /*
752 * when this is called all the option have been set, this method,
753 * initializes certain components before anything else is started.
754 */
755 protected boolean finishOptionSettings0() throws DocletException {
756 extern = new Extern(this);
757 initDestDirectory();
758 for (String link : linkList) {
759 extern.link(link, reporter);
760 }
761 for (Pair<String, String> linkOfflinePair : linkOfflineList) {
762 extern.link(linkOfflinePair.first, linkOfflinePair.second, reporter);
763 }
764 typeElementCatalog = new TypeElementCatalog(includedTypeElements, this);
765 initTagletManager(customTagStrs);
766 groupPairs.stream().forEach((grp) -> {
767 if (showModules) {
768 group.checkModuleGroups(grp.first, grp.second);
769 } else {
770 group.checkPackageGroups(grp.first, grp.second);
771 }
772 });
773 overviewElement = new OverviewElement(workArounds.getUnnamedPackage(), getOverviewPath());
774 return true;
775 }
776
777 /**
778 * Set the command line options supported by this configuration.
779 *
780 * @return true if the options are set successfully
781 * @throws DocletException if there is a problem while setting the options
782 */
783 public boolean setOptions() throws DocletException {
784 initPackages();
785 initModules();
786 if (!finishOptionSettings0() || !finishOptionSettings())
787 return false;
788
789 return true;
790 }
791
792 private void initDestDirectory() throws DocletException {
793 if (!destDirName.isEmpty()) {
794 Resources resources = getResources();
795 DocFile destDir = DocFile.createFileForDirectory(this, destDirName);
796 if (!destDir.exists()) {
797 //Create the output directory (in case it doesn't exist yet)
798 reporter.print(NOTE, resources.getText("doclet.dest_dir_create", destDirName));
799 destDir.mkdirs();
800 } else if (!destDir.isDirectory()) {
801 throw new SimpleDocletException(resources.getText(
802 "doclet.destination_directory_not_directory_0",
803 destDir.getPath()));
804 } else if (!destDir.canWrite()) {
805 throw new SimpleDocletException(resources.getText(
806 "doclet.destination_directory_not_writable_0",
807 destDir.getPath()));
808 }
809 }
810 DocFileFactory.getFactory(this).setDestDir(destDirName);
811 }
812
813 /**
814 * Initialize the taglet manager. The strings to initialize the simple custom tags should
815 * be in the following format: "[tag name]:[location str]:[heading]".
816 *
817 * @param customTagStrs the set two dimensional arrays of strings. These arrays contain
818 * either -tag or -taglet arguments.
819 */
820 private void initTagletManager(Set<List<String>> customTagStrs) {
821 tagletManager = tagletManager == null ?
822 new TagletManager(nosince, showversion, showauthor, javafx, this) :
823 tagletManager;
824 JavaFileManager fileManager = getFileManager();
825 Messages messages = getMessages();
826 try {
827 tagletManager.initTagletPath(fileManager, tagletpath);
828 tagletManager.loadTaglets(fileManager);
829
830 for (List<String> args : customTagStrs) {
831 if (args.get(0).equals("-taglet")) {
832 tagletManager.addCustomTag(args.get(1), fileManager);
833 continue;
834 }
835 List<String> tokens = tokenize(args.get(1), TagletManager.SIMPLE_TAGLET_OPT_SEPARATOR, 3);
836 switch (tokens.size()) {
837 case 1:
838 String tagName = args.get(1);
839 if (tagletManager.isKnownCustomTag(tagName)) {
840 //reorder a standard tag
841 tagletManager.addNewSimpleCustomTag(tagName, null, "");
842 } else {
843 //Create a simple tag with the heading that has the same name as the tag.
844 StringBuilder heading = new StringBuilder(tagName + ":");
845 heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0)));
846 tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a");
847 }
888 token.appendCodePoint(currentChar);
889 prevIsEscapeChar = false;
890 } else if (currentChar == separator && tokens.size() < maxTokens - 1) {
891 // Case 2: separator
892 tokens.add(token.toString());
893 token = new StringBuilder();
894 } else if (currentChar == '\\') {
895 // Case 3: escape character
896 prevIsEscapeChar = true;
897 } else {
898 // Case 4: regular character
899 token.appendCodePoint(currentChar);
900 }
901 }
902 if (token.length() > 0) {
903 tokens.add(token.toString());
904 }
905 return tokens;
906 }
907
908 private void addToSet(Set<String> s, String str) {
909 StringTokenizer st = new StringTokenizer(str, ":");
910 String current;
911 while (st.hasMoreTokens()) {
912 current = st.nextToken();
913 s.add(current);
914 }
915 }
916
917 /**
918 * Add a trailing file separator, if not found. Remove superfluous
919 * file separators if any. Preserve the front double file separator for
920 * UNC paths.
921 *
922 * @param path Path under consideration.
923 * @return String Properly constructed path string.
924 */
925 public static String addTrailingFileSep(String path) {
926 String fs = System.getProperty("file.separator");
927 String dblfs = fs + fs;
928 int indexDblfs;
929 while ((indexDblfs = path.indexOf(dblfs, 1)) >= 0) {
930 path = path.substring(0, indexDblfs) +
931 path.substring(indexDblfs + fs.length());
932 }
933 if (!path.endsWith(fs))
934 path += fs;
935 return path;
936 }
937
938 /**
939 * This checks for the validity of the options used by the user.
940 * As of this writing, this checks only docencoding.
941 *
942 * @return true if all the options are valid.
943 */
944 public boolean generalValidOptions() {
945 if (docencoding != null) {
946 if (!checkOutputFileEncoding(docencoding)) {
947 return false;
948 }
949 }
950 if (docencoding == null && (encoding != null && !encoding.isEmpty())) {
951 if (!checkOutputFileEncoding(encoding)) {
952 return false;
953 }
954 }
955 return true;
956 }
957
958 /**
959 * Check the validity of the given Source or Output File encoding on this
960 * platform.
961 *
962 * @param docencoding output file encoding.
963 */
964 private boolean checkOutputFileEncoding(String docencoding) {
965 OutputStream ost = new ByteArrayOutputStream();
966 OutputStreamWriter osw = null;
967 try {
968 osw = new OutputStreamWriter(ost, docencoding);
969 } catch (UnsupportedEncodingException exc) {
970 reporter.print(ERROR, getResources().getText("doclet.Encoding_not_supported", docencoding));
971 return false;
972 } finally {
973 try {
974 if (osw != null) {
975 osw.close();
976 }
977 } catch (IOException exc) {
978 }
979 }
980 return true;
981 }
982
983 /**
984 * Return true if the given doc-file subdirectory should be excluded and
985 * false otherwise.
986 *
987 * @param docfilesubdir the doc-files subdirectory to check.
988 * @return true if the directory is excluded.
989 */
990 public boolean shouldExcludeDocFileDir(String docfilesubdir) {
991 return excludedDocFileDirs.contains(docfilesubdir);
992 }
993
994 /**
995 * Return true if the given qualifier should be excluded and false otherwise.
996 *
997 * @param qualifier the qualifier to check.
998 * @return true if the qualifier should be excluded
999 */
1000 public boolean shouldExcludeQualifier(String qualifier) {
1001 if (excludedQualifiers.contains("all") ||
1002 excludedQualifiers.contains(qualifier) ||
1003 excludedQualifiers.contains(qualifier + ".*")) {
1004 return true;
1005 } else {
1006 int index = -1;
1007 while ((index = qualifier.indexOf(".", index + 1)) != -1) {
1008 if (excludedQualifiers.contains(qualifier.substring(0, index + 1) + "*")) {
1009 return true;
1010 }
1011 }
1012 return false;
1013 }
1014 }
1015
1016 /**
1017 * Return the qualified name of the Element if its qualifier is not excluded.
1018 * Otherwise return the unqualified Element name.
1019 *
1020 * @param te the TypeElement to check.
1021 * @return the class name
1022 */
1023 public String getClassName(TypeElement te) {
1024 PackageElement pkg = utils.containingPackage(te);
1025 return shouldExcludeQualifier(utils.getPackageName(pkg))
1026 ? utils.getSimpleName(te)
1027 : utils.getFullyQualifiedName(te);
1028 }
1029
1030 /**
1031 * Return true if the TypeElement element is getting documented, depending upon
1032 * -nodeprecated option and the deprecation information. Return true if
1033 * -nodeprecated is not used. Return false if -nodeprecated is used and if
1034 * either TypeElement element is deprecated or the containing package is deprecated.
1035 *
1036 * @param te the TypeElement for which the page generation is checked
1037 * @return true if it is a generated doc.
1038 */
1039 public boolean isGeneratedDoc(TypeElement te) {
1040 if (!nodeprecated) {
1041 return true;
1042 }
1043 return !(utils.isDeprecated(te) || utils.isDeprecated(utils.containingPackage(te)));
1044 }
1045
1046 /**
1047 * Return the doclet specific instance of a writer factory.
1048 *
1049 * @return the {@link WriterFactory} for the doclet.
1050 */
1051 public abstract WriterFactory getWriterFactory();
1052
1053 /**
1054 * Return the input stream to the builder XML.
1055 *
1056 * @return the input steam to the builder XML.
1057 * @throws DocFileIOException when the given XML file cannot be found or opened.
1058 */
1059 public InputStream getBuilderXML() throws DocFileIOException {
1066 * Return the Locale for this document.
1067 *
1068 * @return the current locale
1069 */
1070 public abstract Locale getLocale();
1071
1072 /**
1073 * Return the path of the overview file and null if it does not exist.
1074 *
1075 * @return the path of the overview file.
1076 */
1077 public abstract JavaFileObject getOverviewPath();
1078
1079 /**
1080 * Return the current file manager.
1081 *
1082 * @return JavaFileManager
1083 */
1084 public abstract JavaFileManager getFileManager();
1085
1086 private void setTabWidth(int n) {
1087 sourcetab = n;
1088 tabSpaces = String.format("%" + n + "s", "");
1089 }
1090
1091 public abstract boolean showMessage(DocTreePath path, String key);
1092
1093 public abstract boolean showMessage(Element e, String key);
1094
1095 public abstract static class Option implements Doclet.Option, Comparable<Option> {
1096 private final String[] names;
1097 private final String parameters;
1098 private final String description;
1099 private final int argCount;
1100
1101 protected Option(Resources resources, String name, int argCount) {
1102 this(resources, null, name, argCount);
1103 }
1104
1105 protected Option(Resources resources, String keyBase, String name, int argCount) {
1106 this.names = name.trim().split("\\s+");
1107 if (keyBase == null) {
1108 keyBase = "doclet.usage." + names[0].toLowerCase().replaceAll("^-+", "");
1109 }
1110 String desc = getOptionsMessage(resources, keyBase + ".description");
1111 if (desc.isEmpty()) {
1112 this.description = "<MISSING KEY>";
1113 this.parameters = "<MISSING KEY>";
1114 } else {
1115 this.description = desc;
1116 this.parameters = getOptionsMessage(resources, keyBase + ".parameters");
1117 }
1118 this.argCount = argCount;
1119 }
1120
1121 protected Option(Resources resources, String name) {
1122 this(resources, name, 0);
1123 }
1124
1125 private String getOptionsMessage(Resources resources, String key) {
1126 try {
1127 return resources.getText(key);
1128 } catch (MissingResourceException ignore) {
1129 return "";
1130 }
1131 }
1132
1133 @Override
1134 public String getDescription() {
1135 return description;
1136 }
1137
1138 @Override
1139 public Option.Kind getKind() {
1140 return Doclet.Option.Kind.STANDARD;
1141 }
1142
1143 @Override
1144 public List<String> getNames() {
1145 return Arrays.asList(names);
1146 }
1147
1148 @Override
1149 public String getParameters() {
1150 return parameters;
1151 }
1152
1153 @Override
1154 public String toString() {
1155 return Arrays.toString(names);
1156 }
1157
1158 @Override
1159 public int getArgumentCount() {
1160 return argCount;
1161 }
1162
1163 public boolean matches(String option) {
1164 for (String name : names) {
1165 boolean matchCase = name.startsWith("--");
1166 if (option.startsWith("--") && option.contains("=")) {
1167 return name.equals(option.substring(option.indexOf("=") + 1));
1168 } else if (matchCase) {
1169 return name.equals(option);
1170 }
1171 return name.toLowerCase().equals(option.toLowerCase());
1172 }
1173 return false;
1174 }
1175
1176 @Override
1177 public int compareTo(Option that) {
1178 return this.getNames().get(0).compareTo(that.getNames().get(0));
1179 }
1180 }
1181
1182 public abstract class XOption extends Option {
1183
1184 public XOption(Resources resources, String prefix, String name, int argCount) {
1185 super(resources, prefix, name, argCount);
1186 }
1187
1188 public XOption(Resources resources, String name, int argCount) {
1189 super(resources, name, argCount);
1190 }
1191
1192 public XOption(Resources resources, String name) {
1193 this(resources, name, 0);
1194 }
1195
1196 @Override
1197 public Option.Kind getKind() {
1198 return Doclet.Option.Kind.EXTENDED;
1199 }
1200 }
1201
1202 public abstract class Hidden extends Option {
1203
1204 public Hidden(Resources resources, String name, int argCount) {
1205 super(resources, name, argCount);
1206 }
1207
1208 public Hidden(Resources resources, String name) {
1209 this(resources, name, 0);
1210 }
1211
1212 @Override
1213 public Option.Kind getKind() {
1214 return Doclet.Option.Kind.OTHER;
1215 }
1216 }
1217
1218 /*
1219 * Splits the elements in a collection to its individual
1220 * collection.
1221 */
1222 @SuppressWarnings("preview")
1223 private static class Splitter {
1224
1225 final Set<ModuleElement> mset = new LinkedHashSet<>();
1226 final Set<PackageElement> pset = new LinkedHashSet<>();
1227 final Set<TypeElement> tset = new LinkedHashSet<>();
1228
1229 Splitter(DocletEnvironment docEnv, boolean included) {
1230
1231 Set<? extends Element> inset = included
1232 ? docEnv.getIncludedElements()
1233 : docEnv.getSpecifiedElements();
1234
1235 for (Element e : inset) {
1236 new SimpleElementVisitor14<Void, Void>() {
1237 @Override
1256 }
1257
1258 @Override
1259 @DefinedBy(Api.LANGUAGE_MODEL)
1260 protected Void defaultAction(Element e, Void p) {
1261 throw new AssertionError("unexpected element: " + e);
1262 }
1263
1264 }.visit(e);
1265 }
1266 }
1267 }
1268
1269 /**
1270 * Returns whether or not to allow JavaScript in comments.
1271 * Default is off; can be set true from a command line option.
1272 *
1273 * @return the allowScriptInComments
1274 */
1275 public boolean isAllowScriptInComments() {
1276 return allowScriptInComments;
1277 }
1278
1279 public synchronized VisibleMemberTable getVisibleMemberTable(TypeElement te) {
1280 return visibleMemberCache.getVisibleMemberTable(te);
1281 }
1282
1283 /**
1284 * Determines if JavaFX is available in the compilation environment.
1285 * @return true if JavaFX is available
1286 */
1287 public boolean isJavaFXMode() {
1288 TypeElement observable = utils.elementUtils.getTypeElement("javafx.beans.Observable");
1289 if (observable != null) {
1290 ModuleElement javafxModule = utils.elementUtils.getModuleOf(observable);
1291 if (javafxModule == null || javafxModule.isUnnamed() || javafxModule.getQualifiedName().contentEquals("javafx.base")) {
1292 return true;
1293 }
1294 }
1295 return false;
1296 }
|
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 import java.io.*;
29 import java.util.*;
30
31 import javax.lang.model.element.Element;
32 import javax.lang.model.element.ModuleElement;
33 import javax.lang.model.element.PackageElement;
34 import javax.lang.model.element.TypeElement;
35 import javax.lang.model.util.SimpleElementVisitor14;
36 import javax.tools.JavaFileManager;
37 import javax.tools.JavaFileObject;
38
39 import com.sun.source.util.DocTreePath;
40 import com.sun.tools.javac.util.DefinedBy;
41 import com.sun.tools.javac.util.DefinedBy.Api;
42 import jdk.javadoc.doclet.Doclet;
43 import jdk.javadoc.doclet.DocletEnvironment;
44 import jdk.javadoc.doclet.Reporter;
45 import jdk.javadoc.doclet.StandardDoclet;
46 import jdk.javadoc.doclet.Taglet;
47 import jdk.javadoc.internal.doclets.formats.html.HtmlDoclet;
48 import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory;
49 import jdk.javadoc.internal.doclets.toolkit.taglets.TagletManager;
50 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
51 import jdk.javadoc.internal.doclets.toolkit.util.DocFileFactory;
52 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
53 import jdk.javadoc.internal.doclets.toolkit.util.Extern;
54 import jdk.javadoc.internal.doclets.toolkit.util.Group;
55 import jdk.javadoc.internal.doclets.toolkit.util.MetaKeywords;
56 import jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException;
57 import jdk.javadoc.internal.doclets.toolkit.util.TypeElementCatalog;
58 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
59 import jdk.javadoc.internal.doclets.toolkit.util.Utils.Pair;
60 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberCache;
61 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
62
63 import static javax.tools.Diagnostic.Kind.*;
64
65 /**
66 * Configure the output based on the options. Doclets should sub-class
67 * BaseConfiguration, to configure and add their own options. This class contains
68 * all user options which are supported by the standard doclet.
69 * <p>
70 * <p><b>This is NOT part of any supported API.
71 * If you write code that depends on this, you do so at your own risk.
72 * This code and its internal interfaces are subject to change or
81 /**
82 * The factory for builders.
83 */
84 protected BuilderFactory builderFactory;
85
86 /**
87 * The taglet manager.
88 */
89 public TagletManager tagletManager;
90
91 /**
92 * The path to the builder XML input file.
93 */
94 public String builderXMLPath;
95
96 /**
97 * The default path to the builder XML.
98 */
99 public static final String DEFAULT_BUILDER_XML = "resources/doclet.xml";
100
101
102
103
104
105 /**
106 * Maintain backward compatibility with previous javadoc version
107 */
108 public boolean backwardCompatibility = true;
109
110
111 /**
112 * The meta tag keywords instance.
113 */
114 public MetaKeywords metakeywords;
115
116 /**
117 * The doclet environment.
118 */
119 public DocletEnvironment docEnv;
120
121 /**
122 * An utility class for commonly used helpers
123 */
124 public Utils utils;
125
126 /**
127 * All the temporary accessors to javac internals.
128 */
129 public WorkArounds workArounds;
130
131
132
133 /**
134 * Sourcepath from where to read the source files. Default is classpath.
135 */
136 public String sourcepath = "";
137
138 /**
139 * Generate modules documentation if more than one module is present.
140 */
141 public boolean showModules = false;
142
143
144 /**
145 * The catalog of classes specified on the command-line
146 */
147 public TypeElementCatalog typeElementCatalog;
148
149
150 /**
151 * The package grouping instance.
152 */
153 public final Group group = new Group(this);
154
155 /**
156 * The tracker of external package links.
157 */
158 public Extern extern;
159
160 public Reporter reporter;
161
162 public Locale locale;
163
164
165
166
167
168 public abstract Messages getMessages();
169
170 public abstract Resources getResources();
171
172 /**
173 * Returns a string identifying the version of the doclet.
174 *
175 * @return a version string
176 */
177 public abstract String getDocletVersion();
178
179 /**
180 * This method should be defined in all those doclets (configurations),
181 * which want to derive themselves from this BaseConfiguration. This method
182 * can be used to finish up the options setup.
183 *
184 * @return true if successful and false otherwise
185 */
186
193 */
194 public SortedSet<PackageElement> packages = null;
195
196 public OverviewElement overviewElement;
197
198 public DocFileFactory docFileFactory;
199
200 /**
201 * A sorted map, giving the (specified|included|other) packages for each module.
202 */
203 public SortedMap<ModuleElement, Set<PackageElement>> modulePackages;
204
205 /**
206 * The list of known modules, that should be documented.
207 */
208 public SortedSet<ModuleElement> modules;
209
210 protected static final String sharedResourceBundleName =
211 "jdk.javadoc.internal.doclets.toolkit.resources.doclets";
212
213
214
215 VisibleMemberCache visibleMemberCache = null;
216
217 public PropertyUtils propertyUtils = null;
218
219
220
221 /**
222 * Constructs the configurations needed by the doclet.
223 *
224 * @apiNote
225 * The {@code doclet} parameter is used when {@link Taglet#init(DocletEnvironment, Doclet)
226 * initializing tags}.
227 * Some doclets (such as the {@link StandardDoclet), may delegate to another
228 * (such as the {@link HtmlDoclet}). In such cases, the primary doclet (i.e
229 * {@code StandardDoclet}) should be provided here, and not any internal
230 * class like {@code HtmlDoclet}.
231 *
232 * @param doclet the doclet for this run of javadoc
233 */
234 public BaseConfiguration(Doclet doclet) {
235 this.doclet = doclet;
236 }
237
238 public abstract BaseOptions getOptions();
239
240 private boolean initialized = false;
241
242 protected void initConfiguration(DocletEnvironment docEnv) {
243 if (initialized) {
244 throw new IllegalStateException("configuration previously initialized");
245 }
246 initialized = true;
247 this.docEnv = docEnv;
248 // Utils needs docEnv, safe to init now.
249 utils = new Utils(this);
250
251 BaseOptions options = getOptions();
252 if (!options.javafx) {
253 options.javafx = isJavaFXMode();
254 }
255
256 // Once docEnv and Utils have been initialized, others should be safe.
257 metakeywords = new MetaKeywords(this);
258 cmtUtils = new CommentUtils(this);
259 workArounds = new WorkArounds(this);
260 visibleMemberCache = new VisibleMemberCache(this);
261 propertyUtils = new PropertyUtils(this);
262
263 Splitter specifiedSplitter = new Splitter(docEnv, false);
264 specifiedModuleElements = Collections.unmodifiableSet(specifiedSplitter.mset);
265 specifiedPackageElements = Collections.unmodifiableSet(specifiedSplitter.pset);
266 specifiedTypeElements = Collections.unmodifiableSet(specifiedSplitter.tset);
267
268 Splitter includedSplitter = new Splitter(docEnv, true);
269 includedModuleElements = Collections.unmodifiableSet(includedSplitter.mset);
270 includedPackageElements = Collections.unmodifiableSet(includedSplitter.pset);
271 includedTypeElements = Collections.unmodifiableSet(includedSplitter.tset);
272 }
273
274 /**
275 * Return the builder factory for this doclet.
276 *
277 * @return the builder factory for this doclet.
348 }
349
350 // add entries for modules which may not have exported packages
351 modules.forEach((ModuleElement mdle) -> {
352 modulePackages.computeIfAbsent(mdle, m -> Collections.emptySet());
353 });
354
355 modules.addAll(modulePackages.keySet());
356 showModules = !modules.isEmpty();
357 for (Set<PackageElement> pkgs : modulePackages.values()) {
358 packages.addAll(pkgs);
359 }
360 }
361
362 private void initPackages() {
363 packages = new TreeSet<>(utils.makePackageComparator());
364 // add all the included packages
365 packages.addAll(includedPackageElements);
366 }
367
368 /*
369 * when this is called all the option have been set, this method,
370 * initializes certain components before anything else is started.
371 */
372 protected boolean finishOptionSettings0() throws DocletException {
373 BaseOptions options = getOptions();
374 extern = new Extern(this);
375 initDestDirectory();
376 for (String link : options.linkList) {
377 extern.link(link, reporter);
378 }
379 for (Pair<String, String> linkOfflinePair : options.linkOfflineList) {
380 extern.link(linkOfflinePair.first, linkOfflinePair.second, reporter);
381 }
382 typeElementCatalog = new TypeElementCatalog(includedTypeElements, this);
383 initTagletManager(options.customTagStrs);
384 options.groupPairs.stream().forEach((grp) -> {
385 if (showModules) {
386 group.checkModuleGroups(grp.first, grp.second);
387 } else {
388 group.checkPackageGroups(grp.first, grp.second);
389 }
390 });
391 overviewElement = new OverviewElement(workArounds.getUnnamedPackage(), getOverviewPath());
392 return true;
393 }
394
395 /**
396 * Set the command line options supported by this configuration.
397 *
398 * @return true if the options are set successfully
399 * @throws DocletException if there is a problem while setting the options
400 */
401 public boolean setOptions() throws DocletException {
402 initPackages();
403 initModules();
404 if (!finishOptionSettings0() || !finishOptionSettings())
405 return false;
406
407 return true;
408 }
409
410 private void initDestDirectory() throws DocletException {
411 String destDirName = getOptions().destDirName;
412 if (!destDirName.isEmpty()) {
413 Resources resources = getResources();
414 DocFile destDir = DocFile.createFileForDirectory(this, destDirName);
415 if (!destDir.exists()) {
416 //Create the output directory (in case it doesn't exist yet)
417 reporter.print(NOTE, resources.getText("doclet.dest_dir_create", destDirName));
418 destDir.mkdirs();
419 } else if (!destDir.isDirectory()) {
420 throw new SimpleDocletException(resources.getText(
421 "doclet.destination_directory_not_directory_0",
422 destDir.getPath()));
423 } else if (!destDir.canWrite()) {
424 throw new SimpleDocletException(resources.getText(
425 "doclet.destination_directory_not_writable_0",
426 destDir.getPath()));
427 }
428 }
429 DocFileFactory.getFactory(this).setDestDir(destDirName);
430 }
431
432 /**
433 * Initialize the taglet manager. The strings to initialize the simple custom tags should
434 * be in the following format: "[tag name]:[location str]:[heading]".
435 *
436 * @param customTagStrs the set two dimensional arrays of strings. These arrays contain
437 * either -tag or -taglet arguments.
438 */
439 private void initTagletManager(Set<List<String>> customTagStrs) {
440 tagletManager = tagletManager != null ? tagletManager : new TagletManager(this);
441 JavaFileManager fileManager = getFileManager();
442 Messages messages = getMessages();
443 try {
444 tagletManager.initTagletPath(fileManager);
445 tagletManager.loadTaglets(fileManager);
446
447 for (List<String> args : customTagStrs) {
448 if (args.get(0).equals("-taglet")) {
449 tagletManager.addCustomTag(args.get(1), fileManager);
450 continue;
451 }
452 List<String> tokens = tokenize(args.get(1), TagletManager.SIMPLE_TAGLET_OPT_SEPARATOR, 3);
453 switch (tokens.size()) {
454 case 1:
455 String tagName = args.get(1);
456 if (tagletManager.isKnownCustomTag(tagName)) {
457 //reorder a standard tag
458 tagletManager.addNewSimpleCustomTag(tagName, null, "");
459 } else {
460 //Create a simple tag with the heading that has the same name as the tag.
461 StringBuilder heading = new StringBuilder(tagName + ":");
462 heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0)));
463 tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a");
464 }
505 token.appendCodePoint(currentChar);
506 prevIsEscapeChar = false;
507 } else if (currentChar == separator && tokens.size() < maxTokens - 1) {
508 // Case 2: separator
509 tokens.add(token.toString());
510 token = new StringBuilder();
511 } else if (currentChar == '\\') {
512 // Case 3: escape character
513 prevIsEscapeChar = true;
514 } else {
515 // Case 4: regular character
516 token.appendCodePoint(currentChar);
517 }
518 }
519 if (token.length() > 0) {
520 tokens.add(token.toString());
521 }
522 return tokens;
523 }
524
525
526
527
528
529 /**
530 * Return true if the given doc-file subdirectory should be excluded and
531 * false otherwise.
532 *
533 * @param docfilesubdir the doc-files subdirectory to check.
534 * @return true if the directory is excluded.
535 */
536 public boolean shouldExcludeDocFileDir(String docfilesubdir) {
537 Set<String> excludedDocFileDirs = getOptions().excludedDocFileDirs;
538 return excludedDocFileDirs.contains(docfilesubdir);
539 }
540
541 /**
542 * Return true if the given qualifier should be excluded and false otherwise.
543 *
544 * @param qualifier the qualifier to check.
545 * @return true if the qualifier should be excluded
546 */
547 public boolean shouldExcludeQualifier(String qualifier) {
548 Set<String> excludedQualifiers = getOptions().excludedQualifiers;
549 if (excludedQualifiers.contains("all") ||
550 excludedQualifiers.contains(qualifier) ||
551 excludedQualifiers.contains(qualifier + ".*")) {
552 return true;
553 } else {
554 int index = -1;
555 while ((index = qualifier.indexOf(".", index + 1)) != -1) {
556 if (excludedQualifiers.contains(qualifier.substring(0, index + 1) + "*")) {
557 return true;
558 }
559 }
560 return false;
561 }
562 }
563
564 /**
565 * Return the qualified name of the Element if its qualifier is not excluded.
566 * Otherwise return the unqualified Element name.
567 *
568 * @param te the TypeElement to check.
569 * @return the class name
570 */
571 public String getClassName(TypeElement te) {
572 PackageElement pkg = utils.containingPackage(te);
573 return shouldExcludeQualifier(utils.getPackageName(pkg))
574 ? utils.getSimpleName(te)
575 : utils.getFullyQualifiedName(te);
576 }
577
578 /**
579 * Return true if the TypeElement element is getting documented, depending upon
580 * -nodeprecated option and the deprecation information. Return true if
581 * -nodeprecated is not used. Return false if -nodeprecated is used and if
582 * either TypeElement element is deprecated or the containing package is deprecated.
583 *
584 * @param te the TypeElement for which the page generation is checked
585 * @return true if it is a generated doc.
586 */
587 public boolean isGeneratedDoc(TypeElement te) {
588 boolean nodeprecated = getOptions().noDeprecated;
589 if (!nodeprecated) {
590 return true;
591 }
592 return !(utils.isDeprecated(te) || utils.isDeprecated(utils.containingPackage(te)));
593 }
594
595 /**
596 * Return the doclet specific instance of a writer factory.
597 *
598 * @return the {@link WriterFactory} for the doclet.
599 */
600 public abstract WriterFactory getWriterFactory();
601
602 /**
603 * Return the input stream to the builder XML.
604 *
605 * @return the input steam to the builder XML.
606 * @throws DocFileIOException when the given XML file cannot be found or opened.
607 */
608 public InputStream getBuilderXML() throws DocFileIOException {
615 * Return the Locale for this document.
616 *
617 * @return the current locale
618 */
619 public abstract Locale getLocale();
620
621 /**
622 * Return the path of the overview file and null if it does not exist.
623 *
624 * @return the path of the overview file.
625 */
626 public abstract JavaFileObject getOverviewPath();
627
628 /**
629 * Return the current file manager.
630 *
631 * @return JavaFileManager
632 */
633 public abstract JavaFileManager getFileManager();
634
635
636 public abstract boolean showMessage(DocTreePath path, String key);
637
638 public abstract boolean showMessage(Element e, String key);
639
640 /*
641 * Splits the elements in a collection to its individual
642 * collection.
643 */
644 @SuppressWarnings("preview")
645 private static class Splitter {
646
647 final Set<ModuleElement> mset = new LinkedHashSet<>();
648 final Set<PackageElement> pset = new LinkedHashSet<>();
649 final Set<TypeElement> tset = new LinkedHashSet<>();
650
651 Splitter(DocletEnvironment docEnv, boolean included) {
652
653 Set<? extends Element> inset = included
654 ? docEnv.getIncludedElements()
655 : docEnv.getSpecifiedElements();
656
657 for (Element e : inset) {
658 new SimpleElementVisitor14<Void, Void>() {
659 @Override
678 }
679
680 @Override
681 @DefinedBy(Api.LANGUAGE_MODEL)
682 protected Void defaultAction(Element e, Void p) {
683 throw new AssertionError("unexpected element: " + e);
684 }
685
686 }.visit(e);
687 }
688 }
689 }
690
691 /**
692 * Returns whether or not to allow JavaScript in comments.
693 * Default is off; can be set true from a command line option.
694 *
695 * @return the allowScriptInComments
696 */
697 public boolean isAllowScriptInComments() {
698 return getOptions().allowScriptInComments;
699 }
700
701 public synchronized VisibleMemberTable getVisibleMemberTable(TypeElement te) {
702 return visibleMemberCache.getVisibleMemberTable(te);
703 }
704
705 /**
706 * Determines if JavaFX is available in the compilation environment.
707 * @return true if JavaFX is available
708 */
709 public boolean isJavaFXMode() {
710 TypeElement observable = utils.elementUtils.getTypeElement("javafx.beans.Observable");
711 if (observable != null) {
712 ModuleElement javafxModule = utils.elementUtils.getModuleOf(observable);
713 if (javafxModule == null || javafxModule.isUnnamed() || javafxModule.getQualifiedName().contentEquals("javafx.base")) {
714 return true;
715 }
716 }
717 return false;
718 }
|