JDK 11 jdk.javadoc.jmod - Java Document Tool

JDK 11 jdk.javadoc.jmod is the JMOD file for JDK 11 Java Document tool, which can be invoked by the "javadoc" command.

JDK 11 Java Document tool compiled class files are stored in \fyicenter\jdk-11.0.1\jmods\jdk.javadoc.jmod.

JDK 11 Java Document tool compiled class files are also linked and stored in the \fyicenter\jdk-11.0.1\lib\modules JImage file.

JDK 11 Java Document tool source code files are stored in \fyicenter\jdk-11.0.1\lib\src.zip\jdk.javadoc.

You can click and view the content of each source code file in the list below.

✍: FYIcenter

jdk/javadoc/internal/tool/ElementsTable.java

/*
 * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package jdk.javadoc.internal.tool;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.ModuleElement.ExportsDirective;
import javax.lang.model.element.ModuleElement.RequiresDirective;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;

import com.sun.tools.javac.code.Kinds.Kind;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.Source.Feature;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.comp.Modules;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.doclet.DocletEnvironment.ModuleMode;

import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;

import static javax.lang.model.util.Elements.Origin.*;
import static javax.tools.JavaFileObject.Kind.*;

import static jdk.javadoc.internal.tool.Main.Result.*;
import static jdk.javadoc.internal.tool.JavadocTool.isValidClassName;


/**
 * This class manages elements specified on the command line, and
 * produces "specified" and "included" data sets, needed by the
 * doclet environment, as well as querying an elements' visibility
 * or inclusion.
 *
 * A. Initialization phase: the class is initialized with the
 *    options table by the caller. Some program elements may not
 *    be specified via specific options, such as packages, classes,
 *    these are set with the use of setter methods, such setClassArgList
 *    and setClassDeclList.
 *
 * B. Scan and decode phase: this is performed by scanSpecifiedItems,
 *    to identify the modules specified on the command line, modules
 *    specified with qualified packages and qualified subpackages, the
 *    modules so identified are used to initialize the module system.
 *
 * C. Intermediate phase: before the final analysis can be done,
 *    intermediate methods can be used to get specified elements from
 *    the initialization phase, typically used to parse sources or packages
 *    specified on the command line.
 *
 * D. Analysis phase: the final analysis is performed to determine
 *    the packages that ought to be included, as follows:
 *
 *    1. computes the specified modules, by considering the option
 *       "expand-requires", this must be done exhaustively, as the package
 *       computation phase expects a completed module graph, in order to
 *       check the target of a qualified export is in the included set.
 *
 *    2. computes the packages that must be documented, by considering
 *       the option "show-packages", also if only exported packages are
 *       to be considered, then also check for qualified packages, and
 *       include only those packages whose target is in the included set.
 *
 *    3. compute the specified packages, as part of this, first compute
 *       the subpackages and exclude any packages, if required.
 *
 *    4. Finally, compute the types found by previous parsing steps,
 *       noting that, all enclosed types (nested types) must also be
 *       considered.
 *
 * E. Finally, this class provides methods to obtain the specified sets,
 *    which are frozen and cached in the analysis phase, the included
 *    sets, are computed lazily and cached for future use. An element
 *    can be checked if it should be documented, in which case, the
 *    element is checked against the included set and the result is
 *    cached, for performance reasons.
 *
 * Definitions:
 *    Fully included: an element is included and some or parts
 *    of it components are included implicitly, subject to a
 *    selection criteria of its enclosed children.
 *
 *    Included: if the item should be documented.
 *
 * Rules for processing:
 *
 * 1. A specified element, meaning an element given on the
 *    command-line, and exposed via specified elements collections.
 * 2. Expand-contents, an internal pseudo term, meaning
 *    it is part of the recursive expansion of specified
 *    elements, meaning, the modules are expanded first, then
 *    the packages contained in the expanded modules, and then
 *    the types contained within the packages, to produce the
 *    collections returned by the methods
 *    getInclude{Module|Package|Type}Elements(), this is a
 *    downward expansion.
 * 3. An included element, meaning it should be documented, and
 *    exposed via isIncluded, this enclosing element (module, package)
 *    is recursively included.
 */
public class ElementsTable {

    private final ToolEnvironment toolEnv;
    private final Symtab syms;
    private final Names names;
    private final JavaFileManager fm;
    private final List<Location> locations;
    private final Modules modules;
    private final Map<ToolOption, Object> opts;
    private final Messager messager;
    private final JavaCompiler compiler;

    private final Map<String, Entry> entries = new LinkedHashMap<>();

    // specified elements
    private Set<ModuleElement> specifiedModuleElements = new LinkedHashSet<>();
    private Set<PackageElement> specifiedPackageElements = new LinkedHashSet<>();
    private Set<TypeElement> specifiedTypeElements =new LinkedHashSet<>();

    // included elements
    private Set<ModuleElement> includedModuleElements = null;
    private Set<PackageElement> includedPackageElements = null;
    private Set<TypeElement> includedTypeElements = null;

    // cmdline specifiers
    private Set<ModulePackage> cmdLinePackages = new LinkedHashSet<>();
    private Set<ModulePackage> excludePackages = new LinkedHashSet<>();
    private Set<ModulePackage> subPackages = new LinkedHashSet<>();

    private List<JCClassDecl> classDecList = Collections.emptyList();
    private List<String> classArgList = Collections.emptyList();
    private com.sun.tools.javac.util.List<JCCompilationUnit> classTreeList = null;

    private final Set<JavaFileObject.Kind> sourceKinds = EnumSet.of(JavaFileObject.Kind.SOURCE);

    private final ModifierFilter accessFilter;

    private final AccessKind expandRequires;

    final boolean xclasses;

    /**
     * Creates the table to manage included and excluded elements.
     *
     * @param context the context to locate commonly used objects
     * @param location the location used to locate source files
     */
    ElementsTable(Context context, Map<ToolOption, Object> opts) {
        this.toolEnv = ToolEnvironment.instance(context);
        this.syms = Symtab.instance(context);
        this.names = Names.instance(context);
        this.fm = toolEnv.fileManager;
        this.modules = Modules.instance(context);
        this.opts = opts;
        this.messager = Messager.instance0(context);
        this.compiler = JavaCompiler.instance(context);
        Source source = Source.instance(context);

        List<Location> locs = new ArrayList<>();
        if (modules.multiModuleMode) {
            locs.add(StandardLocation.MODULE_SOURCE_PATH);
        } else {
            if (toolEnv.fileManager.hasLocation(StandardLocation.SOURCE_PATH))
                locs.add(StandardLocation.SOURCE_PATH);
            else
                locs.add(StandardLocation.CLASS_PATH);
        }
        if (Feature.MODULES.allowedInSource(source) && toolEnv.fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH))
            locs.add(StandardLocation.PATCH_MODULE_PATH);
        this.locations = Collections.unmodifiableList(locs);

        getEntry("").excluded = false;

        accessFilter = new ModifierFilter(opts);
        xclasses = (boolean)opts.getOrDefault(ToolOption.XCLASSES, false);
        expandRequires = (AccessKind)opts.get(ToolOption.EXPAND_REQUIRES);
    }

    /**
     * Returns the module documentation level mode.
     * @return the module documentation level mode
     */
    public ModuleMode getModuleMode() {
        switch(accessFilter.getAccessValue(ElementKind.MODULE)) {
            case PACKAGE: case PRIVATE:
                return DocletEnvironment.ModuleMode.ALL;
            default:
                return DocletEnvironment.ModuleMode.API;
        }
    }

    private Set<Element> specifiedElements = null;
    /**
     * Returns a set of elements specified on the
     * command line, including any inner classes.
     *
     * @return the set of elements specified on the command line
     */
    public Set<? extends Element> getSpecifiedElements() {
        if (specifiedElements == null) {
            Set<Element> result = new LinkedHashSet<>();
            result.addAll(specifiedModuleElements);
            result.addAll(specifiedPackageElements);
            result.addAll(specifiedTypeElements);
            specifiedElements = Collections.unmodifiableSet(result);
        }
        return specifiedElements;
    }

    private Set<Element> includedElements = null;
    /**
     * Returns a set of elements included elements. The inclusion is as
     * follows:
     * A module is fully included,
     *   - is specified on the command line --module
     *   - is derived from the module graph, that is, by expanding the
     *     requires directive, based on --expand-requires
     *
     * A module is included if an enclosed package or type is
     * specified on the command line.
     *
     * A package is fully included,
     *  - is specified on the command line
     *  - is derived from expanding -subpackages
     *  - can be documented in a fully included module based on --show-packages
     *
     * A package is included, if an enclosed package or a type is specified on
     * the command line.
     *
     * Included type elements (including those within specified or included packages)
     * to be documented.
     *
     * A type is fully included if
     *  - is specified on the command line with -sourcepath
     *  - is visible with --show-types filter
     * A nested type is fully included if
     *  - is visible with --show-types filter
     *  - is enclosed in a fully included type
     * @return the set of elements specified on the command line
     */
    public Set<? extends Element> getIncludedElements() {
        if (includedElements == null) {
            Set<Element> result = new LinkedHashSet<>();
            result.addAll(includedModuleElements);
            result.addAll(includedPackageElements);
            result.addAll(includedTypeElements);
            includedElements = Collections.unmodifiableSet(result);
        }
        return includedElements;
    }

    private IncludedVisitor includedVisitor = null;

    /**
     * Returns true if the given element is included for consideration.
     * This method accumulates elements in the cache as enclosed elements of
     * fully included elements are tested.
     * A member (constructor, method, field) is included if
     *  - it is visible in a fully included type (--show-members)
     *
     * @param e the element in question
     *
     * @see getIncludedModuleElements
     * @see getIncludedPackageElements
     * @see getIncludedTypeElements
     *
     * @return true if included
     */
    public boolean isIncluded(Element e) {
        if (e == null) {
            return false;
        }
        if (includedVisitor == null) {
            includedVisitor = new IncludedVisitor();
        }
        return includedVisitor.visit(e);
    }

    /**
     * Performs the final computation and freezes the collections.
     * This is a terminal operation, thus no further modifications
     * are allowed to the specified data sets.
     *
     * @throws ToolException if an error occurs
     */
    void analyze() throws ToolException {
        // compute the specified element, by expanding module dependencies
        computeSpecifiedModules();

        // compute all specified packages and subpackages
        computeSpecifiedPackages();

        // compute the specified types
        computeSpecifiedTypes();

        // compute the packages belonging to all the specified modules
        Set<PackageElement> expandedModulePackages = computeModulePackages();
        initializeIncludedSets(expandedModulePackages);
    }

    ElementsTable classTrees(com.sun.tools.javac.util.List<JCCompilationUnit> classTrees) {
        this.classTreeList = classTrees;
        return this;
    }

    /*
     * This method sanity checks the following cases:
     * a. a source-path containing a single module and many modules specified with --module
     * b. no modules on source-path
     * c. mismatched source-path and many modules specified with --module
     */
    void sanityCheckSourcePathModules(List<String> moduleNames) throws ToolException {
        if (!haveSourceLocationWithModule)
            return;

        if (moduleNames.size() > 1) {
            String text = messager.getText("main.cannot_use_sourcepath_for_modules",
                    String.join(", ", moduleNames));
            throw new ToolException(CMDERR, text);
        }

        String foundModule = getModuleName(StandardLocation.SOURCE_PATH);
        if (foundModule == null) {
            String text = messager.getText("main.module_not_found_on_sourcepath", moduleNames.get(0));
            throw new ToolException(CMDERR, text);
        }

        if (!moduleNames.get(0).equals(foundModule)) {
            String text = messager.getText("main.sourcepath_does_not_contain_module", moduleNames.get(0));
            throw new ToolException(CMDERR, text);
        }
    }

    private String getModuleName(Location location) throws ToolException {
        try {
            JavaFileObject jfo = fm.getJavaFileForInput(location,
                    "module-info", JavaFileObject.Kind.SOURCE);
            if (jfo != null) {
                JCCompilationUnit jcu = compiler.parse(jfo);
                JCModuleDecl module = TreeInfo.getModule(jcu);
                if (module != null) {
                    return module.getName().toString();
                }
            }
        } catch (IOException ioe) {
            String text = messager.getText("main.file.manager.list", location);
            throw new ToolException(SYSERR, text, ioe);
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    ElementsTable scanSpecifiedItems() throws ToolException {

        // scan modules specified on the command line
        List<String> moduleNames = (List<String>) opts.computeIfAbsent(ToolOption.MODULE,
                s -> Collections.EMPTY_LIST);
        List<String> mlist = new ArrayList<>();
        for (String m : moduleNames) {
            List<Location> moduleLocations = getModuleLocation(locations, m);
            if (moduleLocations.isEmpty()) {
                String text = messager.getText("main.module_not_found", m);
                throw new ToolException(CMDERR, text);
            }
            if (moduleLocations.contains(StandardLocation.SOURCE_PATH)) {
                sanityCheckSourcePathModules(moduleNames);
            }
            mlist.add(m);
            ModuleSymbol msym = syms.enterModule(names.fromString(m));
            specifiedModuleElements.add((ModuleElement) msym);
        }

        // scan for modules with qualified packages
        cmdLinePackages.stream()
                .filter((mpkg) -> (mpkg.hasModule()))
                .forEachOrdered((mpkg) -> {
                    mlist.add(mpkg.moduleName);
        });

        // scan for modules with qualified subpackages
        ((List<String>)opts.computeIfAbsent(ToolOption.SUBPACKAGES, v -> Collections.EMPTY_LIST))
            .stream()
            .map(ModulePackage::new)
            .forEachOrdered((mpkg) -> {
                subPackages.add(mpkg);
                if (mpkg.hasModule()) {
                    mlist.add(mpkg.moduleName);
                }
            });

        // all the modules specified on the command line have been scraped
        // init the module systems
        modules.addExtraAddModules(mlist.toArray(new String[mlist.size()]));
        modules.initModules(this.classTreeList);

        return this;
    }

    /**
     * Returns the includes table after setting a class names specified on the command line.
     *
     * @param classList
     * @return the include table
     */
    ElementsTable setClassArgList(List<String> classList) {
        classArgList = classList;
        return this;
    }

    /**
     * Returns the includes table after setting the parsed class names.
     *
     * @param classesDecList
     * @return the include table
     */
    ElementsTable setClassDeclList(List<JCClassDecl> classesDecList) {
        this.classDecList = classesDecList;
        return this;
    }

    /**
     * Returns an includes table after setting the specified package
     * names.
     * @param packageNames packages on the command line
     * @return the includes table after setting the specified package
     * names
     */
    ElementsTable packages(Collection<String> packageNames) {
        packageNames.stream()
            .map(ModulePackage::new)
            .forEachOrdered((mpkg) -> cmdLinePackages.add(mpkg));
        return this;
    }

    /**
     * Returns the aggregate set of included packages and specified
     * sub packages.
     *
     * @return the aggregate set of included packages and specified
     * sub packages
     */
    Iterable<ModulePackage> getPackagesToParse() throws IOException {
        List<ModulePackage> result = new ArrayList<>();
        result.addAll(cmdLinePackages);
        result.addAll(subPackages);
        return result;
    }

    @SuppressWarnings("unchecked")
    private void computeSubpackages() throws ToolException {
        ((List<String>) opts.computeIfAbsent(ToolOption.EXCLUDE, v -> Collections.EMPTY_LIST))
                .stream()
                .map(ModulePackage::new)
                .forEachOrdered((mpkg) -> excludePackages.add(mpkg));

        excludePackages.forEach((p) -> {
            getEntry(p).excluded = true;
        });

        for (ModulePackage modpkg : subPackages) {
            List<Location> locs = getLocation(modpkg);
            for (Location loc : locs) {
                addPackagesFromLocations(loc, modpkg);
            }
        }
    }

    /* Call fm.list and wrap any IOException that occurs in a ToolException */
    private Iterable<JavaFileObject> fmList(Location location,
                                            String packagename,
                                            Set<JavaFileObject.Kind> kinds,
                                            boolean recurse) throws ToolException {
        try {
            return fm.list(location, packagename, kinds, recurse);
        } catch (IOException ioe) {
            String text = messager.getText("main.file.manager.list", packagename);
            throw new ToolException(SYSERR, text, ioe);
        }
    }

    private void addPackagesFromLocations(Location packageLocn, ModulePackage modpkg) throws ToolException {
        for (JavaFileObject fo : fmList(packageLocn, modpkg.packageName, sourceKinds, true)) {
            String binaryName = fm.inferBinaryName(packageLocn, fo);
            String pn = getPackageName(binaryName);
            String simpleName = getSimpleName(binaryName);
            Entry e = getEntry(pn);
            if (!e.isExcluded() && isValidClassName(simpleName)) {
                ModuleSymbol msym = (modpkg.hasModule())
                        ? syms.getModule(names.fromString(modpkg.moduleName))
                        : findModuleOfPackageName(modpkg.packageName);

                if (msym != null && !msym.isUnnamed()) {
                    syms.enterPackage(msym, names.fromString(pn));
                    ModulePackage npkg = new ModulePackage(msym.toString(), pn);
                    cmdLinePackages.add(npkg);
                } else {
                    cmdLinePackages.add(e.modpkg);
                }
                e.files = (e.files == null
                        ? com.sun.tools.javac.util.List.of(fo)
                        : e.files.prepend(fo));
            }
        }
    }

    /**
     * Returns the "requires" modules for the target module.
     * @param mdle the target module element
     * @param onlyTransitive true gets all the requires transitive, otherwise
     *                 gets all the non-transitive requires
     *
     * @return a set of modules
     */
    private Set<ModuleElement> getModuleRequires(ModuleElement mdle, boolean onlyTransitive) throws ToolException {
        Set<ModuleElement> result = new HashSet<>();
        for (RequiresDirective rd : ElementFilter.requiresIn(mdle.getDirectives())) {
            ModuleElement dep = rd.getDependency();
            if (result.contains(dep))
                continue;
            if (!isMandated(mdle, rd) && onlyTransitive == rd.isTransitive()) {
                if (!haveModuleSources(dep)) {
                    messager.printWarning(dep, "main.module_not_found", dep.getSimpleName());
                }
                result.add(dep);
            } else if (isMandated(mdle, rd) && haveModuleSources(dep)) {
                result.add(dep);
            }
        }
        return result;
    }

    private boolean isMandated(ModuleElement mdle, RequiresDirective rd) {
        return toolEnv.elements.getOrigin(mdle, rd) == MANDATED;
    }

    Map<ModuleSymbol, Boolean> haveModuleSourcesCache = new HashMap<>();
    private boolean haveModuleSources(ModuleElement mdle) throws ToolException {
        ModuleSymbol msym =  (ModuleSymbol)mdle;
        if (msym.sourceLocation != null) {
            return true;
        }
        if (msym.patchLocation != null) {
            Boolean value = haveModuleSourcesCache.get(msym);
            if (value == null) {
                value = fmList(msym.patchLocation, "", sourceKinds, true).iterator().hasNext();
                haveModuleSourcesCache.put(msym, value);
            }
            return value;
        }
        return false;
    }

    private void computeSpecifiedModules() throws ToolException {
        if (expandRequires == null) { // no expansion requested
            specifiedModuleElements = Collections.unmodifiableSet(specifiedModuleElements);
            return;
        }

        final boolean expandAll = expandRequires.equals(AccessKind.PRIVATE)
                || expandRequires.equals(AccessKind.PACKAGE);

        Set<ModuleElement> result = new LinkedHashSet<>();
        ListBuffer<ModuleElement> queue = new ListBuffer<>();

        // expand each specified module
        for (ModuleElement mdle : specifiedModuleElements) {
            result.add(mdle); // a specified module is included
            queue.append(mdle);
            Set<ModuleElement> publicRequires = getModuleRequires(mdle, true);
            result.addAll(publicRequires);
            // add all requires public
            queue.addAll(publicRequires);

            if (expandAll) {
                 // add non-public requires if needed
                result.addAll(getModuleRequires(mdle, !expandAll));
            }
        }

        // compute the transitive closure of all the requires public
        for (ModuleElement m = queue.poll() ; m != null ; m = queue.poll()) {
            for (ModuleElement mdle : getModuleRequires(m, true)) {
                if (!result.contains(mdle)) {
                    result.add(mdle);
                    queue.append(mdle);
                }
            }
        }
        specifiedModuleElements = Collections.unmodifiableSet(result);
    }

    private Set<PackageElement> getAllModulePackages(ModuleElement mdle) throws ToolException {
        Set<PackageElement> result = new HashSet<>();
        ModuleSymbol msym = (ModuleSymbol) mdle;
        List<Location> msymlocs = getModuleLocation(locations, msym.name.toString());
        for (Location msymloc : msymlocs) {
            for (JavaFileObject fo : fmList(msymloc, "", sourceKinds, true)) {
                if (fo.getName().endsWith("module-info.java")) {
                    continue;
                }
                String binaryName = fm.inferBinaryName(msymloc, fo);
                String pn = getPackageName(binaryName);
                PackageSymbol psym = syms.enterPackage(msym, names.fromString(pn));
                result.add((PackageElement) psym);
            }
        }
        return result;
    }

    private Set<PackageElement> computeModulePackages() throws ToolException {
        AccessKind accessValue = accessFilter.getAccessValue(ElementKind.PACKAGE);
        final boolean documentAllModulePackages = (accessValue == AccessKind.PACKAGE ||
                accessValue == AccessKind.PRIVATE);

        accessValue = accessFilter.getAccessValue(ElementKind.MODULE);
        final boolean moduleDetailedMode = (accessValue == AccessKind.PACKAGE ||
                accessValue == AccessKind.PRIVATE);
        Set<PackageElement> expandedModulePackages = new LinkedHashSet<>();

        for (ModuleElement mdle : specifiedModuleElements) {
            if (documentAllModulePackages) { // include all packages
                List<PackageElement> packages = ElementFilter.packagesIn(mdle.getEnclosedElements());
                expandedModulePackages.addAll(packages);
                expandedModulePackages.addAll(getAllModulePackages(mdle));
            } else { // selectively include required packages
                List<ExportsDirective> exports = ElementFilter.exportsIn(mdle.getDirectives());
                for (ExportsDirective export : exports) {
                    // add if fully exported or add qualified exports only if desired
                    if (export.getTargetModules() == null
                            || documentAllModulePackages || moduleDetailedMode) {
                        expandedModulePackages.add(export.getPackage());
                    }
                }
            }

            // add all packages specified on the command line
            // belonging to this module
            if (!cmdLinePackages.isEmpty()) {
                for (ModulePackage modpkg : cmdLinePackages) {
                    PackageElement pkg = toolEnv.elements.getPackageElement(mdle,
                            modpkg.packageName);
                    if (pkg != null) {
                        expandedModulePackages.add(pkg);
                    }
                }
            }
        }
        return expandedModulePackages;
    }

    private void initializeIncludedSets(Set<PackageElement> expandedModulePackages) {

        // process modules
        Set<ModuleElement> imodules = new LinkedHashSet<>();
        // add all the expanded modules
        imodules.addAll(specifiedModuleElements);

        // process packages
        Set<PackageElement> ipackages = new LinkedHashSet<>();
        // add all packages belonging to expanded modules
        ipackages.addAll(expandedModulePackages);
        // add all specified packages
        specifiedPackageElements.forEach(pkg -> {
            ModuleElement mdle = toolEnv.elements.getModuleOf(pkg);
            if (mdle != null)
                imodules.add(mdle);
            ipackages.add(pkg);
        });

        // process types
        Set<TypeElement> iclasses = new LinkedHashSet<>();
        // add all types enclosed in expanded modules and packages
        ipackages.forEach((pkg) -> {
            addAllClasses(iclasses, pkg);
        });
        // add all types and its nested types
        specifiedTypeElements.forEach((klass) -> {
            ModuleElement mdle = toolEnv.elements.getModuleOf(klass);
            if (mdle != null && !mdle.isUnnamed())
                imodules.add(mdle);
            PackageElement pkg = toolEnv.elements.getPackageOf(klass);
            ipackages.add(pkg);
            addAllClasses(iclasses, klass, true);
        });

        // all done, freeze the collections
        includedModuleElements = Collections.unmodifiableSet(imodules);
        includedPackageElements = Collections.unmodifiableSet(ipackages);
        includedTypeElements = Collections.unmodifiableSet(iclasses);
    }

    /*
     * Computes the included packages and freezes the specified packages list.
     */
    private void computeSpecifiedPackages() throws ToolException {

        computeSubpackages();

        Set<PackageElement> packlist = new LinkedHashSet<>();
        cmdLinePackages.forEach((modpkg) -> {
            PackageElement pkg;
            if (modpkg.hasModule()) {
                ModuleElement mdle = toolEnv.elements.getModuleElement(modpkg.moduleName);
                pkg = toolEnv.elements.getPackageElement(mdle, modpkg.packageName);
            } else {
                pkg = toolEnv.elements.getPackageElement(modpkg.toString());
            }

            if (pkg != null) {
                packlist.add(pkg);
            } else {
                messager.printWarningUsingKey("main.package_not_found", modpkg.toString());
            }
        });
        specifiedPackageElements = Collections.unmodifiableSet(packlist);
    }

    /**
     * Adds all classes as well as inner classes, to the specified
     * list.
     */
    private void computeSpecifiedTypes() throws ToolException {
        Set<TypeElement> classes = new LinkedHashSet<>();
          classDecList.forEach((def) -> {
            TypeElement te = (TypeElement) def.sym;
            if (te != null) {
                addAllClasses(classes, te, true);
            }
        });
        for (String className : classArgList) {
            TypeElement te = toolEnv.loadClass(className);
            if (te == null) {
                String text = messager.getText("javadoc.class_not_found", className);
                throw new ToolException(CMDERR, text);
            } else {
                addAllClasses(classes, te, true);
            }
        }
        specifiedTypeElements = Collections.unmodifiableSet(classes);
    }

    private void addFilesForParser(Collection<JavaFileObject> result,
            Collection<ModulePackage> collection,
            boolean recurse) throws ToolException {
        for (ModulePackage modpkg : collection) {
            toolEnv.notice("main.Loading_source_files_for_package", modpkg.toString());
            List<JavaFileObject> files = getFiles(modpkg, recurse);
            if (files.isEmpty()) {
                String text = messager.getText("main.no_source_files_for_package",
                        modpkg.toString());
                throw new ToolException(CMDERR, text);
            } else {
                result.addAll(files);
            }
        }
    }

    /**
     * Returns an aggregated list of java file objects from the items
     * specified on the command line. The packages specified should not
     * recurse, however sub-packages should recurse into the sub directories.
     * @return a list of java file objects
     * @throws IOException if an error occurs
     */
    List<JavaFileObject> getFilesToParse() throws ToolException {
        List<JavaFileObject> result = new ArrayList<>();
        addFilesForParser(result, cmdLinePackages, false);
        addFilesForParser(result, subPackages, true);
        return result;
    }

    /**
     * Returns the set of source files for a package.
     *
     * @param packageName the specified package
     * @return the set of file objects for the specified package
     * @throws ToolException if an error occurs while accessing the files
     */
    private List<JavaFileObject> getFiles(ModulePackage modpkg,
            boolean recurse) throws ToolException {
        Entry e = getEntry(modpkg);
        // The files may have been found as a side effect of searching for subpackages
        if (e.files != null) {
            return e.files;
        }

        ListBuffer<JavaFileObject> lb = new ListBuffer<>();
        List<Location> locs = getLocation(modpkg);
        if (locs.isEmpty()) {
            return Collections.emptyList();
        }
        String pname = modpkg.packageName;
        for (Location packageLocn : locs) {
            for (JavaFileObject fo : fmList(packageLocn, pname, sourceKinds, recurse)) {
                String binaryName = fm.inferBinaryName(packageLocn, fo);
                String simpleName = getSimpleName(binaryName);
                if (isValidClassName(simpleName)) {
                    lb.append(fo);
                }
            }
        }
        return lb.toList();
    }

    private ModuleSymbol findModuleOfPackageName(String packageName) {
            Name pack = names.fromString(packageName);
            for (ModuleSymbol msym : modules.allModules()) {
                PackageSymbol p = syms.getPackage(msym, pack);
                if (p != null && !p.members().isEmpty()) {
                    return msym;
                }
            }
            return null;
    }

    private List<Location> getLocation(ModulePackage modpkg) throws ToolException {
        if (locations.size() == 1 && !locations.contains(StandardLocation.MODULE_SOURCE_PATH)) {
            return Collections.singletonList(locations.get(0));
        }

        if (modpkg.hasModule()) {
            return getModuleLocation(locations, modpkg.moduleName);
        }
        // TODO: handle invalid results better.
        ModuleSymbol msym = findModuleOfPackageName(modpkg.packageName);
        if (msym == null) {
            return Collections.emptyList();
        }
        return getModuleLocation(locations, msym.name.toString());
    }

    boolean haveSourceLocationWithModule = false;

    private List<Location> getModuleLocation(List<Location> locations, String msymName) throws ToolException {
        List<Location> out = new ArrayList<>();
        // search in the patch module first, this overrides others
        if (locations.contains(StandardLocation.PATCH_MODULE_PATH)) {
            Location loc = getModuleLocation(StandardLocation.PATCH_MODULE_PATH, msymName);
            if (loc != null)
                out.add(loc);
        }
        for (Location location : locations) {
            // skip patch module, already done
            if (location == StandardLocation.PATCH_MODULE_PATH) {
                continue;
            } else if (location == StandardLocation.MODULE_SOURCE_PATH) {
                Location loc = getModuleLocation(location, msymName);
                if (loc != null)
                    out.add(loc);
            } else if (location == StandardLocation.SOURCE_PATH) {
                haveSourceLocationWithModule = true;
                out.add(StandardLocation.SOURCE_PATH);
            }
        }
        return out;
    }

    private Location getModuleLocation(Location location, String msymName) throws ToolException {
        try {
            return fm.getLocationForModule(location, msymName);
        } catch (IOException ioe) {
            String text = messager.getText("main.doclet_could_not_get_location", msymName);
            throw new ToolException(ERROR, text, ioe);
        }
    }

    private Entry getEntry(String name) {
        return getEntry(new ModulePackage(name));
    }

    private Entry getEntry(ModulePackage modpkg) {
        Entry e = entries.get(modpkg.packageName);
        if (e == null) {
            entries.put(modpkg.packageName, e = new Entry(modpkg));
        }
        return e;
    }

    private String getPackageName(String name) {
        int lastDot = name.lastIndexOf(".");
        return (lastDot == -1 ? "" : name.substring(0, lastDot));
    }

    private String getSimpleName(String name) {
        int lastDot = name.lastIndexOf(".");
        return (lastDot == -1 ? name : name.substring(lastDot + 1));
    }

    /**
     * Adds all inner classes of this class, and their inner classes recursively, to the list
     */
    private void addAllClasses(Collection<TypeElement> list, TypeElement typeElement, boolean filtered) {
        ClassSymbol klass = (ClassSymbol)typeElement;
        try {
            // eliminate needless checking, do this first.
            if (list.contains(klass)) return;
            // ignore classes with invalid Java class names
            if (!JavadocTool.isValidClassName(klass.name.toString())) return;
            if (filtered && !isTypeElementSelected(klass)) return;
            list.add(klass);
            for (Symbol sym : klass.members().getSymbols(NON_RECURSIVE)) {
                if (sym != null && sym.kind == Kind.TYP) {
                    ClassSymbol s = (ClassSymbol)sym;
                    addAllClasses(list, s, filtered);
                }
            }
        } catch (CompletionFailure e) {
            if (e.getMessage() != null)
                messager.printWarning(e.getMessage());
            else
                messager.printWarningUsingKey("main.unexpected.exception", e);
        }
    }

    /**
     * Returns a list of all classes contained in this package, including
     * member classes of those classes, and their member classes, etc.
     */
    private void addAllClasses(Collection<TypeElement> list, PackageElement pkg) {
        boolean filtered = true;
        for (Element isym : pkg.getEnclosedElements()) {
            addAllClasses(list, (TypeElement)isym, filtered);
        }
    }

    private boolean isTypeElementSelected(TypeElement te) {
        return (xclasses || toolEnv.getFileKind(te) == SOURCE) && isSelected(te);
    }

    SimpleElementVisitor9<Boolean, Void> visibleElementVisitor = null;
    /**
     * Returns true if the element is selected, by applying
     * the access filter checks. Special treatment is applied to
     * types, for a top level type the access filter applies completely,
     * however if is a nested type then it is allowed either  if
     * the enclosing is a static or the enclosing is also selected.
     *
     * @param e the element to be checked
     * @return true if the element is visible
     */
    public boolean isSelected(Element e) {
        if (toolEnv.isSynthetic((Symbol) e)) {
            return false;
        }
        if (visibleElementVisitor == null) {
            visibleElementVisitor = new SimpleElementVisitor9<Boolean, Void>() {
                @Override
                public Boolean visitType(TypeElement e, Void p) {
                    if (!accessFilter.checkModifier(e)) {
                        return false; // it is not allowed
                    }
                    Element encl = e.getEnclosingElement();

                    // check if nested
                    if (encl.getKind() == ElementKind.PACKAGE)
                        return true; // top-level class, allow it

                    // is enclosed static
                    if (encl.getModifiers().contains(Modifier.STATIC))
                        return true; // allowed

                    // check the enclosing
                    return visit(encl);
                }

                @Override
                protected Boolean defaultAction(Element e, Void p) {
                    return accessFilter.checkModifier(e);
                }

                @Override
                public Boolean visitUnknown(Element e, Void p) {
                    throw new AssertionError("unkown element: " + p);
                }
            };
        }
        return visibleElementVisitor.visit(e);
    }

    private class IncludedVisitor extends SimpleElementVisitor9<Boolean, Void> {
        final private Set<Element> includedCache;

        public IncludedVisitor() {
            includedCache = new LinkedHashSet<>();
        }

        @Override
        public Boolean visitModule(ModuleElement e, Void p) {
            // deduced by specified and/or requires expansion
            return includedModuleElements.contains(e);
        }

        @Override
        public Boolean visitPackage(PackageElement e, Void p) {
            // deduced by specified or downward expansions
            return includedPackageElements.contains(e);
        }

        @Override
        public Boolean visitType(TypeElement e, Void p) {
            if (includedTypeElements.contains(e)) {
                return true;
            }
            if (isTypeElementSelected(e)) {
                // Class is nameable from top-level and
                // the class and all enclosing classes
                // pass the modifier filter.
                PackageElement pkg = toolEnv.elements.getPackageOf(e);
                if (specifiedPackageElements.contains(pkg)) {
                    return true;
                }
                Element enclosing = e.getEnclosingElement();
                if (enclosing != null) {
                    switch(enclosing.getKind()) {
                        case PACKAGE:
                            return specifiedPackageElements.contains((PackageElement)enclosing);
                        case CLASS: case INTERFACE: case ENUM: case ANNOTATION_TYPE:
                            return visit((TypeElement) enclosing);
                        default:
                            throw new AssertionError("unknown element: " + enclosing);
                    }
                }
            }
            return false;
        }

        // members
        @Override
        public Boolean defaultAction(Element e, Void p) {
            if (includedCache.contains(e))
                return true;
            if (visit(e.getEnclosingElement()) && isSelected(e)) {
                switch(e.getKind()) {
                    case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE:
                    case MODULE: case OTHER: case PACKAGE:
                        throw new AssertionError("invalid element for this operation: " + e);
                    default:
                        // the only allowed kinds in the cache are "members"
                        includedCache.add(e);
                        return true;
                }
            }
            return false;
        }

        @Override
        public Boolean visitUnknown(Element e, Void p) {
            throw new AssertionError("unknown element: " + e);
        }

    }

    class Entry {
        final ModulePackage modpkg;
        Boolean excluded = false;
        com.sun.tools.javac.util.List<JavaFileObject> files;

        Entry(ModulePackage modpkg) {
            this.modpkg = modpkg;
        }

        Entry(String name) {
            modpkg = new ModulePackage(name);
        }

        boolean isExcluded() {
            return excluded;
        }

        @Override
        public String toString() {
            return "Entry{" + "modpkg=" + modpkg + ", excluded=" + excluded + ", files=" + files + '}';
        }
    }

    /**
     * A container class to retrieve the module and package pair
     * from a parsed qualified package name.
     */
    static class ModulePackage {

        public final String moduleName;
        public final String packageName;

        ModulePackage(String modulename, String packagename) {
            this.moduleName = modulename;
            this.packageName = packagename;
        }

        ModulePackage(ModuleElement msym, String packagename) {
            this.moduleName = msym.toString();
            this.packageName = packagename;
        }

        ModulePackage(String name) {
            String a[] = name.split("/");
            if (a.length == 2) {
                this.moduleName = a[0];
                this.packageName = a[1];
            } else {
                moduleName = null;
                packageName = name;
            }
        }

        boolean hasModule() {
            return this.moduleName != null;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof ModulePackage) {
                ModulePackage that = (ModulePackage)obj;
                return this.toString().equals(that.toString());
            }
            return false;
        }

        @Override
        public int hashCode() {
             return toString().hashCode();
        }

        @Override
        public String toString() {
            return moduleName == null ? packageName : moduleName + "/" + packageName;
        }
    }

    /**
     * A class which filters the access flags on classes, fields, methods, etc.
     *
     * @see javax.lang.model.element.Modifier
     */

    static class ModifierFilter {
        /**
         * The allowed ElementKind that can be stored.
         */
        static final EnumSet<ElementKind> ALLOWED_KINDS = EnumSet.of(ElementKind.METHOD,
                                                    ElementKind.CLASS,
                                                    ElementKind.PACKAGE,
                                                    ElementKind.MODULE);

        // all possible accesss levels allowed for each element
        private final EnumMap<ElementKind, EnumSet<AccessKind>> filterMap =
                new EnumMap<>(ElementKind.class);

        // the specified access level for each element
        private final EnumMap<ElementKind, AccessKind> accessMap =
                new EnumMap<>(ElementKind.class);

        /**
         * Constructor - Specify a filter.
         *
         * @param accessSet an Access filter.
         */
        ModifierFilter(Map<ToolOption, Object> opts) {

            AccessKind accessValue = null;
            for (ElementKind kind : ALLOWED_KINDS) {
                switch (kind) {
                    case METHOD:
                        accessValue  = (AccessKind)opts.get(ToolOption.SHOW_MEMBERS);
                        break;
                    case CLASS:
                        accessValue  = (AccessKind)opts.get(ToolOption.SHOW_TYPES);
                        break;
                    case PACKAGE:
                        accessValue  = (AccessKind)opts.get(ToolOption.SHOW_PACKAGES);
                        break;
                    case MODULE:
                        accessValue  = (AccessKind)opts.get(ToolOption.SHOW_MODULE_CONTENTS);
                        break;
                    default:
                        throw new AssertionError("unknown element: " + kind);

                }
                accessMap.put(kind, accessValue);
                filterMap.put(kind, getFilterSet(accessValue));
            }
        }

        static EnumSet<AccessKind> getFilterSet(AccessKind acccessValue) {
            switch (acccessValue) {
                case PUBLIC:
                    return EnumSet.of(AccessKind.PUBLIC);
                case PROTECTED:
                default:
                    return EnumSet.of(AccessKind.PUBLIC, AccessKind.PROTECTED);
                case PACKAGE:
                    return EnumSet.of(AccessKind.PUBLIC, AccessKind.PROTECTED, AccessKind.PACKAGE);
                case PRIVATE:
                    return EnumSet.allOf(AccessKind.class);
            }
        }

        public AccessKind getAccessValue(ElementKind kind) {
            if (!ALLOWED_KINDS.contains(kind)) {
                throw new IllegalArgumentException("not allowed: " + kind);
            }
            return accessMap.getOrDefault(kind, AccessKind.PROTECTED);
        }

        /**
         * Returns true if access is allowed.
         *
         * @param e the element in question
         * @return whether the modifiers pass this filter
         */
        public boolean checkModifier(Element e) {
            Set<Modifier> modifiers = e.getModifiers();
            AccessKind fflag = AccessKind.PACKAGE;
            if (modifiers.contains(Modifier.PUBLIC)) {
                fflag = AccessKind.PUBLIC;
            } else if (modifiers.contains(Modifier.PROTECTED)) {
                fflag = AccessKind.PROTECTED;
            } else if (modifiers.contains(Modifier.PRIVATE)) {
                fflag = AccessKind.PRIVATE;
            }
            EnumSet<AccessKind> filterSet = filterMap.get(getAllowedKind(e.getKind()));
            return filterSet.contains(fflag);
        }

        // convert a requested element kind to an allowed access kind
        private ElementKind getAllowedKind(ElementKind kind) {
            switch (kind) {
                case CLASS: case METHOD: case MODULE: case PACKAGE:
                    return kind;
                case ANNOTATION_TYPE: case ENUM: case INTERFACE:
                    return ElementKind.CLASS;
                case CONSTRUCTOR: case ENUM_CONSTANT: case EXCEPTION_PARAMETER:
                case FIELD: case INSTANCE_INIT: case LOCAL_VARIABLE: case PARAMETER:
                case RESOURCE_VARIABLE: case STATIC_INIT: case TYPE_PARAMETER:
                    return ElementKind.METHOD;
                default:
                    throw new AssertionError("unsupported kind: " + kind);
            }
        }
    } // end ModifierFilter
}

jdk/javadoc/internal/tool/ElementsTable.java

 

JDK 11 jdk.jcmd.jmod - JCmd Tool

JDK 11 jdk.jartool.jmod - JAR Tool

Download and Use JDK 11

⇑⇑ FAQ for JDK (Java Development Kit)

2020-07-22, 14137👍, 0💬