Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java
41161 views
1
/*
2
* Copyright (c) 2001, 2021, 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
package jdk.javadoc.internal.tool;
26
27
import java.io.IOException;
28
import java.util.ArrayList;
29
import java.util.Collection;
30
import java.util.Collections;
31
import java.util.EnumMap;
32
import java.util.EnumSet;
33
import java.util.HashMap;
34
import java.util.HashSet;
35
import java.util.LinkedHashMap;
36
import java.util.LinkedHashSet;
37
import java.util.List;
38
import java.util.Map;
39
import java.util.Set;
40
41
import javax.lang.model.element.Element;
42
import javax.lang.model.element.ElementKind;
43
import javax.lang.model.element.Modifier;
44
import javax.lang.model.element.ModuleElement;
45
import javax.lang.model.element.ModuleElement.ExportsDirective;
46
import javax.lang.model.element.ModuleElement.RequiresDirective;
47
import javax.lang.model.element.PackageElement;
48
import javax.lang.model.element.TypeElement;
49
import javax.lang.model.util.ElementFilter;
50
import javax.lang.model.util.SimpleElementVisitor14;
51
import javax.tools.JavaFileManager;
52
import javax.tools.JavaFileManager.Location;
53
import javax.tools.JavaFileObject;
54
import javax.tools.StandardLocation;
55
56
import com.sun.tools.javac.code.Kinds.Kind;
57
import com.sun.tools.javac.code.Source;
58
import com.sun.tools.javac.code.Source.Feature;
59
import com.sun.tools.javac.code.Symbol;
60
import com.sun.tools.javac.code.Symbol.ClassSymbol;
61
import com.sun.tools.javac.code.Symbol.CompletionFailure;
62
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
63
import com.sun.tools.javac.code.Symbol.PackageSymbol;
64
import com.sun.tools.javac.code.Symtab;
65
import com.sun.tools.javac.comp.Modules;
66
import com.sun.tools.javac.main.JavaCompiler;
67
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
68
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
69
import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
70
import com.sun.tools.javac.tree.TreeInfo;
71
import com.sun.tools.javac.util.Context;
72
import com.sun.tools.javac.util.ListBuffer;
73
import com.sun.tools.javac.util.Name;
74
import com.sun.tools.javac.util.Names;
75
import jdk.javadoc.doclet.DocletEnvironment;
76
import jdk.javadoc.doclet.DocletEnvironment.ModuleMode;
77
78
import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
79
80
import static javax.lang.model.util.Elements.Origin.*;
81
import static javax.tools.JavaFileObject.Kind.*;
82
83
import static jdk.javadoc.internal.tool.Main.Result.*;
84
import static jdk.javadoc.internal.tool.JavadocTool.isValidClassName;
85
86
87
/**
88
* This class manages elements specified on the command line, and
89
* produces "specified" and "included" data sets, needed by the
90
* doclet environment, as well as querying an elements' visibility
91
* or inclusion.
92
*
93
* A. Initialization phase: the class is initialized with the
94
* options table by the caller. Some program elements may not
95
* be specified via specific options, such as packages, classes,
96
* these are set with the use of setter methods, such setClassArgList
97
* and setClassDeclList.
98
*
99
* B. Scan and decode phase: this is performed by scanSpecifiedItems,
100
* to identify the modules specified on the command line, modules
101
* specified with qualified packages and qualified subpackages, the
102
* modules so identified are used to initialize the module system.
103
*
104
* C. Intermediate phase: before the final analysis can be done,
105
* intermediate methods can be used to get specified elements from
106
* the initialization phase, typically used to parse sources or packages
107
* specified on the command line.
108
*
109
* D. Analysis phase: the final analysis is performed to determine
110
* the packages that ought to be included, as follows:
111
*
112
* 1. computes the specified modules, by considering the option
113
* "expand-requires", this must be done exhaustively, as the package
114
* computation phase expects a completed module graph, in order to
115
* check the target of a qualified export is in the included set.
116
*
117
* 2. computes the packages that must be documented, by considering
118
* the option "show-packages", also if only exported packages are
119
* to be considered, then also check for qualified packages, and
120
* include only those packages whose target is in the included set.
121
*
122
* 3. compute the specified packages, as part of this, first compute
123
* the subpackages and exclude any packages, if required.
124
*
125
* 4. Finally, compute the types found by previous parsing steps,
126
* noting that, all enclosed types (nested types) must also be
127
* considered.
128
*
129
* E. Finally, this class provides methods to obtain the specified sets,
130
* which are frozen and cached in the analysis phase, the included
131
* sets, are computed lazily and cached for future use. An element
132
* can be checked if it should be documented, in which case, the
133
* element is checked against the included set and the result is
134
* cached, for performance reasons.
135
*
136
* Definitions:
137
* Fully included: an element is included and some or parts
138
* of it components are included implicitly, subject to a
139
* selection criteria of its enclosed children.
140
*
141
* Included: if the item should be documented.
142
*
143
* Rules for processing:
144
*
145
* 1. A specified element, meaning an element given on the
146
* command-line, and exposed via specified elements collections.
147
* 2. Expand-contents, an internal pseudo term, meaning
148
* it is part of the recursive expansion of specified
149
* elements, meaning, the modules are expanded first, then
150
* the packages contained in the expanded modules, and then
151
* the types contained within the packages, to produce the
152
* collections returned by the methods
153
* getInclude{Module|Package|Type}Elements(), this is a
154
* downward expansion.
155
* 3. An included element, meaning it should be documented, and
156
* exposed via isIncluded, this enclosing element (module, package)
157
* is recursively included.
158
*/
159
public class ElementsTable {
160
161
private final ToolEnvironment toolEnv;
162
private final Symtab syms;
163
private final Names names;
164
private final JavaFileManager fm;
165
private final List<Location> locations;
166
private final Modules modules;
167
private final ToolOptions options;
168
private final Messager messager;
169
private final JavaCompiler compiler;
170
171
private final Map<String, Entry> entries = new LinkedHashMap<>();
172
173
// specified elements
174
private Set<ModuleElement> specifiedModuleElements = new LinkedHashSet<>();
175
private Set<PackageElement> specifiedPackageElements = new LinkedHashSet<>();
176
private Set<TypeElement> specifiedTypeElements = new LinkedHashSet<>();
177
178
// included elements
179
private Set<ModuleElement> includedModuleElements = null;
180
private Set<PackageElement> includedPackageElements = null;
181
private Set<TypeElement> includedTypeElements = null;
182
183
// cmdline specifiers
184
private Set<ModulePackage> cmdLinePackages = new LinkedHashSet<>();
185
private Set<ModulePackage> excludePackages = new LinkedHashSet<>();
186
private Set<ModulePackage> subPackages = new LinkedHashSet<>();
187
188
private List<JCClassDecl> classDecList = Collections.emptyList();
189
private List<String> classArgList = Collections.emptyList();
190
private com.sun.tools.javac.util.List<JCCompilationUnit> classTreeList = null;
191
192
private final Set<JavaFileObject.Kind> sourceKinds = EnumSet.of(JavaFileObject.Kind.SOURCE);
193
194
private final ModifierFilter accessFilter;
195
196
private final AccessKind expandRequires;
197
198
final boolean xclasses;
199
200
/**
201
* Creates the table to manage included and excluded elements.
202
*
203
* @param context the context to locate commonly used objects
204
* @param options the tool options
205
*/
206
ElementsTable(Context context, ToolOptions options) {
207
this.toolEnv = ToolEnvironment.instance(context);
208
this.syms = Symtab.instance(context);
209
this.names = Names.instance(context);
210
this.fm = toolEnv.fileManager;
211
this.modules = Modules.instance(context);
212
this.options = options;
213
this.messager = Messager.instance0(context);
214
this.compiler = JavaCompiler.instance(context);
215
Source source = Source.instance(context);
216
217
List<Location> locs = new ArrayList<>();
218
if (modules.multiModuleMode) {
219
locs.add(StandardLocation.MODULE_SOURCE_PATH);
220
} else {
221
if (toolEnv.fileManager.hasLocation(StandardLocation.SOURCE_PATH))
222
locs.add(StandardLocation.SOURCE_PATH);
223
else
224
locs.add(StandardLocation.CLASS_PATH);
225
}
226
if (Feature.MODULES.allowedInSource(source) && toolEnv.fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH))
227
locs.add(StandardLocation.PATCH_MODULE_PATH);
228
this.locations = Collections.unmodifiableList(locs);
229
230
getEntry("").excluded = false;
231
232
accessFilter = new ModifierFilter(options);
233
xclasses = options.xclasses();
234
expandRequires = options.expandRequires();
235
}
236
237
/**
238
* Returns the module documentation level mode.
239
* @return the module documentation level mode
240
*/
241
public ModuleMode getModuleMode() {
242
switch(accessFilter.getAccessValue(ElementKind.MODULE)) {
243
case PACKAGE: case PRIVATE:
244
return DocletEnvironment.ModuleMode.ALL;
245
default:
246
return DocletEnvironment.ModuleMode.API;
247
}
248
}
249
250
private Set<Element> specifiedElements = null;
251
/**
252
* Returns a set of elements specified on the
253
* command line, including any inner classes.
254
*
255
* @return the set of elements specified on the command line
256
*/
257
public Set<? extends Element> getSpecifiedElements() {
258
if (specifiedElements == null) {
259
Set<Element> result = new LinkedHashSet<>();
260
result.addAll(specifiedModuleElements);
261
result.addAll(specifiedPackageElements);
262
result.addAll(specifiedTypeElements);
263
specifiedElements = Collections.unmodifiableSet(result);
264
}
265
return specifiedElements;
266
}
267
268
private Set<Element> includedElements = null;
269
/**
270
* Returns a set of elements included elements. The inclusion is as
271
* follows:
272
* A module is fully included,
273
* - is specified on the command line --module
274
* - is derived from the module graph, that is, by expanding the
275
* requires directive, based on --expand-requires
276
*
277
* A module is included if an enclosed package or type is
278
* specified on the command line.
279
*
280
* A package is fully included,
281
* - is specified on the command line
282
* - is derived from expanding -subpackages
283
* - can be documented in a fully included module based on --show-packages
284
*
285
* A package is included, if an enclosed package or a type is specified on
286
* the command line.
287
*
288
* Included type elements (including those within specified or included packages)
289
* to be documented.
290
*
291
* A type is fully included if
292
* - is specified on the command line with -sourcepath
293
* - is visible with --show-types filter
294
* A nested type is fully included if
295
* - is visible with --show-types filter
296
* - is enclosed in a fully included type
297
* @return the set of elements specified on the command line
298
*/
299
public Set<? extends Element> getIncludedElements() {
300
if (includedElements == null) {
301
Set<Element> result = new LinkedHashSet<>();
302
result.addAll(includedModuleElements);
303
result.addAll(includedPackageElements);
304
result.addAll(includedTypeElements);
305
includedElements = Collections.unmodifiableSet(result);
306
}
307
return includedElements;
308
}
309
310
private IncludedVisitor includedVisitor = null;
311
312
/**
313
* Returns true if the given element is included for consideration.
314
* This method accumulates elements in the cache as enclosed elements of
315
* fully included elements are tested.
316
* A member (constructor, method, field) is included if
317
* - it is visible in a fully included type (--show-members)
318
*
319
* @param e the element in question
320
*
321
* @see #getIncludedElements()
322
*
323
* @return true if included
324
*/
325
public boolean isIncluded(Element e) {
326
if (e == null) {
327
return false;
328
}
329
if (includedVisitor == null) {
330
includedVisitor = new IncludedVisitor();
331
}
332
return includedVisitor.visit(e);
333
}
334
335
/**
336
* Performs the final computation and freezes the collections.
337
* This is a terminal operation, thus no further modifications
338
* are allowed to the specified data sets.
339
*
340
* @throws ToolException if an error occurs
341
*/
342
void analyze() throws ToolException {
343
// compute the specified element, by expanding module dependencies
344
computeSpecifiedModules();
345
346
// compute all specified packages and subpackages
347
computeSpecifiedPackages();
348
349
// compute the specified types
350
computeSpecifiedTypes();
351
352
// compute the packages belonging to all the specified modules
353
Set<PackageElement> expandedModulePackages = computeModulePackages();
354
initializeIncludedSets(expandedModulePackages);
355
}
356
357
ElementsTable classTrees(com.sun.tools.javac.util.List<JCCompilationUnit> classTrees) {
358
this.classTreeList = classTrees;
359
return this;
360
}
361
362
/*
363
* This method sanity checks the following cases:
364
* a. a source-path containing a single module and many modules specified with --module
365
* b. no modules on source-path
366
* c. mismatched source-path and many modules specified with --module
367
*/
368
void sanityCheckSourcePathModules(List<String> moduleNames) throws ToolException {
369
if (!haveSourceLocationWithModule)
370
return;
371
372
if (moduleNames.size() > 1) {
373
String text = messager.getText("main.cannot_use_sourcepath_for_modules",
374
String.join(", ", moduleNames));
375
throw new ToolException(CMDERR, text);
376
}
377
378
String foundModule = getModuleName(StandardLocation.SOURCE_PATH);
379
if (foundModule == null) {
380
String text = messager.getText("main.module_not_found_on_sourcepath", moduleNames.get(0));
381
throw new ToolException(CMDERR, text);
382
}
383
384
if (!moduleNames.get(0).equals(foundModule)) {
385
String text = messager.getText("main.sourcepath_does_not_contain_module", moduleNames.get(0));
386
throw new ToolException(CMDERR, text);
387
}
388
}
389
390
private String getModuleName(Location location) throws ToolException {
391
try {
392
JavaFileObject jfo = fm.getJavaFileForInput(location,
393
"module-info", JavaFileObject.Kind.SOURCE);
394
if (jfo != null) {
395
JCCompilationUnit jcu = compiler.parse(jfo);
396
JCModuleDecl module = TreeInfo.getModule(jcu);
397
if (module != null) {
398
return module.getName().toString();
399
}
400
}
401
} catch (IOException ioe) {
402
String text = messager.getText("main.file.manager.list", location);
403
throw new ToolException(SYSERR, text, ioe);
404
}
405
return null;
406
}
407
408
ElementsTable scanSpecifiedItems() throws ToolException {
409
410
// scan modules specified on the command line
411
List<String> modules = options.modules();
412
List<String> mlist = new ArrayList<>();
413
for (String m : modules) {
414
List<Location> moduleLocations = getModuleLocation(locations, m);
415
if (moduleLocations.isEmpty()) {
416
String text = messager.getText("main.module_not_found", m);
417
throw new ToolException(CMDERR, text);
418
}
419
if (moduleLocations.contains(StandardLocation.SOURCE_PATH)) {
420
sanityCheckSourcePathModules(modules);
421
}
422
mlist.add(m);
423
ModuleSymbol msym = syms.enterModule(names.fromString(m));
424
specifiedModuleElements.add(msym);
425
}
426
427
// scan for modules with qualified packages
428
cmdLinePackages.stream()
429
.filter(ModulePackage::hasModule)
430
.forEachOrdered(mpkg -> mlist.add(mpkg.moduleName));
431
432
// scan for modules with qualified subpackages
433
options.subpackages().stream()
434
.map(ModulePackage::new)
435
.forEachOrdered(mpkg -> {
436
subPackages.add(mpkg);
437
if (mpkg.hasModule()) {
438
mlist.add(mpkg.moduleName);
439
}
440
});
441
442
// all the modules specified on the command line have been scraped
443
// init the module systems
444
this.modules.addExtraAddModules(mlist.toArray(new String[mlist.size()]));
445
this.modules.initModules(this.classTreeList);
446
447
return this;
448
}
449
450
/**
451
* Returns the includes table after setting a class names specified on the command line.
452
*
453
* @param classList
454
* @return the include table
455
*/
456
ElementsTable setClassArgList(List<String> classList) {
457
classArgList = classList;
458
return this;
459
}
460
461
/**
462
* Returns the includes table after setting the parsed class names.
463
*
464
* @param classesDecList
465
* @return the include table
466
*/
467
ElementsTable setClassDeclList(List<JCClassDecl> classesDecList) {
468
this.classDecList = classesDecList;
469
return this;
470
}
471
472
/**
473
* Returns an includes table after setting the specified package
474
* names.
475
* @param packageNames packages on the command line
476
* @return the includes table after setting the specified package
477
* names
478
*/
479
ElementsTable packages(Collection<String> packageNames) {
480
packageNames.stream()
481
.map(ModulePackage::new)
482
.forEachOrdered(mpkg -> cmdLinePackages.add(mpkg));
483
return this;
484
}
485
486
/**
487
* Returns the aggregate set of included packages and specified
488
* sub packages.
489
*
490
* @return the aggregate set of included packages and specified
491
* sub packages
492
*/
493
Iterable<ModulePackage> getPackagesToParse() throws IOException {
494
List<ModulePackage> result = new ArrayList<>();
495
result.addAll(cmdLinePackages);
496
result.addAll(subPackages);
497
return result;
498
}
499
500
private void computeSubpackages() throws ToolException {
501
options.excludes().stream()
502
.map(ModulePackage::new)
503
.forEachOrdered(mpkg -> excludePackages.add(mpkg));
504
505
excludePackages.forEach(p -> getEntry(p).excluded = true);
506
507
for (ModulePackage modpkg : subPackages) {
508
List<Location> locs = getLocation(modpkg);
509
for (Location loc : locs) {
510
addPackagesFromLocations(loc, modpkg);
511
}
512
}
513
}
514
515
/* Call fm.list and wrap any IOException that occurs in a ToolException */
516
private Iterable<JavaFileObject> fmList(Location location,
517
String packagename,
518
Set<JavaFileObject.Kind> kinds,
519
boolean recurse) throws ToolException {
520
try {
521
return fm.list(location, packagename, kinds, recurse);
522
} catch (IOException ioe) {
523
String text = messager.getText("main.file.manager.list", packagename);
524
throw new ToolException(SYSERR, text, ioe);
525
}
526
}
527
528
private void addPackagesFromLocations(Location packageLocn, ModulePackage modpkg) throws ToolException {
529
for (JavaFileObject fo : fmList(packageLocn, modpkg.packageName, sourceKinds, true)) {
530
String binaryName = fm.inferBinaryName(packageLocn, fo);
531
String pn = getPackageName(binaryName);
532
String simpleName = getSimpleName(binaryName);
533
Entry e = getEntry(pn);
534
if (!e.isExcluded() && isValidClassName(simpleName)) {
535
ModuleSymbol msym = (modpkg.hasModule())
536
? syms.getModule(names.fromString(modpkg.moduleName))
537
: findModuleOfPackageName(modpkg.packageName);
538
539
if (msym != null && !msym.isUnnamed()) {
540
syms.enterPackage(msym, names.fromString(pn));
541
ModulePackage npkg = new ModulePackage(msym.toString(), pn);
542
cmdLinePackages.add(npkg);
543
} else {
544
cmdLinePackages.add(e.modpkg);
545
}
546
e.files = (e.files == null
547
? com.sun.tools.javac.util.List.of(fo)
548
: e.files.prepend(fo));
549
}
550
}
551
}
552
553
/**
554
* Returns the "requires" modules for the target module.
555
* @param mdle the target module element
556
* @param onlyTransitive true gets all the requires transitive, otherwise
557
* gets all the non-transitive requires
558
*
559
* @return a set of modules
560
*/
561
private Set<ModuleElement> getModuleRequires(ModuleElement mdle, boolean onlyTransitive) throws ToolException {
562
Set<ModuleElement> result = new HashSet<>();
563
for (RequiresDirective rd : ElementFilter.requiresIn(mdle.getDirectives())) {
564
ModuleElement dep = rd.getDependency();
565
if (result.contains(dep))
566
continue;
567
if (!isMandated(mdle, rd) && onlyTransitive == rd.isTransitive()) {
568
if (!haveModuleSources(dep)) {
569
if (!warnedNoSources.contains(dep)) {
570
messager.printWarningUsingKey(dep, "main.module_source_not_found", dep.getQualifiedName());
571
warnedNoSources.add(dep);
572
}
573
}
574
result.add(dep);
575
} else if (isMandated(mdle, rd) && haveModuleSources(dep)) {
576
result.add(dep);
577
}
578
}
579
return result;
580
}
581
582
private boolean isMandated(ModuleElement mdle, RequiresDirective rd) {
583
return toolEnv.elements.getOrigin(mdle, rd) == MANDATED;
584
}
585
586
Set<ModuleElement> warnedNoSources = new HashSet<>();
587
588
Map<ModuleSymbol, Boolean> haveModuleSourcesCache = new HashMap<>();
589
private boolean haveModuleSources(ModuleElement mdle) throws ToolException {
590
ModuleSymbol msym = (ModuleSymbol) mdle;
591
if (msym.sourceLocation != null) {
592
return true;
593
}
594
if (msym.patchLocation != null) {
595
Boolean value = haveModuleSourcesCache.get(msym);
596
if (value == null) {
597
value = fmList(msym.patchLocation, "", sourceKinds, true).iterator().hasNext();
598
haveModuleSourcesCache.put(msym, value);
599
}
600
return value;
601
}
602
return false;
603
}
604
605
private void computeSpecifiedModules() throws ToolException {
606
if (expandRequires == null) { // no expansion requested
607
specifiedModuleElements = Collections.unmodifiableSet(specifiedModuleElements);
608
return;
609
}
610
611
final boolean expandAll = expandRequires.equals(AccessKind.PRIVATE)
612
|| expandRequires.equals(AccessKind.PACKAGE);
613
614
Set<ModuleElement> result = new LinkedHashSet<>();
615
ListBuffer<ModuleElement> queue = new ListBuffer<>();
616
617
// expand each specified module
618
for (ModuleElement mdle : specifiedModuleElements) {
619
result.add(mdle); // a specified module is included
620
queue.append(mdle);
621
Set<ModuleElement> publicRequires = getModuleRequires(mdle, true);
622
result.addAll(publicRequires);
623
// add all requires public
624
queue.addAll(publicRequires);
625
626
if (expandAll) {
627
// add non-public requires if needed
628
result.addAll(getModuleRequires(mdle, false));
629
}
630
}
631
632
// compute the transitive closure of all the requires public
633
for (ModuleElement m = queue.poll() ; m != null ; m = queue.poll()) {
634
for (ModuleElement mdle : getModuleRequires(m, true)) {
635
if (!result.contains(mdle)) {
636
result.add(mdle);
637
queue.append(mdle);
638
}
639
}
640
}
641
specifiedModuleElements = Collections.unmodifiableSet(result);
642
}
643
644
private Set<PackageElement> getAllModulePackages(ModuleElement mdle) throws ToolException {
645
Set<PackageElement> result = new HashSet<>();
646
ModuleSymbol msym = (ModuleSymbol) mdle;
647
List<Location> msymlocs = getModuleLocation(locations, msym.name.toString());
648
for (Location msymloc : msymlocs) {
649
for (JavaFileObject fo : fmList(msymloc, "", sourceKinds, true)) {
650
if (fo.getName().endsWith("module-info.java")) {
651
continue;
652
}
653
String binaryName = fm.inferBinaryName(msymloc, fo);
654
String pn = getPackageName(binaryName);
655
PackageSymbol psym = syms.enterPackage(msym, names.fromString(pn));
656
result.add((PackageElement) psym);
657
}
658
}
659
return result;
660
}
661
662
private Set<PackageElement> computeModulePackages() throws ToolException {
663
AccessKind accessValue = accessFilter.getAccessValue(ElementKind.PACKAGE);
664
final boolean documentAllModulePackages = (accessValue == AccessKind.PACKAGE ||
665
accessValue == AccessKind.PRIVATE);
666
667
accessValue = accessFilter.getAccessValue(ElementKind.MODULE);
668
final boolean moduleDetailedMode = (accessValue == AccessKind.PACKAGE ||
669
accessValue == AccessKind.PRIVATE);
670
Set<PackageElement> expandedModulePackages = new LinkedHashSet<>();
671
672
for (ModuleElement mdle : specifiedModuleElements) {
673
if (documentAllModulePackages) { // include all packages
674
List<PackageElement> packages = ElementFilter.packagesIn(mdle.getEnclosedElements());
675
expandedModulePackages.addAll(packages);
676
expandedModulePackages.addAll(getAllModulePackages(mdle));
677
} else { // selectively include required packages
678
List<ExportsDirective> exports = ElementFilter.exportsIn(mdle.getDirectives());
679
for (ExportsDirective export : exports) {
680
// add if fully exported or add qualified exports only if desired
681
if (export.getTargetModules() == null
682
|| documentAllModulePackages || moduleDetailedMode) {
683
expandedModulePackages.add(export.getPackage());
684
}
685
}
686
}
687
688
// add all packages specified on the command line
689
// belonging to this module
690
if (!cmdLinePackages.isEmpty()) {
691
for (ModulePackage modpkg : cmdLinePackages) {
692
PackageElement pkg = toolEnv.elements.getPackageElement(mdle,
693
modpkg.packageName);
694
if (pkg != null) {
695
expandedModulePackages.add(pkg);
696
}
697
}
698
}
699
}
700
return expandedModulePackages;
701
}
702
703
private void initializeIncludedSets(Set<PackageElement> expandedModulePackages) {
704
705
// process modules
706
Set<ModuleElement> imodules = new LinkedHashSet<>();
707
// add all the expanded modules
708
imodules.addAll(specifiedModuleElements);
709
710
// process packages
711
Set<PackageElement> ipackages = new LinkedHashSet<>();
712
// add all packages belonging to expanded modules
713
ipackages.addAll(expandedModulePackages);
714
// add all specified packages
715
specifiedPackageElements.forEach(pkg -> {
716
ModuleElement mdle = toolEnv.elements.getModuleOf(pkg);
717
if (mdle != null)
718
imodules.add(mdle);
719
ipackages.add(pkg);
720
});
721
722
// process types
723
Set<TypeElement> iclasses = new LinkedHashSet<>();
724
// add all types enclosed in expanded modules and packages
725
ipackages.forEach(pkg -> addAllClasses(iclasses, pkg));
726
// add all types and its nested types
727
specifiedTypeElements.forEach(klass -> {
728
ModuleElement mdle = toolEnv.elements.getModuleOf(klass);
729
if (mdle != null && !mdle.isUnnamed())
730
imodules.add(mdle);
731
PackageElement pkg = toolEnv.elements.getPackageOf(klass);
732
ipackages.add(pkg);
733
addAllClasses(iclasses, klass, true);
734
});
735
736
// all done, freeze the collections
737
includedModuleElements = Collections.unmodifiableSet(imodules);
738
includedPackageElements = Collections.unmodifiableSet(ipackages);
739
includedTypeElements = Collections.unmodifiableSet(iclasses);
740
}
741
742
/*
743
* Computes the included packages and freezes the specified packages list.
744
*/
745
private void computeSpecifiedPackages() throws ToolException {
746
747
computeSubpackages();
748
749
Set<PackageElement> packlist = new LinkedHashSet<>();
750
cmdLinePackages.forEach(modpkg -> {
751
PackageElement pkg;
752
if (modpkg.hasModule()) {
753
ModuleElement mdle = toolEnv.elements.getModuleElement(modpkg.moduleName);
754
pkg = toolEnv.elements.getPackageElement(mdle, modpkg.packageName);
755
} else {
756
pkg = toolEnv.elements.getPackageElement(modpkg.toString());
757
}
758
759
if (pkg != null) {
760
packlist.add(pkg);
761
} else {
762
messager.printWarningUsingKey("main.package_not_found", modpkg.toString());
763
}
764
});
765
specifiedPackageElements = Collections.unmodifiableSet(packlist);
766
}
767
768
/**
769
* Adds all classes as well as inner classes, to the specified
770
* list.
771
*/
772
private void computeSpecifiedTypes() throws ToolException {
773
Set<TypeElement> classes = new LinkedHashSet<>();
774
classDecList.forEach(def -> {
775
TypeElement te = def.sym;
776
if (te != null) {
777
addAllClasses(classes, te, true);
778
}
779
});
780
for (String className : classArgList) {
781
TypeElement te = toolEnv.loadClass(className);
782
if (te == null) {
783
String text = messager.getText("javadoc.class_not_found", className);
784
throw new ToolException(CMDERR, text);
785
} else {
786
addAllClasses(classes, te, true);
787
}
788
}
789
specifiedTypeElements = Collections.unmodifiableSet(classes);
790
}
791
792
private void addFilesForParser(Collection<JavaFileObject> result,
793
Collection<ModulePackage> collection,
794
boolean recurse) throws ToolException {
795
for (ModulePackage modpkg : collection) {
796
toolEnv.notice("main.Loading_source_files_for_package", modpkg.toString());
797
List<JavaFileObject> files = getFiles(modpkg, recurse);
798
if (files.isEmpty()) {
799
String text = messager.getText("main.no_source_files_for_package",
800
modpkg.toString());
801
throw new ToolException(CMDERR, text);
802
} else {
803
result.addAll(files);
804
}
805
}
806
}
807
808
/**
809
* Returns an aggregated list of java file objects from the items
810
* specified on the command line. The packages specified should not
811
* recurse, however sub-packages should recurse into the sub directories.
812
* @return a list of java file objects
813
* @throws IOException if an error occurs
814
*/
815
List<JavaFileObject> getFilesToParse() throws ToolException {
816
List<JavaFileObject> result = new ArrayList<>();
817
addFilesForParser(result, cmdLinePackages, false);
818
addFilesForParser(result, subPackages, true);
819
return result;
820
}
821
822
/**
823
* Returns the set of source files for a package.
824
*
825
* @param modpkg the specified package
826
* @return the set of file objects for the specified package
827
* @throws ToolException if an error occurs while accessing the files
828
*/
829
private List<JavaFileObject> getFiles(ModulePackage modpkg,
830
boolean recurse) throws ToolException {
831
Entry e = getEntry(modpkg);
832
// The files may have been found as a side effect of searching for subpackages
833
if (e.files != null) {
834
return e.files;
835
}
836
837
ListBuffer<JavaFileObject> lb = new ListBuffer<>();
838
List<Location> locs = getLocation(modpkg);
839
if (locs.isEmpty()) {
840
return Collections.emptyList();
841
}
842
String pname = modpkg.packageName;
843
for (Location packageLocn : locs) {
844
for (JavaFileObject fo : fmList(packageLocn, pname, sourceKinds, recurse)) {
845
String binaryName = fm.inferBinaryName(packageLocn, fo);
846
String simpleName = getSimpleName(binaryName);
847
if (isValidClassName(simpleName)) {
848
lb.append(fo);
849
}
850
}
851
}
852
return lb.toList();
853
}
854
855
private ModuleSymbol findModuleOfPackageName(String packageName) {
856
Name pack = names.fromString(packageName);
857
for (ModuleSymbol msym : modules.allModules()) {
858
PackageSymbol p = syms.getPackage(msym, pack);
859
if (p != null && !p.members().isEmpty()) {
860
return msym;
861
}
862
}
863
return null;
864
}
865
866
private List<Location> getLocation(ModulePackage modpkg) throws ToolException {
867
if (locations.size() == 1 && !locations.contains(StandardLocation.MODULE_SOURCE_PATH)) {
868
return Collections.singletonList(locations.get(0));
869
}
870
871
if (modpkg.hasModule()) {
872
return getModuleLocation(locations, modpkg.moduleName);
873
}
874
// TODO: handle invalid results better.
875
ModuleSymbol msym = findModuleOfPackageName(modpkg.packageName);
876
if (msym == null) {
877
return Collections.emptyList();
878
}
879
return getModuleLocation(locations, msym.name.toString());
880
}
881
882
boolean haveSourceLocationWithModule = false;
883
884
private List<Location> getModuleLocation(List<Location> locations, String msymName) throws ToolException {
885
List<Location> out = new ArrayList<>();
886
// search in the patch module first, this overrides others
887
if (locations.contains(StandardLocation.PATCH_MODULE_PATH)) {
888
Location loc = getModuleLocation(StandardLocation.PATCH_MODULE_PATH, msymName);
889
if (loc != null)
890
out.add(loc);
891
}
892
for (Location location : locations) {
893
// skip patch module, already done
894
if (location == StandardLocation.PATCH_MODULE_PATH) {
895
continue;
896
} else if (location == StandardLocation.MODULE_SOURCE_PATH) {
897
Location loc = getModuleLocation(location, msymName);
898
if (loc != null)
899
out.add(loc);
900
} else if (location == StandardLocation.SOURCE_PATH) {
901
haveSourceLocationWithModule = true;
902
out.add(StandardLocation.SOURCE_PATH);
903
}
904
}
905
return out;
906
}
907
908
private Location getModuleLocation(Location location, String msymName) throws ToolException {
909
try {
910
return fm.getLocationForModule(location, msymName);
911
} catch (IOException ioe) {
912
String text = messager.getText("main.doclet_could_not_get_location", msymName);
913
throw new ToolException(ERROR, text, ioe);
914
}
915
}
916
917
private Entry getEntry(String name) {
918
return getEntry(new ModulePackage(name));
919
}
920
921
private Entry getEntry(ModulePackage modpkg) {
922
Entry e = entries.get(modpkg.packageName);
923
if (e == null) {
924
entries.put(modpkg.packageName, e = new Entry(modpkg));
925
}
926
return e;
927
}
928
929
private String getPackageName(String name) {
930
int lastDot = name.lastIndexOf(".");
931
return (lastDot == -1 ? "" : name.substring(0, lastDot));
932
}
933
934
private String getSimpleName(String name) {
935
int lastDot = name.lastIndexOf(".");
936
return (lastDot == -1 ? name : name.substring(lastDot + 1));
937
}
938
939
/**
940
* Adds all inner classes of this class, and their inner classes recursively, to the list
941
*/
942
private void addAllClasses(Collection<TypeElement> list, TypeElement typeElement, boolean filtered) {
943
ClassSymbol klass = (ClassSymbol)typeElement;
944
try {
945
// eliminate needless checking, do this first.
946
if (list.contains(klass)) return;
947
// ignore classes with invalid Java class names
948
if (!JavadocTool.isValidClassName(klass.name.toString())) return;
949
if (filtered && !isTypeElementSelected(klass)) return;
950
list.add(klass);
951
for (Symbol sym : klass.members().getSymbols(NON_RECURSIVE)) {
952
if (sym != null && sym.kind == Kind.TYP) {
953
ClassSymbol s = (ClassSymbol)sym;
954
addAllClasses(list, s, filtered);
955
}
956
}
957
} catch (CompletionFailure e) {
958
if (e.getMessage() != null)
959
messager.printWarning(e.getMessage());
960
else
961
messager.printWarningUsingKey("main.unexpected.exception", e);
962
}
963
}
964
965
/**
966
* Returns a list of all classes contained in this package, including
967
* member classes of those classes, and their member classes, etc.
968
*/
969
private void addAllClasses(Collection<TypeElement> list, PackageElement pkg) {
970
boolean filtered = true;
971
for (Element isym : pkg.getEnclosedElements()) {
972
addAllClasses(list, (TypeElement)isym, filtered);
973
}
974
}
975
976
private boolean isTypeElementSelected(TypeElement te) {
977
return (xclasses || toolEnv.getFileKind(te) == SOURCE) && isSelected(te);
978
}
979
980
SimpleElementVisitor14<Boolean, Void> visibleElementVisitor = null;
981
/**
982
* Returns true if the element is selected, by applying
983
* the access filter checks. Special treatment is applied to
984
* types, for a top level type the access filter applies completely,
985
* however if is a nested type then it is allowed either if
986
* the enclosing is a static or the enclosing is also selected.
987
*
988
* @param e the element to be checked
989
* @return true if the element is visible
990
*/
991
public boolean isSelected(Element e) {
992
if (toolEnv.isSynthetic((Symbol) e)) {
993
return false;
994
}
995
if (visibleElementVisitor == null) {
996
visibleElementVisitor = new SimpleElementVisitor14<Boolean, Void>() {
997
@Override
998
public Boolean visitType(TypeElement e, Void p) {
999
if (!accessFilter.checkModifier(e)) {
1000
return false; // it is not allowed
1001
}
1002
Element encl = e.getEnclosingElement();
1003
1004
// check if nested
1005
if (encl.getKind() == ElementKind.PACKAGE)
1006
return true; // top-level class, allow it
1007
1008
// is enclosed static
1009
if (encl.getModifiers().contains(Modifier.STATIC))
1010
return true; // allowed
1011
1012
// check the enclosing
1013
return visit(encl);
1014
}
1015
1016
@Override
1017
protected Boolean defaultAction(Element e, Void p) {
1018
return accessFilter.checkModifier(e);
1019
}
1020
1021
@Override
1022
public Boolean visitUnknown(Element e, Void p) {
1023
throw new AssertionError("unknown element: " + e);
1024
}
1025
};
1026
}
1027
return visibleElementVisitor.visit(e);
1028
}
1029
1030
private class IncludedVisitor extends SimpleElementVisitor14<Boolean, Void> {
1031
private final Set<Element> includedCache;
1032
1033
public IncludedVisitor() {
1034
includedCache = new LinkedHashSet<>();
1035
}
1036
1037
@Override
1038
public Boolean visitModule(ModuleElement e, Void p) {
1039
// deduced by specified and/or requires expansion
1040
return includedModuleElements.contains(e);
1041
}
1042
1043
@Override
1044
public Boolean visitPackage(PackageElement e, Void p) {
1045
// deduced by specified or downward expansions
1046
return includedPackageElements.contains(e);
1047
}
1048
1049
@Override
1050
public Boolean visitType(TypeElement e, Void p) {
1051
if (includedTypeElements.contains(e)) {
1052
return true;
1053
}
1054
if (isTypeElementSelected(e)) {
1055
// Class is nameable from top-level and
1056
// the class and all enclosing classes
1057
// pass the modifier filter.
1058
PackageElement pkg = toolEnv.elements.getPackageOf(e);
1059
if (specifiedPackageElements.contains(pkg)) {
1060
return true;
1061
}
1062
Element enclosing = e.getEnclosingElement();
1063
if (enclosing != null) {
1064
switch(enclosing.getKind()) {
1065
case PACKAGE:
1066
return specifiedPackageElements.contains((PackageElement)enclosing);
1067
case CLASS: case INTERFACE: case ENUM: case ANNOTATION_TYPE:
1068
return visit((TypeElement) enclosing);
1069
default:
1070
throw new AssertionError("unknown element: " + enclosing);
1071
}
1072
}
1073
}
1074
return false;
1075
}
1076
1077
// members
1078
@Override
1079
public Boolean defaultAction(Element e, Void p) {
1080
if (includedCache.contains(e))
1081
return true;
1082
if (visit(e.getEnclosingElement()) && isSelected(e)) {
1083
switch(e.getKind()) {
1084
case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE:
1085
case MODULE: case OTHER: case PACKAGE:
1086
throw new AssertionError("invalid element for this operation: " + e);
1087
default:
1088
// the only allowed kinds in the cache are "members"
1089
includedCache.add(e);
1090
return true;
1091
}
1092
}
1093
return false;
1094
}
1095
1096
@Override
1097
public Boolean visitUnknown(Element e, Void p) {
1098
throw new AssertionError("unknown element: " + e);
1099
}
1100
1101
}
1102
1103
class Entry {
1104
final ModulePackage modpkg;
1105
Boolean excluded = false;
1106
com.sun.tools.javac.util.List<JavaFileObject> files;
1107
1108
Entry(ModulePackage modpkg) {
1109
this.modpkg = modpkg;
1110
}
1111
1112
Entry(String name) {
1113
modpkg = new ModulePackage(name);
1114
}
1115
1116
boolean isExcluded() {
1117
return excluded;
1118
}
1119
1120
@Override
1121
public String toString() {
1122
return "Entry{" + "modpkg=" + modpkg + ", excluded=" + excluded + ", files=" + files + '}';
1123
}
1124
}
1125
1126
/**
1127
* A container class to retrieve the module and package pair
1128
* from a parsed qualified package name.
1129
*/
1130
static class ModulePackage {
1131
1132
public final String moduleName;
1133
public final String packageName;
1134
1135
ModulePackage(String modulename, String packagename) {
1136
this.moduleName = modulename;
1137
this.packageName = packagename;
1138
}
1139
1140
ModulePackage(ModuleElement msym, String packagename) {
1141
this.moduleName = msym.toString();
1142
this.packageName = packagename;
1143
}
1144
1145
ModulePackage(String name) {
1146
String a[] = name.split("/");
1147
if (a.length == 2) {
1148
this.moduleName = a[0];
1149
this.packageName = a[1];
1150
} else {
1151
moduleName = null;
1152
packageName = name;
1153
}
1154
}
1155
1156
boolean hasModule() {
1157
return this.moduleName != null;
1158
}
1159
1160
@Override
1161
public boolean equals(Object obj) {
1162
if (obj instanceof ModulePackage that) {
1163
return this.toString().equals(that.toString());
1164
}
1165
return false;
1166
}
1167
1168
@Override
1169
public int hashCode() {
1170
return toString().hashCode();
1171
}
1172
1173
@Override
1174
public String toString() {
1175
return moduleName == null ? packageName : moduleName + "/" + packageName;
1176
}
1177
}
1178
1179
/**
1180
* A class which filters the access flags on classes, fields, methods, etc.
1181
*
1182
* @see javax.lang.model.element.Modifier
1183
*/
1184
1185
static class ModifierFilter {
1186
/**
1187
* The allowed ElementKind that can be stored.
1188
*/
1189
static final EnumSet<ElementKind> ALLOWED_KINDS = EnumSet.of(ElementKind.METHOD,
1190
ElementKind.CLASS,
1191
ElementKind.PACKAGE,
1192
ElementKind.MODULE);
1193
1194
// all possible access levels allowed for each element
1195
private final EnumMap<ElementKind, EnumSet<AccessKind>> filterMap =
1196
new EnumMap<>(ElementKind.class);
1197
1198
// the specified access level for each element
1199
private final EnumMap<ElementKind, AccessKind> accessMap =
1200
new EnumMap<>(ElementKind.class);
1201
1202
/**
1203
* Constructor - Specify a filter.
1204
*
1205
* @param options the tool options
1206
*/
1207
ModifierFilter(ToolOptions options) {
1208
1209
AccessKind accessValue = null;
1210
for (ElementKind kind : ALLOWED_KINDS) {
1211
switch (kind) {
1212
case METHOD:
1213
accessValue = options.showMembersAccess();
1214
break;
1215
case CLASS:
1216
accessValue = options.showTypesAccess();
1217
break;
1218
case PACKAGE:
1219
accessValue = options.showPackagesAccess();
1220
break;
1221
case MODULE:
1222
accessValue = options.showModuleContents();
1223
break;
1224
default:
1225
throw new AssertionError("unknown element: " + kind);
1226
1227
}
1228
accessMap.put(kind, accessValue);
1229
filterMap.put(kind, getFilterSet(accessValue));
1230
}
1231
}
1232
1233
static EnumSet<AccessKind> getFilterSet(AccessKind accessValue) {
1234
switch (accessValue) {
1235
case PUBLIC:
1236
return EnumSet.of(AccessKind.PUBLIC);
1237
case PROTECTED:
1238
default:
1239
return EnumSet.of(AccessKind.PUBLIC, AccessKind.PROTECTED);
1240
case PACKAGE:
1241
return EnumSet.of(AccessKind.PUBLIC, AccessKind.PROTECTED, AccessKind.PACKAGE);
1242
case PRIVATE:
1243
return EnumSet.allOf(AccessKind.class);
1244
}
1245
}
1246
1247
public AccessKind getAccessValue(ElementKind kind) {
1248
if (!ALLOWED_KINDS.contains(kind)) {
1249
throw new IllegalArgumentException("not allowed: " + kind);
1250
}
1251
return accessMap.getOrDefault(kind, AccessKind.PROTECTED);
1252
}
1253
1254
/**
1255
* Returns true if access is allowed.
1256
*
1257
* @param e the element in question
1258
* @return whether the modifiers pass this filter
1259
*/
1260
public boolean checkModifier(Element e) {
1261
Set<Modifier> modifiers = e.getModifiers();
1262
AccessKind fflag = AccessKind.PACKAGE;
1263
if (modifiers.contains(Modifier.PUBLIC)) {
1264
fflag = AccessKind.PUBLIC;
1265
} else if (modifiers.contains(Modifier.PROTECTED)) {
1266
fflag = AccessKind.PROTECTED;
1267
} else if (modifiers.contains(Modifier.PRIVATE)) {
1268
fflag = AccessKind.PRIVATE;
1269
}
1270
EnumSet<AccessKind> filterSet = filterMap.get(getAllowedKind(e.getKind()));
1271
return filterSet.contains(fflag);
1272
}
1273
1274
// convert a requested element kind to an allowed access kind
1275
private ElementKind getAllowedKind(ElementKind kind) {
1276
switch (kind) {
1277
case CLASS: case METHOD: case MODULE: case PACKAGE:
1278
return kind;
1279
case RECORD: case ANNOTATION_TYPE: case ENUM: case INTERFACE:
1280
return ElementKind.CLASS;
1281
case CONSTRUCTOR: case ENUM_CONSTANT: case EXCEPTION_PARAMETER:
1282
case FIELD: case INSTANCE_INIT: case LOCAL_VARIABLE: case PARAMETER:
1283
case RESOURCE_VARIABLE: case STATIC_INIT: case TYPE_PARAMETER:
1284
case RECORD_COMPONENT:
1285
return ElementKind.METHOD;
1286
default:
1287
throw new AssertionError("unsupported kind: " + kind);
1288
}
1289
}
1290
} // end ModifierFilter
1291
}
1292
1293