1 /*
   2  * Copyright (c) 2001, 2019, 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((ModuleElement) msym);
 425         }
 426 
 427         // scan for modules with qualified packages
 428         cmdLinePackages.stream()
 429                 .filter((mpkg) -> (mpkg.hasModule()))
 430                 .forEachOrdered((mpkg) -> {
 431                     mlist.add(mpkg.moduleName);
 432         });
 433 
 434         // scan for modules with qualified subpackages
 435         options.subpackages().stream()
 436             .map(ModulePackage::new)
 437             .forEachOrdered((mpkg) -> {
 438                 subPackages.add(mpkg);
 439                 if (mpkg.hasModule()) {
 440                     mlist.add(mpkg.moduleName);
 441                 }
 442             });
 443 
 444         // all the modules specified on the command line have been scraped
 445         // init the module systems
 446         this.modules.addExtraAddModules(mlist.toArray(new String[mlist.size()]));
 447         this.modules.initModules(this.classTreeList);
 448 
 449         return this;
 450     }
 451 
 452     /**
 453      * Returns the includes table after setting a class names specified on the command line.
 454      *
 455      * @param classList
 456      * @return the include table
 457      */
 458     ElementsTable setClassArgList(List<String> classList) {
 459         classArgList = classList;
 460         return this;
 461     }
 462 
 463     /**
 464      * Returns the includes table after setting the parsed class names.
 465      *
 466      * @param classesDecList
 467      * @return the include table
 468      */
 469     ElementsTable setClassDeclList(List<JCClassDecl> classesDecList) {
 470         this.classDecList = classesDecList;
 471         return this;
 472     }
 473 
 474     /**
 475      * Returns an includes table after setting the specified package
 476      * names.
 477      * @param packageNames packages on the command line
 478      * @return the includes table after setting the specified package
 479      * names
 480      */
 481     ElementsTable packages(Collection<String> packageNames) {
 482         packageNames.stream()
 483             .map(ModulePackage::new)
 484             .forEachOrdered((mpkg) -> cmdLinePackages.add(mpkg));
 485         return this;
 486     }
 487 
 488     /**
 489      * Returns the aggregate set of included packages and specified
 490      * sub packages.
 491      *
 492      * @return the aggregate set of included packages and specified
 493      * sub packages
 494      */
 495     Iterable<ModulePackage> getPackagesToParse() throws IOException {
 496         List<ModulePackage> result = new ArrayList<>();
 497         result.addAll(cmdLinePackages);
 498         result.addAll(subPackages);
 499         return result;
 500     }
 501 
 502     private void computeSubpackages() throws ToolException {
 503         options.excludes().stream()
 504                 .map(ModulePackage::new)
 505                 .forEachOrdered((mpkg) -> excludePackages.add(mpkg));
 506 
 507         excludePackages.forEach((p) -> {
 508             getEntry(p).excluded = true;
 509         });
 510 
 511         for (ModulePackage modpkg : subPackages) {
 512             List<Location> locs = getLocation(modpkg);
 513             for (Location loc : locs) {
 514                 addPackagesFromLocations(loc, modpkg);
 515             }
 516         }
 517     }
 518 
 519     /* Call fm.list and wrap any IOException that occurs in a ToolException */
 520     private Iterable<JavaFileObject> fmList(Location location,
 521                                             String packagename,
 522                                             Set<JavaFileObject.Kind> kinds,
 523                                             boolean recurse) throws ToolException {
 524         try {
 525             return fm.list(location, packagename, kinds, recurse);
 526         } catch (IOException ioe) {
 527             String text = messager.getText("main.file.manager.list", packagename);
 528             throw new ToolException(SYSERR, text, ioe);
 529         }
 530     }
 531 
 532     private void addPackagesFromLocations(Location packageLocn, ModulePackage modpkg) throws ToolException {
 533         for (JavaFileObject fo : fmList(packageLocn, modpkg.packageName, sourceKinds, true)) {
 534             String binaryName = fm.inferBinaryName(packageLocn, fo);
 535             String pn = getPackageName(binaryName);
 536             String simpleName = getSimpleName(binaryName);
 537             Entry e = getEntry(pn);
 538             if (!e.isExcluded() && isValidClassName(simpleName)) {
 539                 ModuleSymbol msym = (modpkg.hasModule())
 540                         ? syms.getModule(names.fromString(modpkg.moduleName))
 541                         : findModuleOfPackageName(modpkg.packageName);
 542 
 543                 if (msym != null && !msym.isUnnamed()) {
 544                     syms.enterPackage(msym, names.fromString(pn));
 545                     ModulePackage npkg = new ModulePackage(msym.toString(), pn);
 546                     cmdLinePackages.add(npkg);
 547                 } else {
 548                     cmdLinePackages.add(e.modpkg);
 549                 }
 550                 e.files = (e.files == null
 551                         ? com.sun.tools.javac.util.List.of(fo)
 552                         : e.files.prepend(fo));
 553             }
 554         }
 555     }
 556 
 557     /**
 558      * Returns the "requires" modules for the target module.
 559      * @param mdle the target module element
 560      * @param onlyTransitive true gets all the requires transitive, otherwise
 561      *                 gets all the non-transitive requires
 562      *
 563      * @return a set of modules
 564      */
 565     private Set<ModuleElement> getModuleRequires(ModuleElement mdle, boolean onlyTransitive) throws ToolException {
 566         Set<ModuleElement> result = new HashSet<>();
 567         for (RequiresDirective rd : ElementFilter.requiresIn(mdle.getDirectives())) {
 568             ModuleElement dep = rd.getDependency();
 569             if (result.contains(dep))
 570                 continue;
 571             if (!isMandated(mdle, rd) && onlyTransitive == rd.isTransitive()) {
 572                 if (!haveModuleSources(dep)) {
 573                     messager.printWarning(dep, "main.module_not_found", dep.getSimpleName());
 574                 }
 575                 result.add(dep);
 576             } else if (isMandated(mdle, rd) && haveModuleSources(dep)) {
 577                 result.add(dep);
 578             }
 579         }
 580         return result;
 581     }
 582 
 583     private boolean isMandated(ModuleElement mdle, RequiresDirective rd) {
 584         return toolEnv.elements.getOrigin(mdle, rd) == MANDATED;
 585     }
 586 
 587     Map<ModuleSymbol, Boolean> haveModuleSourcesCache = new HashMap<>();
 588     private boolean haveModuleSources(ModuleElement mdle) throws ToolException {
 589         ModuleSymbol msym =  (ModuleSymbol)mdle;
 590         if (msym.sourceLocation != null) {
 591             return true;
 592         }
 593         if (msym.patchLocation != null) {
 594             Boolean value = haveModuleSourcesCache.get(msym);
 595             if (value == null) {
 596                 value = fmList(msym.patchLocation, "", sourceKinds, true).iterator().hasNext();
 597                 haveModuleSourcesCache.put(msym, value);
 598             }
 599             return value;
 600         }
 601         return false;
 602     }
 603 
 604     private void computeSpecifiedModules() throws ToolException {
 605         if (expandRequires == null) { // no expansion requested
 606             specifiedModuleElements = Collections.unmodifiableSet(specifiedModuleElements);
 607             return;
 608         }
 609 
 610         final boolean expandAll = expandRequires.equals(AccessKind.PRIVATE)
 611                 || expandRequires.equals(AccessKind.PACKAGE);
 612 
 613         Set<ModuleElement> result = new LinkedHashSet<>();
 614         ListBuffer<ModuleElement> queue = new ListBuffer<>();
 615 
 616         // expand each specified module
 617         for (ModuleElement mdle : specifiedModuleElements) {
 618             result.add(mdle); // a specified module is included
 619             queue.append(mdle);
 620             Set<ModuleElement> publicRequires = getModuleRequires(mdle, true);
 621             result.addAll(publicRequires);
 622             // add all requires public
 623             queue.addAll(publicRequires);
 624 
 625             if (expandAll) {
 626                  // add non-public requires if needed
 627                 result.addAll(getModuleRequires(mdle, !expandAll));
 628             }
 629         }
 630 
 631         // compute the transitive closure of all the requires public
 632         for (ModuleElement m = queue.poll() ; m != null ; m = queue.poll()) {
 633             for (ModuleElement mdle : getModuleRequires(m, true)) {
 634                 if (!result.contains(mdle)) {
 635                     result.add(mdle);
 636                     queue.append(mdle);
 637                 }
 638             }
 639         }
 640         specifiedModuleElements = Collections.unmodifiableSet(result);
 641     }
 642 
 643     private Set<PackageElement> getAllModulePackages(ModuleElement mdle) throws ToolException {
 644         Set<PackageElement> result = new HashSet<>();
 645         ModuleSymbol msym = (ModuleSymbol) mdle;
 646         List<Location> msymlocs = getModuleLocation(locations, msym.name.toString());
 647         for (Location msymloc : msymlocs) {
 648             for (JavaFileObject fo : fmList(msymloc, "", sourceKinds, true)) {
 649                 if (fo.getName().endsWith("module-info.java")) {
 650                     continue;
 651                 }
 652                 String binaryName = fm.inferBinaryName(msymloc, fo);
 653                 String pn = getPackageName(binaryName);
 654                 PackageSymbol psym = syms.enterPackage(msym, names.fromString(pn));
 655                 result.add((PackageElement) psym);
 656             }
 657         }
 658         return result;
 659     }
 660 
 661     private Set<PackageElement> computeModulePackages() throws ToolException {
 662         AccessKind accessValue = accessFilter.getAccessValue(ElementKind.PACKAGE);
 663         final boolean documentAllModulePackages = (accessValue == AccessKind.PACKAGE ||
 664                 accessValue == AccessKind.PRIVATE);
 665 
 666         accessValue = accessFilter.getAccessValue(ElementKind.MODULE);
 667         final boolean moduleDetailedMode = (accessValue == AccessKind.PACKAGE ||
 668                 accessValue == AccessKind.PRIVATE);
 669         Set<PackageElement> expandedModulePackages = new LinkedHashSet<>();
 670 
 671         for (ModuleElement mdle : specifiedModuleElements) {
 672             if (documentAllModulePackages) { // include all packages
 673                 List<PackageElement> packages = ElementFilter.packagesIn(mdle.getEnclosedElements());
 674                 expandedModulePackages.addAll(packages);
 675                 expandedModulePackages.addAll(getAllModulePackages(mdle));
 676             } else { // selectively include required packages
 677                 List<ExportsDirective> exports = ElementFilter.exportsIn(mdle.getDirectives());
 678                 for (ExportsDirective export : exports) {
 679                     // add if fully exported or add qualified exports only if desired
 680                     if (export.getTargetModules() == null
 681                             || documentAllModulePackages || moduleDetailedMode) {
 682                         expandedModulePackages.add(export.getPackage());
 683                     }
 684                 }
 685             }
 686 
 687             // add all packages specified on the command line
 688             // belonging to this module
 689             if (!cmdLinePackages.isEmpty()) {
 690                 for (ModulePackage modpkg : cmdLinePackages) {
 691                     PackageElement pkg = toolEnv.elements.getPackageElement(mdle,
 692                             modpkg.packageName);
 693                     if (pkg != null) {
 694                         expandedModulePackages.add(pkg);
 695                     }
 696                 }
 697             }
 698         }
 699         return expandedModulePackages;
 700     }
 701 
 702     private void initializeIncludedSets(Set<PackageElement> expandedModulePackages) {
 703 
 704         // process modules
 705         Set<ModuleElement> imodules = new LinkedHashSet<>();
 706         // add all the expanded modules
 707         imodules.addAll(specifiedModuleElements);
 708 
 709         // process packages
 710         Set<PackageElement> ipackages = new LinkedHashSet<>();
 711         // add all packages belonging to expanded modules
 712         ipackages.addAll(expandedModulePackages);
 713         // add all specified packages
 714         specifiedPackageElements.forEach(pkg -> {
 715             ModuleElement mdle = toolEnv.elements.getModuleOf(pkg);
 716             if (mdle != null)
 717                 imodules.add(mdle);
 718             ipackages.add(pkg);
 719         });
 720 
 721         // process types
 722         Set<TypeElement> iclasses = new LinkedHashSet<>();
 723         // add all types enclosed in expanded modules and packages
 724         ipackages.forEach((pkg) -> {
 725             addAllClasses(iclasses, pkg);
 726         });
 727         // add all types and its nested types
 728         specifiedTypeElements.forEach((klass) -> {
 729             ModuleElement mdle = toolEnv.elements.getModuleOf(klass);
 730             if (mdle != null && !mdle.isUnnamed())
 731                 imodules.add(mdle);
 732             PackageElement pkg = toolEnv.elements.getPackageOf(klass);
 733             ipackages.add(pkg);
 734             addAllClasses(iclasses, klass, true);
 735         });
 736 
 737         // all done, freeze the collections
 738         includedModuleElements = Collections.unmodifiableSet(imodules);
 739         includedPackageElements = Collections.unmodifiableSet(ipackages);
 740         includedTypeElements = Collections.unmodifiableSet(iclasses);
 741     }
 742 
 743     /*
 744      * Computes the included packages and freezes the specified packages list.
 745      */
 746     private void computeSpecifiedPackages() throws ToolException {
 747 
 748         computeSubpackages();
 749 
 750         Set<PackageElement> packlist = new LinkedHashSet<>();
 751         cmdLinePackages.forEach((modpkg) -> {
 752             PackageElement pkg;
 753             if (modpkg.hasModule()) {
 754                 ModuleElement mdle = toolEnv.elements.getModuleElement(modpkg.moduleName);
 755                 pkg = toolEnv.elements.getPackageElement(mdle, modpkg.packageName);
 756             } else {
 757                 pkg = toolEnv.elements.getPackageElement(modpkg.toString());
 758             }
 759 
 760             if (pkg != null) {
 761                 packlist.add(pkg);
 762             } else {
 763                 messager.printWarningUsingKey("main.package_not_found", modpkg.toString());
 764             }
 765         });
 766         specifiedPackageElements = Collections.unmodifiableSet(packlist);
 767     }
 768 
 769     /**
 770      * Adds all classes as well as inner classes, to the specified
 771      * list.
 772      */
 773     private void computeSpecifiedTypes() throws ToolException {
 774         Set<TypeElement> classes = new LinkedHashSet<>();
 775           classDecList.forEach((def) -> {
 776             TypeElement te = (TypeElement) def.sym;
 777             if (te != null) {
 778                 addAllClasses(classes, te, true);
 779             }
 780         });
 781         for (String className : classArgList) {
 782             TypeElement te = toolEnv.loadClass(className);
 783             if (te == null) {
 784                 String text = messager.getText("javadoc.class_not_found", className);
 785                 throw new ToolException(CMDERR, text);
 786             } else {
 787                 addAllClasses(classes, te, true);
 788             }
 789         }
 790         specifiedTypeElements = Collections.unmodifiableSet(classes);
 791     }
 792 
 793     private void addFilesForParser(Collection<JavaFileObject> result,
 794             Collection<ModulePackage> collection,
 795             boolean recurse) throws ToolException {
 796         for (ModulePackage modpkg : collection) {
 797             toolEnv.notice("main.Loading_source_files_for_package", modpkg.toString());
 798             List<JavaFileObject> files = getFiles(modpkg, recurse);
 799             if (files.isEmpty()) {
 800                 String text = messager.getText("main.no_source_files_for_package",
 801                         modpkg.toString());
 802                 throw new ToolException(CMDERR, text);
 803             } else {
 804                 result.addAll(files);
 805             }
 806         }
 807     }
 808 
 809     /**
 810      * Returns an aggregated list of java file objects from the items
 811      * specified on the command line. The packages specified should not
 812      * recurse, however sub-packages should recurse into the sub directories.
 813      * @return a list of java file objects
 814      * @throws IOException if an error occurs
 815      */
 816     List<JavaFileObject> getFilesToParse() throws ToolException {
 817         List<JavaFileObject> result = new ArrayList<>();
 818         addFilesForParser(result, cmdLinePackages, false);
 819         addFilesForParser(result, subPackages, true);
 820         return result;
 821     }
 822 
 823     /**
 824      * Returns the set of source files for a package.
 825      *
 826      * @param modpkg the specified package
 827      * @return the set of file objects for the specified package
 828      * @throws ToolException if an error occurs while accessing the files
 829      */
 830     private List<JavaFileObject> getFiles(ModulePackage modpkg,
 831             boolean recurse) throws ToolException {
 832         Entry e = getEntry(modpkg);
 833         // The files may have been found as a side effect of searching for subpackages
 834         if (e.files != null) {
 835             return e.files;
 836         }
 837 
 838         ListBuffer<JavaFileObject> lb = new ListBuffer<>();
 839         List<Location> locs = getLocation(modpkg);
 840         if (locs.isEmpty()) {
 841             return Collections.emptyList();
 842         }
 843         String pname = modpkg.packageName;
 844         for (Location packageLocn : locs) {
 845             for (JavaFileObject fo : fmList(packageLocn, pname, sourceKinds, recurse)) {
 846                 String binaryName = fm.inferBinaryName(packageLocn, fo);
 847                 String simpleName = getSimpleName(binaryName);
 848                 if (isValidClassName(simpleName)) {
 849                     lb.append(fo);
 850                 }
 851             }
 852         }
 853         return lb.toList();
 854     }
 855 
 856     private ModuleSymbol findModuleOfPackageName(String packageName) {
 857             Name pack = names.fromString(packageName);
 858             for (ModuleSymbol msym : modules.allModules()) {
 859                 PackageSymbol p = syms.getPackage(msym, pack);
 860                 if (p != null && !p.members().isEmpty()) {
 861                     return msym;
 862                 }
 863             }
 864             return null;
 865     }
 866 
 867     private List<Location> getLocation(ModulePackage modpkg) throws ToolException {
 868         if (locations.size() == 1 && !locations.contains(StandardLocation.MODULE_SOURCE_PATH)) {
 869             return Collections.singletonList(locations.get(0));
 870         }
 871 
 872         if (modpkg.hasModule()) {
 873             return getModuleLocation(locations, modpkg.moduleName);
 874         }
 875         // TODO: handle invalid results better.
 876         ModuleSymbol msym = findModuleOfPackageName(modpkg.packageName);
 877         if (msym == null) {
 878             return Collections.emptyList();
 879         }
 880         return getModuleLocation(locations, msym.name.toString());
 881     }
 882 
 883     boolean haveSourceLocationWithModule = false;
 884 
 885     private List<Location> getModuleLocation(List<Location> locations, String msymName) throws ToolException {
 886         List<Location> out = new ArrayList<>();
 887         // search in the patch module first, this overrides others
 888         if (locations.contains(StandardLocation.PATCH_MODULE_PATH)) {
 889             Location loc = getModuleLocation(StandardLocation.PATCH_MODULE_PATH, msymName);
 890             if (loc != null)
 891                 out.add(loc);
 892         }
 893         for (Location location : locations) {
 894             // skip patch module, already done
 895             if (location == StandardLocation.PATCH_MODULE_PATH) {
 896                 continue;
 897             } else if (location == StandardLocation.MODULE_SOURCE_PATH) {
 898                 Location loc = getModuleLocation(location, msymName);
 899                 if (loc != null)
 900                     out.add(loc);
 901             } else if (location == StandardLocation.SOURCE_PATH) {
 902                 haveSourceLocationWithModule = true;
 903                 out.add(StandardLocation.SOURCE_PATH);
 904             }
 905         }
 906         return out;
 907     }
 908 
 909     private Location getModuleLocation(Location location, String msymName) throws ToolException {
 910         try {
 911             return fm.getLocationForModule(location, msymName);
 912         } catch (IOException ioe) {
 913             String text = messager.getText("main.doclet_could_not_get_location", msymName);
 914             throw new ToolException(ERROR, text, ioe);
 915         }
 916     }
 917 
 918     private Entry getEntry(String name) {
 919         return getEntry(new ModulePackage(name));
 920     }
 921 
 922     private Entry getEntry(ModulePackage modpkg) {
 923         Entry e = entries.get(modpkg.packageName);
 924         if (e == null) {
 925             entries.put(modpkg.packageName, e = new Entry(modpkg));
 926         }
 927         return e;
 928     }
 929 
 930     private String getPackageName(String name) {
 931         int lastDot = name.lastIndexOf(".");
 932         return (lastDot == -1 ? "" : name.substring(0, lastDot));
 933     }
 934 
 935     private String getSimpleName(String name) {
 936         int lastDot = name.lastIndexOf(".");
 937         return (lastDot == -1 ? name : name.substring(lastDot + 1));
 938     }
 939 
 940     /**
 941      * Adds all inner classes of this class, and their inner classes recursively, to the list
 942      */
 943     private void addAllClasses(Collection<TypeElement> list, TypeElement typeElement, boolean filtered) {
 944         ClassSymbol klass = (ClassSymbol)typeElement;
 945         try {
 946             // eliminate needless checking, do this first.
 947             if (list.contains(klass)) return;
 948             // ignore classes with invalid Java class names
 949             if (!JavadocTool.isValidClassName(klass.name.toString())) return;
 950             if (filtered && !isTypeElementSelected(klass)) return;
 951             list.add(klass);
 952             for (Symbol sym : klass.members().getSymbols(NON_RECURSIVE)) {
 953                 if (sym != null && sym.kind == Kind.TYP) {
 954                     ClassSymbol s = (ClassSymbol)sym;
 955                     addAllClasses(list, s, filtered);
 956                 }
 957             }
 958         } catch (CompletionFailure e) {
 959             if (e.getMessage() != null)
 960                 messager.printWarning(e.getMessage());
 961             else
 962                 messager.printWarningUsingKey("main.unexpected.exception", e);
 963         }
 964     }
 965 
 966     /**
 967      * Returns a list of all classes contained in this package, including
 968      * member classes of those classes, and their member classes, etc.
 969      */
 970     private void addAllClasses(Collection<TypeElement> list, PackageElement pkg) {
 971         boolean filtered = true;
 972         for (Element isym : pkg.getEnclosedElements()) {
 973             addAllClasses(list, (TypeElement)isym, filtered);
 974         }
 975     }
 976 
 977     private boolean isTypeElementSelected(TypeElement te) {
 978         return (xclasses || toolEnv.getFileKind(te) == SOURCE) && isSelected(te);
 979     }
 980 
 981     @SuppressWarnings("preview")
 982     SimpleElementVisitor14<Boolean, Void> visibleElementVisitor = null;
 983     /**
 984      * Returns true if the element is selected, by applying
 985      * the access filter checks. Special treatment is applied to
 986      * types, for a top level type the access filter applies completely,
 987      * however if is a nested type then it is allowed either  if
 988      * the enclosing is a static or the enclosing is also selected.
 989      *
 990      * @param e the element to be checked
 991      * @return true if the element is visible
 992      */
 993     @SuppressWarnings("preview")
 994     public boolean isSelected(Element e) {
 995         if (toolEnv.isSynthetic((Symbol) e)) {
 996             return false;
 997         }
 998         if (visibleElementVisitor == null) {
 999             visibleElementVisitor = new SimpleElementVisitor14<Boolean, Void>() {
1000                 @Override
1001                 public Boolean visitType(TypeElement e, Void p) {
1002                     if (!accessFilter.checkModifier(e)) {
1003                         return false; // it is not allowed
1004                     }
1005                     Element encl = e.getEnclosingElement();
1006 
1007                     // check if nested
1008                     if (encl.getKind() == ElementKind.PACKAGE)
1009                         return true; // top-level class, allow it
1010 
1011                     // is enclosed static
1012                     if (encl.getModifiers().contains(Modifier.STATIC))
1013                         return true; // allowed
1014 
1015                     // check the enclosing
1016                     return visit(encl);
1017                 }
1018 
1019                 @Override
1020                 protected Boolean defaultAction(Element e, Void p) {
1021                     return accessFilter.checkModifier(e);
1022                 }
1023 
1024                 @Override
1025                 public Boolean visitUnknown(Element e, Void p) {
1026                     throw new AssertionError("unknown element: " + e);
1027                 }
1028             };
1029         }
1030         return visibleElementVisitor.visit(e);
1031     }
1032 
1033     @SuppressWarnings("preview")
1034     private class IncludedVisitor extends SimpleElementVisitor14<Boolean, Void> {
1035         private final Set<Element> includedCache;
1036 
1037         public IncludedVisitor() {
1038             includedCache = new LinkedHashSet<>();
1039         }
1040 
1041         @Override
1042         public Boolean visitModule(ModuleElement e, Void p) {
1043             // deduced by specified and/or requires expansion
1044             return includedModuleElements.contains(e);
1045         }
1046 
1047         @Override
1048         public Boolean visitPackage(PackageElement e, Void p) {
1049             // deduced by specified or downward expansions
1050             return includedPackageElements.contains(e);
1051         }
1052 
1053         @Override
1054         public Boolean visitType(TypeElement e, Void p) {
1055             if (includedTypeElements.contains(e)) {
1056                 return true;
1057             }
1058             if (isTypeElementSelected(e)) {
1059                 // Class is nameable from top-level and
1060                 // the class and all enclosing classes
1061                 // pass the modifier filter.
1062                 PackageElement pkg = toolEnv.elements.getPackageOf(e);
1063                 if (specifiedPackageElements.contains(pkg)) {
1064                     return true;
1065                 }
1066                 Element enclosing = e.getEnclosingElement();
1067                 if (enclosing != null) {
1068                     switch(enclosing.getKind()) {
1069                         case PACKAGE:
1070                             return specifiedPackageElements.contains((PackageElement)enclosing);
1071                         case CLASS: case INTERFACE: case ENUM: case ANNOTATION_TYPE:
1072                             return visit((TypeElement) enclosing);
1073                         default:
1074                             throw new AssertionError("unknown element: " + enclosing);
1075                     }
1076                 }
1077             }
1078             return false;
1079         }
1080 
1081         // members
1082         @Override
1083         public Boolean defaultAction(Element e, Void p) {
1084             if (includedCache.contains(e))
1085                 return true;
1086             if (visit(e.getEnclosingElement()) && isSelected(e)) {
1087                 switch(e.getKind()) {
1088                     case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE:
1089                     case MODULE: case OTHER: case PACKAGE:
1090                         throw new AssertionError("invalid element for this operation: " + e);
1091                     default:
1092                         // the only allowed kinds in the cache are "members"
1093                         includedCache.add(e);
1094                         return true;
1095                 }
1096             }
1097             return false;
1098         }
1099 
1100         @Override
1101         public Boolean visitUnknown(Element e, Void p) {
1102             throw new AssertionError("unknown element: " + e);
1103         }
1104 
1105     }
1106 
1107     class Entry {
1108         final ModulePackage modpkg;
1109         Boolean excluded = false;
1110         com.sun.tools.javac.util.List<JavaFileObject> files;
1111 
1112         Entry(ModulePackage modpkg) {
1113             this.modpkg = modpkg;
1114         }
1115 
1116         Entry(String name) {
1117             modpkg = new ModulePackage(name);
1118         }
1119 
1120         boolean isExcluded() {
1121             return excluded;
1122         }
1123 
1124         @Override
1125         public String toString() {
1126             return "Entry{" + "modpkg=" + modpkg + ", excluded=" + excluded + ", files=" + files + '}';
1127         }
1128     }
1129 
1130     /**
1131      * A container class to retrieve the module and package pair
1132      * from a parsed qualified package name.
1133      */
1134     static class ModulePackage {
1135 
1136         public final String moduleName;
1137         public final String packageName;
1138 
1139         ModulePackage(String modulename, String packagename) {
1140             this.moduleName = modulename;
1141             this.packageName = packagename;
1142         }
1143 
1144         ModulePackage(ModuleElement msym, String packagename) {
1145             this.moduleName = msym.toString();
1146             this.packageName = packagename;
1147         }
1148 
1149         ModulePackage(String name) {
1150             String a[] = name.split("/");
1151             if (a.length == 2) {
1152                 this.moduleName = a[0];
1153                 this.packageName = a[1];
1154             } else {
1155                 moduleName = null;
1156                 packageName = name;
1157             }
1158         }
1159 
1160         boolean hasModule() {
1161             return this.moduleName != null;
1162         }
1163 
1164         @Override
1165         public boolean equals(Object obj) {
1166             if (obj instanceof ModulePackage) {
1167                 ModulePackage that = (ModulePackage)obj;
1168                 return this.toString().equals(that.toString());
1169             }
1170             return false;
1171         }
1172 
1173         @Override
1174         public int hashCode() {
1175              return toString().hashCode();
1176         }
1177 
1178         @Override
1179         public String toString() {
1180             return moduleName == null ? packageName : moduleName + "/" + packageName;
1181         }
1182     }
1183 
1184     /**
1185      * A class which filters the access flags on classes, fields, methods, etc.
1186      *
1187      * @see javax.lang.model.element.Modifier
1188      */
1189 
1190     static class ModifierFilter {
1191         /**
1192          * The allowed ElementKind that can be stored.
1193          */
1194         static final EnumSet<ElementKind> ALLOWED_KINDS = EnumSet.of(ElementKind.METHOD,
1195                                                     ElementKind.CLASS,
1196                                                     ElementKind.PACKAGE,
1197                                                     ElementKind.MODULE);
1198 
1199         // all possible access levels allowed for each element
1200         private final EnumMap<ElementKind, EnumSet<AccessKind>> filterMap =
1201                 new EnumMap<>(ElementKind.class);
1202 
1203         // the specified access level for each element
1204         private final EnumMap<ElementKind, AccessKind> accessMap =
1205                 new EnumMap<>(ElementKind.class);
1206 
1207         /**
1208          * Constructor - Specify a filter.
1209          *
1210          * @param options the tool options
1211          */
1212         ModifierFilter(ToolOptions options) {
1213 
1214             AccessKind accessValue = null;
1215             for (ElementKind kind : ALLOWED_KINDS) {
1216                 switch (kind) {
1217                     case METHOD:
1218                         accessValue  = options.showMembersAccess();
1219                         break;
1220                     case CLASS:
1221                         accessValue  = options.showTypesAccess();
1222                         break;
1223                     case PACKAGE:
1224                         accessValue  = options.showPackagesAccess();
1225                         break;
1226                     case MODULE:
1227                         accessValue  = options.showModuleContents();
1228                         break;
1229                     default:
1230                         throw new AssertionError("unknown element: " + kind);
1231 
1232                 }
1233                 accessMap.put(kind, accessValue);
1234                 filterMap.put(kind, getFilterSet(accessValue));
1235             }
1236         }
1237 
1238         static EnumSet<AccessKind> getFilterSet(AccessKind accessValue) {
1239             switch (accessValue) {
1240                 case PUBLIC:
1241                     return EnumSet.of(AccessKind.PUBLIC);
1242                 case PROTECTED:
1243                 default:
1244                     return EnumSet.of(AccessKind.PUBLIC, AccessKind.PROTECTED);
1245                 case PACKAGE:
1246                     return EnumSet.of(AccessKind.PUBLIC, AccessKind.PROTECTED, AccessKind.PACKAGE);
1247                 case PRIVATE:
1248                     return EnumSet.allOf(AccessKind.class);
1249             }
1250         }
1251 
1252         public AccessKind getAccessValue(ElementKind kind) {
1253             if (!ALLOWED_KINDS.contains(kind)) {
1254                 throw new IllegalArgumentException("not allowed: " + kind);
1255             }
1256             return accessMap.getOrDefault(kind, AccessKind.PROTECTED);
1257         }
1258 
1259         /**
1260          * Returns true if access is allowed.
1261          *
1262          * @param e the element in question
1263          * @return whether the modifiers pass this filter
1264          */
1265         public boolean checkModifier(Element e) {
1266             Set<Modifier> modifiers = e.getModifiers();
1267             AccessKind fflag = AccessKind.PACKAGE;
1268             if (modifiers.contains(Modifier.PUBLIC)) {
1269                 fflag = AccessKind.PUBLIC;
1270             } else if (modifiers.contains(Modifier.PROTECTED)) {
1271                 fflag = AccessKind.PROTECTED;
1272             } else if (modifiers.contains(Modifier.PRIVATE)) {
1273                 fflag = AccessKind.PRIVATE;
1274             }
1275             EnumSet<AccessKind> filterSet = filterMap.get(getAllowedKind(e.getKind()));
1276             return filterSet.contains(fflag);
1277         }
1278 
1279         // convert a requested element kind to an allowed access kind
1280         private ElementKind getAllowedKind(ElementKind kind) {
1281             switch (kind) {
1282                 case CLASS: case METHOD: case MODULE: case PACKAGE:
1283                     return kind;
1284                 case RECORD: case ANNOTATION_TYPE: case ENUM: case INTERFACE:
1285                     return ElementKind.CLASS;
1286                 case CONSTRUCTOR: case ENUM_CONSTANT: case EXCEPTION_PARAMETER:
1287                 case FIELD: case INSTANCE_INIT: case LOCAL_VARIABLE: case PARAMETER:
1288                 case RESOURCE_VARIABLE: case STATIC_INIT: case TYPE_PARAMETER:
1289                     return ElementKind.METHOD;
1290                 default:
1291                     throw new AssertionError("unsupported kind: " + kind);
1292             }
1293         }
1294     } // end ModifierFilter
1295 }