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