src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java
author Dusan Balek <dbalek@netbeans.org>
Mon, 31 Jul 2017 11:07:41 +0200
changeset 5955 f54cccaf6e6c
parent 5951 e1bdd2b27bfc
permissions -rw-r--r--
Mergin jlahoda's fix of #8182450: javac aborts when generating ct.sym intermittently - Initialize the module system model even in presence of missing/broken module-infos; BadClassFiles should not immediatelly abort compilation anymore, but should be handled as if the classfile did not exist.
     1 /*
     2  * Copyright (c) 2009, 2017, 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 
    26 
    27 package com.sun.tools.javac.comp;
    28 
    29 import java.io.IOException;
    30 import java.util.Arrays;
    31 import java.util.Collection;
    32 import java.util.Collections;
    33 import java.util.EnumSet;
    34 import java.util.HashMap;
    35 import java.util.HashSet;
    36 import java.util.LinkedHashMap;
    37 import java.util.LinkedHashSet;
    38 import java.util.Map;
    39 import java.util.Set;
    40 import java.util.function.Consumer;
    41 import java.util.function.Predicate;
    42 import java.util.regex.Matcher;
    43 import java.util.regex.Pattern;
    44 import java.util.stream.Collectors;
    45 import java.util.stream.Stream;
    46 
    47 import javax.lang.model.SourceVersion;
    48 import javax.tools.JavaFileManager;
    49 import javax.tools.JavaFileManager.Location;
    50 import javax.tools.JavaFileObject;
    51 import javax.tools.JavaFileObject.Kind;
    52 import javax.tools.StandardLocation;
    53 
    54 import com.sun.source.tree.ModuleTree.ModuleKind;
    55 import com.sun.tools.javac.code.ClassFinder;
    56 import com.sun.tools.javac.code.DeferredLintHandler;
    57 import com.sun.tools.javac.code.Directive;
    58 import com.sun.tools.javac.code.Directive.ExportsDirective;
    59 import com.sun.tools.javac.code.Directive.ExportsFlag;
    60 import com.sun.tools.javac.code.Directive.OpensDirective;
    61 import com.sun.tools.javac.code.Directive.OpensFlag;
    62 import com.sun.tools.javac.code.Directive.RequiresDirective;
    63 import com.sun.tools.javac.code.Directive.RequiresFlag;
    64 import com.sun.tools.javac.code.Directive.UsesDirective;
    65 import com.sun.tools.javac.code.Flags;
    66 import com.sun.tools.javac.code.Lint.LintCategory;
    67 import com.sun.tools.javac.code.ModuleFinder;
    68 import com.sun.tools.javac.code.Source;
    69 import com.sun.tools.javac.code.Symbol;
    70 import com.sun.tools.javac.code.Symbol.ClassSymbol;
    71 import com.sun.tools.javac.code.Symbol.Completer;
    72 import com.sun.tools.javac.code.Symbol.CompletionFailure;
    73 import com.sun.tools.javac.code.Symbol.MethodSymbol;
    74 import com.sun.tools.javac.code.Symbol.ModuleFlags;
    75 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
    76 import com.sun.tools.javac.code.Symbol.PackageSymbol;
    77 import com.sun.tools.javac.code.Symtab;
    78 import com.sun.tools.javac.code.Type;
    79 import com.sun.tools.javac.code.Types;
    80 import com.sun.tools.javac.jvm.ClassWriter;
    81 import com.sun.tools.javac.jvm.JNIWriter;
    82 import com.sun.tools.javac.main.Option;
    83 import com.sun.tools.javac.resources.CompilerProperties.Errors;
    84 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
    85 import com.sun.tools.javac.tree.JCTree;
    86 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
    87 import com.sun.tools.javac.tree.JCTree.JCDirective;
    88 import com.sun.tools.javac.tree.JCTree.JCExports;
    89 import com.sun.tools.javac.tree.JCTree.JCExpression;
    90 import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
    91 import com.sun.tools.javac.tree.JCTree.JCOpens;
    92 import com.sun.tools.javac.tree.JCTree.JCProvides;
    93 import com.sun.tools.javac.tree.JCTree.JCRequires;
    94 import com.sun.tools.javac.tree.JCTree.JCUses;
    95 import com.sun.tools.javac.tree.JCTree.Tag;
    96 import com.sun.tools.javac.tree.TreeInfo;
    97 import com.sun.tools.javac.util.Assert;
    98 import com.sun.tools.javac.util.Context;
    99 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
   100 import com.sun.tools.javac.util.List;
   101 import com.sun.tools.javac.util.ListBuffer;
   102 import com.sun.tools.javac.util.Log;
   103 import com.sun.tools.javac.util.Name;
   104 import com.sun.tools.javac.util.Names;
   105 import com.sun.tools.javac.util.Options;
   106 
   107 import static com.sun.tools.javac.code.Flags.ABSTRACT;
   108 import static com.sun.tools.javac.code.Flags.ENUM;
   109 import static com.sun.tools.javac.code.Flags.PUBLIC;
   110 import static com.sun.tools.javac.code.Flags.UNATTRIBUTED;
   111 import com.sun.tools.javac.code.Kinds;
   112 import static com.sun.tools.javac.code.Kinds.Kind.ERR;
   113 import static com.sun.tools.javac.code.Kinds.Kind.MDL;
   114 import static com.sun.tools.javac.code.Kinds.Kind.MTH;
   115 import com.sun.tools.javac.code.Symbol.ModuleResolutionFlags;
   116 import static com.sun.tools.javac.code.TypeTag.CLASS;
   117 
   118 /**
   119  *  TODO: fill in
   120  *
   121  *  <p><b>This is NOT part of any supported API.
   122  *  If you write code that depends on this, you do so at your own risk.
   123  *  This code and its internal interfaces are subject to change or
   124  *  deletion without notice.</b>
   125  */
   126 public class Modules extends JCTree.Visitor {
   127     private static final String ALL_SYSTEM = "ALL-SYSTEM";
   128     private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
   129 
   130     private final Log log;
   131     private final Names names;
   132     private final Symtab syms;
   133     private final Attr attr;
   134     private final Check chk;
   135     private final DeferredLintHandler deferredLintHandler;
   136     private final TypeEnvs typeEnvs;
   137     private final Types types;
   138     private final JavaFileManager fileManager;
   139     private final ModuleFinder moduleFinder;
   140     private final Source source;
   141     private final boolean allowModules;
   142 
   143     public final boolean multiModuleMode;
   144 
   145     private final String legacyModuleOverride;
   146 
   147     private final Name java_se;
   148     private final Name java_;
   149 
   150     ModuleSymbol defaultModule;
   151 
   152     private final String addExportsOpt;
   153     private Map<ModuleSymbol, Set<ExportsDirective>> addExports;
   154     private final String addReadsOpt;
   155     private Map<ModuleSymbol, Set<RequiresDirective>> addReads;
   156     private final String addModsOpt;
   157     private final Set<String> extraAddMods = new HashSet<>();
   158     private final String limitModsOpt;
   159     private final Set<String> extraLimitMods = new HashSet<>();
   160     private final String moduleVersionOpt;
   161 
   162     private final boolean lintOptions;
   163     private final boolean backgroundCompilation;
   164     private final boolean ideMode;
   165     private final JavaFileManager fm;
   166 
   167     private Set<ModuleSymbol> rootModules = null;
   168     private final Set<ModuleSymbol> warnedMissing = new HashSet<>();
   169 
   170     public PackageNameFinder findPackageInFile;
   171 
   172     public static Modules instance(Context context) {
   173         Modules instance = context.get(Modules.class);
   174         if (instance == null)
   175             instance = new Modules(context);
   176         return instance;
   177     }
   178 
   179     protected Modules(Context context) {
   180         context.put(Modules.class, this);
   181         log = Log.instance(context);
   182         names = Names.instance(context);
   183         syms = Symtab.instance(context);
   184         attr = Attr.instance(context);
   185         chk = Check.instance(context);
   186         deferredLintHandler = DeferredLintHandler.instance(context);
   187         typeEnvs = TypeEnvs.instance(context);
   188         moduleFinder = ModuleFinder.instance(context);
   189         types = Types.instance(context);
   190         fileManager = context.get(JavaFileManager.class);
   191         source = Source.instance(context);
   192         allowModules = source.allowModules();
   193         Options options = Options.instance(context);
   194 
   195         lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option);
   196 
   197         Collection<String> xmodules = options.keySet()
   198                                              .stream()
   199                                              .filter(opt -> opt.startsWith(XMODULES_PREFIX))
   200                                              .map(opt -> opt.substring(XMODULES_PREFIX.length()))
   201                                              .collect(Collectors.toList());
   202 
   203         legacyModuleOverride = xmodules.size() == 1 ? xmodules.iterator().next() : null;
   204 
   205         multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH);
   206         ClassWriter classWriter = ClassWriter.instance(context);
   207         classWriter.multiModuleMode = multiModuleMode;
   208         JNIWriter jniWriter = JNIWriter.instance(context);
   209         jniWriter.multiModuleMode = multiModuleMode;
   210 
   211         java_se = names.fromString("java.se");
   212         java_ = names.fromString("java.");
   213 
   214         addExportsOpt = options.get(Option.ADD_EXPORTS);
   215         addReadsOpt = options.get(Option.ADD_READS);
   216         addModsOpt = options.get(Option.ADD_MODULES);
   217         limitModsOpt = options.get(Option.LIMIT_MODULES);
   218         moduleVersionOpt = options.get(Option.MODULE_VERSION);
   219 
   220         fm = context.get(JavaFileManager.class);
   221         backgroundCompilation = options.get("backgroundCompilation") != null;
   222         ideMode = options.get("ide") != null;
   223     }
   224     //where
   225         private static final String XMODULES_PREFIX = "-Xmodule:";
   226 
   227     int depth = -1;
   228     private void dprintln(String msg) {
   229         for (int i = 0; i < depth; i++)
   230             System.err.print("  ");
   231         System.err.println(msg);
   232     }
   233 
   234     public void addExtraAddModules(String... extras) {
   235         extraAddMods.addAll(Arrays.asList(extras));
   236     }
   237 
   238     public void addExtraLimitModules(String... extras) {
   239         extraLimitMods.addAll(Arrays.asList(extras));
   240     }
   241 
   242     boolean inInitModules;
   243     public void initModules(List<JCCompilationUnit> trees) {
   244         Assert.check(!inInitModules);
   245         try {
   246             inInitModules = true;
   247             if (rootModules == null) {
   248                 enter(trees, modules -> {
   249                     Assert.checkNull(rootModules);
   250                     Assert.checkNull(allModules);
   251                     this.rootModules = modules;
   252                     setupAllModules(); //initialize the module graph
   253                     Assert.checkNonNull(allModules);
   254                     inInitModules = false;
   255                 }, null);
   256             } else {
   257                 enter(trees, null);
   258             }
   259         } finally {
   260             inInitModules = false;
   261         }
   262     }
   263 
   264     public boolean enter(List<JCCompilationUnit> trees, ClassSymbol c) {
   265         Assert.check(rootModules != null || inInitModules || !allowModules);
   266         return enter(trees, modules -> {}, c);
   267     }
   268 
   269     private boolean enter(List<JCCompilationUnit> trees, Consumer<Set<ModuleSymbol>> init, ClassSymbol c) {
   270         if (!allowModules) {
   271             for (JCCompilationUnit tree: trees) {
   272                 tree.modle = syms.noModule;
   273             }
   274             defaultModule = syms.noModule;
   275             return true;
   276         }
   277 
   278         int startErrors = log.nerrors;
   279 
   280         depth++;
   281         try {
   282             // scan trees for module defs
   283             Set<ModuleSymbol> roots = enterModules(trees, c);
   284 
   285             setCompilationUnitModules(trees, roots, c);
   286 
   287             init.accept(roots);
   288 
   289             for (ModuleSymbol msym: roots) {
   290                 msym.complete();
   291             }
   292         } catch (CompletionFailure ex) {
   293             chk.completionError(null, ex);
   294         } finally {
   295             depth--;
   296         }
   297 
   298         return (log.nerrors == startErrors);
   299     }
   300 
   301     public Completer getCompleter() {
   302         return mainCompleter;
   303     }
   304 
   305     public ModuleSymbol getDefaultModule() {
   306         return defaultModule;
   307     }
   308 
   309     public boolean modulesInitialized() {
   310         return allModules != null;
   311     }
   312 
   313     private Set<ModuleSymbol> enterModules(List<JCCompilationUnit> trees, ClassSymbol c) {
   314         Set<ModuleSymbol> modules = new LinkedHashSet<>();
   315         for (JCCompilationUnit tree : trees) {
   316             JavaFileObject prev = log.useSource(tree.sourcefile);
   317             try {
   318                 enterModule(tree, c, modules);
   319             } finally {
   320                 log.useSource(prev);
   321             }
   322         }
   323         return modules;
   324     }
   325 
   326 
   327     private void enterModule(JCCompilationUnit toplevel, ClassSymbol c, Set<ModuleSymbol> modules) {
   328         boolean isModuleInfo = toplevel.sourcefile.isNameCompatible("module-info", Kind.SOURCE);
   329         boolean isModuleDecl = toplevel.getModuleDecl() != null;
   330         if (isModuleDecl) {
   331             JCModuleDecl decl = toplevel.getModuleDecl();
   332             if (!isModuleInfo) {
   333                 log.error(decl.pos(), Errors.ModuleDeclSbInModuleInfoJava);
   334             }
   335             Name name = TreeInfo.fullName(decl.qualId);
   336             ModuleSymbol sym;
   337             if (c != null) {
   338                 sym = (ModuleSymbol) c.owner;
   339                 Assert.checkNonNull(sym.name);
   340                 Name treeName = TreeInfo.fullName(decl.qualId);
   341                 if (sym.name != treeName) {
   342                     log.error(decl.pos(), Errors.ModuleNameMismatch(name, sym.name));
   343                 }
   344             } else {
   345                 sym = syms.enterModule(name);
   346                 if ((sym.flags_field & Flags.FROMCLASS) == 0 && sym.module_info.sourcefile != null && sym.module_info.sourcefile != toplevel.sourcefile) {
   347                     log.error(decl.pos(), Errors.DuplicateModule(sym));
   348                     return;
   349                 }
   350             }
   351             sym.completer = getSourceCompleter(toplevel);
   352             sym.module_info.sourcefile = toplevel.sourcefile;
   353             decl.sym = sym;
   354 
   355             if (multiModuleMode || modules.isEmpty()) {
   356                 modules.add(sym);
   357             } else {
   358                 log.error(toplevel.pos(), Errors.TooManyModules);
   359             }
   360 
   361             Env<AttrContext> provisionalEnv = new Env<>(decl, null);
   362 
   363             provisionalEnv.toplevel = toplevel;
   364             typeEnvs.put(sym, provisionalEnv);
   365         } else if (isModuleInfo) {
   366             if (multiModuleMode) {
   367                 JCTree tree = toplevel.defs.isEmpty() ? toplevel : toplevel.defs.head;
   368                 log.error(tree.pos(), Errors.ExpectedModule);
   369             }
   370         }
   371     }
   372 
   373     private void setCompilationUnitModules(List<JCCompilationUnit> trees, Set<ModuleSymbol> rootModules, ClassSymbol c) {
   374         // update the module for each compilation unit
   375         if (multiModuleMode) {
   376             checkNoAllModulePath();
   377             for (JCCompilationUnit tree: trees) {
   378                 if (tree.modle != null) {
   379                     continue;
   380                 }
   381                 if (tree.defs.isEmpty()) {
   382                     tree.modle = syms.unnamedModule;
   383                     continue;
   384                 }
   385 
   386                 JavaFileObject prev = log.useSource(tree.sourcefile);
   387                 try {
   388                     Location msplocn = getModuleLocation(tree);
   389                     Location plocn = fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH) ?
   390                             fileManager.getLocationForModule(StandardLocation.PATCH_MODULE_PATH,
   391                                                              tree.sourcefile) :
   392                             null;
   393 
   394                     if (plocn != null) {
   395                         Name name = names.fromString(fileManager.inferModuleName(plocn));
   396                         ModuleSymbol msym = moduleFinder.findModule(name);
   397                         tree.modle = msym;
   398                         rootModules.add(msym);
   399 
   400                         if (msplocn != null) {
   401                             Name mspname = names.fromString(fileManager.inferModuleName(msplocn));
   402                             if (name != mspname) {
   403                                 log.error(tree.pos(), Errors.FilePatchedAndMsp(name, mspname));
   404                             }
   405                         }
   406                     } else if (msplocn != null) {
   407                         if (tree.getModuleDecl() != null) {
   408                             JavaFileObject canonical =
   409                                     fileManager.getJavaFileForInput(msplocn, "module-info", Kind.SOURCE);
   410                             if (canonical == null || !fileManager.isSameFile(canonical, tree.sourcefile)) {
   411                                 log.error(tree.pos(), Errors.ModuleNotFoundOnModuleSourcePath);
   412                             }
   413                         }
   414                         Name name = names.fromString(fileManager.inferModuleName(msplocn));
   415                         ModuleSymbol msym;
   416                         JCModuleDecl decl = tree.getModuleDecl();
   417                         if (decl != null) {
   418                             msym = decl.sym;
   419                             if (msym.name != name) {
   420                                 log.error(decl.qualId, Errors.ModuleNameMismatch(msym.name, name));
   421                             }
   422                         } else {
   423                             if (tree.getPackage() == null) {
   424                                 log.error(tree.pos(), Errors.UnnamedPkgNotAllowedNamedModules);
   425                             }
   426                             msym = syms.enterModule(name);
   427                         }
   428                         if (msym.sourceLocation == null) {
   429                             msym.sourceLocation = msplocn;
   430                             if (fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) {
   431                                 msym.patchLocation = fileManager.getLocationForModule(
   432                                         StandardLocation.PATCH_MODULE_PATH, msym.name.toString());
   433                             }
   434                             if (fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) {
   435                                 Location outputLocn = fileManager.getLocationForModule(
   436                                         StandardLocation.CLASS_OUTPUT, msym.name.toString());
   437                                 if (msym.patchLocation == null) {
   438                                     msym.classLocation = outputLocn;
   439                                 } else {
   440                                     msym.patchOutputLocation = outputLocn;
   441                                 }
   442                             }
   443                         }
   444                         tree.modle = msym;
   445                         rootModules.add(msym);
   446                     } else if (c != null && c.packge().modle == syms.unnamedModule) {
   447                         tree.modle = syms.unnamedModule;
   448                     } else {
   449                         if (tree.getModuleDecl() != null) {
   450                             log.error(tree.pos(), Errors.ModuleNotFoundOnModuleSourcePath);
   451                         } else {
   452                             log.error(tree.pos(), Errors.NotInModuleOnModuleSourcePath);
   453                         }
   454                         tree.modle = syms.errModule;
   455                         tree.modle.completer = sym -> completeModule((ModuleSymbol)sym);
   456                     }
   457                 } catch (IOException e) {
   458                     throw new Error(e); // FIXME
   459                 } finally {
   460                     log.useSource(prev);
   461                 }
   462             }
   463             if (syms.unnamedModule.sourceLocation == null) {
   464                 syms.unnamedModule.completer = getUnnamedModuleCompleter();
   465                 syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH;
   466                 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH;
   467             }
   468             defaultModule = syms.unnamedModule;
   469         } else {
   470             ModuleSymbol module = null;
   471             if (defaultModule == null) {
   472                 String moduleOverride = singleModuleOverride(trees);
   473                 switch (rootModules.size()) {
   474                     case 0:
   475                         defaultModule = moduleFinder.findSingleModule();
   476                         if (defaultModule == syms.unnamedModule) {
   477                             if (moduleOverride != null) {
   478                                 checkNoAllModulePath();
   479                                 defaultModule = moduleFinder.findModule(names.fromString(moduleOverride));
   480                                 if (legacyModuleOverride != null) {
   481                                     defaultModule.sourceLocation = StandardLocation.SOURCE_PATH;
   482                                 }
   483                                 defaultModule.patchOutputLocation = StandardLocation.CLASS_OUTPUT;
   484                             } else {
   485                                 // Question: why not do findAllModules and initVisiblePackages here?
   486                                 // i.e. body of unnamedModuleCompleter
   487                                 defaultModule.completer = getUnnamedModuleCompleter();
   488                                 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH;
   489                                 defaultModule.classLocation = StandardLocation.CLASS_PATH;
   490                             }
   491                         } else {
   492                             checkNoAllModulePath();
   493                             defaultModule.complete();
   494                             // Question: why not do completeModule here?
   495                             defaultModule.completer = sym -> completeModule((ModuleSymbol) sym);
   496                             defaultModule.sourceLocation = StandardLocation.SOURCE_PATH;
   497                         }
   498                         rootModules.add(defaultModule);
   499                         break;
   500                     case 1:
   501                         checkNoAllModulePath();
   502                         defaultModule = rootModules.iterator().next();
   503                         defaultModule.sourceLocation = StandardLocation.SOURCE_PATH;
   504                         if (fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) {
   505                             try {
   506                                 defaultModule.patchLocation = fileManager.getLocationForModule(
   507                                         StandardLocation.PATCH_MODULE_PATH, defaultModule.name.toString());
   508                             } catch (IOException ex) {
   509                                 throw new Error(ex);
   510                             }
   511                         }
   512                         if (defaultModule.patchLocation == null) {
   513                             Location loc = StandardLocation.CLASS_OUTPUT;
   514                             if (!backgroundCompilation && !fm.hasLocation(StandardLocation.CLASS_OUTPUT)) {
   515                                 for (Location baseLoc : new Location[] {
   516                                         StandardLocation.UPGRADE_MODULE_PATH,
   517                                         StandardLocation.SYSTEM_MODULES,
   518                                         StandardLocation.MODULE_PATH}) {
   519                                     try {
   520                                         final Location tmp = fm.getLocationForModule(
   521                                                 baseLoc,
   522                                                 defaultModule.name.toString());
   523                                         if(tmp != null) {
   524                                             loc = tmp;
   525                                             break;
   526                                         }
   527                                     } catch (IOException ioe) {
   528                                         //pass
   529                                     }
   530                                 }
   531                             }
   532                             defaultModule.classLocation = loc;
   533                         } else {
   534                             defaultModule.patchOutputLocation = StandardLocation.CLASS_OUTPUT;
   535                         }
   536                         break;
   537                     default:
   538                         Assert.error("too many modules");
   539                 }
   540             } else if (rootModules.size() == 1) {
   541                 module = rootModules.iterator().next();
   542                 module.complete();
   543                 module.completer = sym -> completeModule((ModuleSymbol) sym);
   544             } else {
   545                 Assert.check(rootModules.isEmpty());
   546                 String moduleOverride = singleModuleOverride(trees);
   547                 if (moduleOverride != null) {
   548                     module = moduleFinder.findModule(names.fromString(moduleOverride));
   549                 } else {
   550                     module = defaultModule;
   551                 }
   552                 rootModules.add(module);
   553             }
   554 
   555             if (defaultModule != syms.unnamedModule) {
   556                 syms.unnamedModule.completer = getUnnamedModuleCompleter();
   557                 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH;
   558             }
   559 
   560             if (module == null) {
   561                 module = defaultModule;
   562             }
   563 
   564             for (JCCompilationUnit tree: trees) {
   565                 if (defaultModule != syms.unnamedModule
   566                         && defaultModule.sourceLocation == StandardLocation.SOURCE_PATH
   567                         && fileManager.hasLocation(StandardLocation.SOURCE_PATH)) {
   568                     checkSourceLocation(tree, module);
   569                 }
   570                 if (tree.modle == null) {
   571                     tree.modle = module;
   572                 }
   573             }
   574         }
   575     }
   576 
   577     private void checkSourceLocation(JCCompilationUnit tree, ModuleSymbol msym) {
   578         // skip check if legacy module override still in use
   579         if (ideMode || legacyModuleOverride != null) {
   580             return;
   581         }
   582 
   583         try {
   584             JavaFileObject fo = tree.sourcefile;
   585             if (fileManager.contains(msym.sourceLocation, fo)) {
   586                 return;
   587             }
   588             if (msym.patchLocation != null && fileManager.contains(msym.patchLocation, fo)) {
   589                 return;
   590             }
   591             if (fileManager.hasLocation(StandardLocation.SOURCE_OUTPUT)) {
   592                 if (fileManager.contains(StandardLocation.SOURCE_OUTPUT, fo)) {
   593                     return;
   594                 }
   595             } else {
   596                 if (fileManager.contains(StandardLocation.CLASS_OUTPUT, fo)) {
   597                     return;
   598                 }
   599             }
   600         } catch (IOException e) {
   601             throw new Error(e);
   602         }
   603 
   604         JavaFileObject prev = log.useSource(tree.sourcefile);
   605         try {
   606             log.error(tree.pos(), "file.sb.on.source.or.patch.path.for.module");
   607         } finally {
   608             log.useSource(prev);
   609         }
   610     }
   611 
   612     private String singleModuleOverride(List<JCCompilationUnit> trees) {
   613         if (!fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) {
   614             return legacyModuleOverride;
   615         }
   616 
   617         Set<String> override = new LinkedHashSet<>();
   618         for (JCCompilationUnit tree : trees) {
   619             JavaFileObject fo = tree.sourcefile;
   620 
   621             try {
   622                 Location loc =
   623                         fileManager.getLocationForModule(StandardLocation.PATCH_MODULE_PATH, fo);
   624 
   625                 if (loc != null) {
   626                     override.add(fileManager.inferModuleName(loc));
   627                 }
   628             } catch (IOException ex) {
   629                 throw new Error(ex);
   630             }
   631         }
   632 
   633         switch (override.size()) {
   634             case 0: return legacyModuleOverride;
   635             case 1: return override.iterator().next();
   636             default:
   637                 log.error(Errors.TooManyPatchedModules(override));
   638                 return null;
   639         }
   640     }
   641 
   642     /**
   643      * Determine the location for the module on the module source path
   644      * or source output directory which contains a given CompilationUnit.
   645      * If the source output directory is unset, the class output directory
   646      * will be checked instead.
   647      * {@code null} is returned if no such module can be found.
   648      * @param tree the compilation unit tree
   649      * @return the location for the enclosing module
   650      * @throws IOException if there is a problem while searching for the module.
   651      */
   652     private Location getModuleLocation(JCCompilationUnit tree) throws IOException {
   653         JavaFileObject fo = tree.sourcefile;
   654 
   655         Location loc =
   656                 fileManager.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, fo);
   657         if (loc == null) {
   658             Location sourceOutput = fileManager.hasLocation(StandardLocation.SOURCE_OUTPUT) ?
   659                     StandardLocation.SOURCE_OUTPUT : StandardLocation.CLASS_OUTPUT;
   660             loc =
   661                 fileManager.getLocationForModule(sourceOutput, fo);
   662             if (loc != null) {
   663                 loc = fileManager.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, fileManager.inferModuleName(loc));
   664             }
   665         }
   666         return loc;
   667     }
   668 
   669     private void checkNoAllModulePath() {
   670         if (addModsOpt != null && Arrays.asList(addModsOpt.split(",")).contains(ALL_MODULE_PATH)) {
   671             log.error(Errors.AddmodsAllModulePathInvalid);
   672         }
   673     }
   674 
   675     private final Completer mainCompleter = new Completer() {
   676         @Override
   677         public void complete(Symbol sym) throws CompletionFailure {
   678             ModuleSymbol msym = moduleFinder.findModule((ModuleSymbol) sym);
   679 
   680             if (msym.kind == ERR) {
   681                 //make sure the module is initialized:
   682                 msym.directives = List.nil();
   683                 msym.exports = List.nil();
   684                 msym.provides = List.nil();
   685                 msym.requires = List.nil();
   686                 msym.uses = List.nil();
   687             } else if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) {
   688                 setupAutomaticModule(msym);
   689             } else {
   690                 msym.module_info.complete();
   691             }
   692 
   693             // If module-info comes from a .java file, the underlying
   694             // call of classFinder.fillIn will have called through the
   695             // source completer, to Enter, and then to Modules.enter,
   696             // which will call completeModule.
   697             // But, if module-info comes from a .class file, the underlying
   698             // call of classFinder.fillIn will just call ClassReader to read
   699             // the .class file, and so we call completeModule here.
   700             if (msym.module_info.classfile == null || msym.module_info.classfile.getKind() == Kind.CLASS) {
   701                 completeModule(msym);
   702             }
   703         }
   704 
   705         @Override
   706         public String toString() {
   707             return "mainCompleter";
   708         }
   709     };
   710 
   711     private void setupAutomaticModule(ModuleSymbol msym) throws CompletionFailure {
   712         try {
   713             ListBuffer<Directive> directives = new ListBuffer<>();
   714             ListBuffer<ExportsDirective> exports = new ListBuffer<>();
   715             Set<String> seenPackages = new HashSet<>();
   716 
   717             for (JavaFileObject clazz : fileManager.list(msym.classLocation, "", EnumSet.of(Kind.CLASS), true)) {
   718                 String binName = fileManager.inferBinaryName(msym.classLocation, clazz);
   719                 String pack = binName.lastIndexOf('.') != (-1) ? binName.substring(0, binName.lastIndexOf('.')) : ""; //unnamed package????
   720                 if (seenPackages.add(pack)) {
   721                     ExportsDirective d = new ExportsDirective(syms.enterPackage(msym, names.fromString(pack)), null);
   722                     //TODO: opens?
   723                     directives.add(d);
   724                     exports.add(d);
   725                 }
   726             }
   727 
   728             msym.exports = exports.toList();
   729             msym.provides = List.nil();
   730             msym.requires = List.nil();
   731             msym.uses = List.nil();
   732             msym.directives = directives.toList();
   733             msym.flags_field |= Flags.ACYCLIC;
   734         } catch (IOException ex) {
   735             throw new IllegalStateException(ex);
   736         }
   737     }
   738 
   739     private void completeAutomaticModule(ModuleSymbol msym) throws CompletionFailure {
   740         ListBuffer<Directive> directives = new ListBuffer<>();
   741 
   742         directives.addAll(msym.directives);
   743 
   744         ListBuffer<RequiresDirective> requires = new ListBuffer<>();
   745 
   746         for (ModuleSymbol ms : allModules()) {
   747             if (ms == syms.unnamedModule || ms == msym)
   748                 continue;
   749             Set<RequiresFlag> flags = (ms.flags_field & Flags.AUTOMATIC_MODULE) != 0 ?
   750                     EnumSet.of(RequiresFlag.TRANSITIVE) : EnumSet.noneOf(RequiresFlag.class);
   751             RequiresDirective d = new RequiresDirective(ms, flags);
   752             directives.add(d);
   753             requires.add(d);
   754         }
   755 
   756         RequiresDirective requiresUnnamed = new RequiresDirective(syms.unnamedModule);
   757         directives.add(requiresUnnamed);
   758         requires.add(requiresUnnamed);
   759 
   760         msym.requires = requires.toList();
   761         msym.directives = directives.toList();
   762     }
   763 
   764     private Completer getSourceCompleter(JCCompilationUnit tree) {
   765         return new Completer() {
   766             @Override
   767             public void complete(Symbol sym) throws CompletionFailure {
   768                 ModuleSymbol msym = (ModuleSymbol) sym;
   769                 msym.flags_field |= UNATTRIBUTED;
   770                 ModuleVisitor v = new ModuleVisitor();
   771                 JavaFileObject prev = log.useSource(tree.sourcefile);
   772                 JCModuleDecl moduleDecl = tree.getModuleDecl();
   773                 DiagnosticPosition prevLintPos = deferredLintHandler.setPos(moduleDecl.pos());
   774 
   775                 try {
   776                     moduleDecl.accept(v);
   777                     completeModule(msym);
   778                     checkCyclicDependencies(moduleDecl);
   779                 } finally {
   780                     log.useSource(prev);
   781                     deferredLintHandler.setPos(prevLintPos);
   782                     msym.flags_field &= ~UNATTRIBUTED;
   783                 }
   784             }
   785 
   786             @Override
   787             public String toString() {
   788                 return "SourceCompleter: " + tree.sourcefile.getName();
   789             }
   790 
   791         };
   792     }
   793 
   794     public boolean isRootModule(ModuleSymbol module) {
   795         Assert.checkNonNull(rootModules);
   796         return rootModules.contains(module);
   797     }
   798 
   799     public Set<ModuleSymbol> getRootModules() {
   800         Assert.checkNonNull(rootModules);
   801         return rootModules;
   802     }
   803 
   804     class ModuleVisitor extends JCTree.Visitor {
   805         private ModuleSymbol sym;
   806         private final Set<ModuleSymbol> allRequires = new HashSet<>();
   807         private final Map<PackageSymbol,List<ExportsDirective>> allExports = new HashMap<>();
   808         private final Map<PackageSymbol,List<OpensDirective>> allOpens = new HashMap<>();
   809 
   810         @Override
   811         public void visitModuleDef(JCModuleDecl tree) {
   812             sym = Assert.checkNonNull(tree.sym);
   813 
   814             if (tree.getModuleType() == ModuleKind.OPEN) {
   815                 sym.flags.add(ModuleFlags.OPEN);
   816             }
   817             sym.flags_field |= (tree.mods.flags & Flags.DEPRECATED);
   818 
   819             sym.requires = List.nil();
   820             sym.exports = List.nil();
   821             sym.opens = List.nil();
   822             tree.directives.forEach(t -> t.accept(this));
   823             sym.requires = sym.requires.reverse();
   824             sym.exports = sym.exports.reverse();
   825             sym.opens = sym.opens.reverse();
   826             ensureJavaBase();
   827         }
   828 
   829         @Override
   830         public void visitRequires(JCRequires tree) {
   831             ModuleSymbol msym = lookupModule(tree.moduleName);
   832             Set<RequiresFlag> flags = EnumSet.noneOf(RequiresFlag.class);
   833             if (tree.isTransitive)
   834                 flags.add(RequiresFlag.TRANSITIVE);
   835             if (tree.isStaticPhase)
   836                 flags.add(RequiresFlag.STATIC_PHASE);
   837             RequiresDirective d = new RequiresDirective(msym, flags);
   838             tree.directive = d;
   839             if (msym.kind != MDL) {
   840                 log.error(tree.moduleName.pos(), Errors.ModuleNotFound(msym));
   841                 warnedMissing.add(msym);
   842             } else if (allRequires.contains(msym)) {
   843                 log.error(tree.moduleName.pos(), Errors.DuplicateRequires(msym));
   844             } else {
   845                 allRequires.add(msym);
   846                 sym.requires = sym.requires.prepend(d);
   847             }
   848         }
   849 
   850         @Override
   851         public void visitExports(JCExports tree) {
   852             Name name = TreeInfo.fullName(tree.qualid);
   853             PackageSymbol packge = syms.enterPackage(sym, name);
   854             attr.setPackageSymbols(tree.qualid, packge);
   855 
   856             List<ExportsDirective> exportsForPackage = allExports.computeIfAbsent(packge, p -> List.nil());
   857             for (ExportsDirective d : exportsForPackage) {
   858                 reportExportsConflict(tree, packge);
   859             }
   860 
   861             List<ModuleSymbol> toModules = null;
   862             if (tree.moduleNames != null) {
   863                 Set<ModuleSymbol> to = new LinkedHashSet<>();
   864                 for (JCExpression n: tree.moduleNames) {
   865                     ModuleSymbol msym = lookupModule(n);
   866                     chk.checkModuleExists(n.pos(), msym);
   867                     for (ExportsDirective d : exportsForPackage) {
   868                         checkDuplicateExportsToModule(n, msym, d);
   869                     }
   870                     if (!to.add(msym)) {
   871                         reportExportsConflictToModule(n, msym);
   872                     }
   873                 }
   874                 toModules = List.from(to);
   875             }
   876 
   877             if (toModules == null || !toModules.isEmpty()) {
   878                 Set<ExportsFlag> flags = EnumSet.noneOf(ExportsFlag.class);
   879                 ExportsDirective d = new ExportsDirective(packge, toModules, flags);
   880                 sym.exports = sym.exports.prepend(d);
   881                 tree.directive = d;
   882 
   883                 allExports.put(packge, exportsForPackage.prepend(d));
   884             }
   885         }
   886 
   887         private void reportExportsConflict(JCExports tree, PackageSymbol packge) {
   888             log.error(tree.qualid.pos(), Errors.ConflictingExports(packge));
   889         }
   890 
   891         private void checkDuplicateExportsToModule(JCExpression name, ModuleSymbol msym,
   892                 ExportsDirective d) {
   893             if (d.modules != null) {
   894                 for (ModuleSymbol other : d.modules) {
   895                     if (msym == other) {
   896                         reportExportsConflictToModule(name, msym);
   897                     }
   898                 }
   899             }
   900         }
   901 
   902         private void reportExportsConflictToModule(JCExpression name, ModuleSymbol msym) {
   903             log.error(name.pos(), Errors.ConflictingExportsToModule(msym));
   904         }
   905 
   906         @Override
   907         public void visitOpens(JCOpens tree) {
   908             Name name = TreeInfo.fullName(tree.qualid);
   909             PackageSymbol packge = syms.enterPackage(sym, name);
   910             attr.setPackageSymbols(tree.qualid, packge);
   911 
   912             if (sym.flags.contains(ModuleFlags.OPEN)) {
   913                 log.error(tree.pos(), Errors.NoOpensUnlessStrong);
   914             }
   915             List<OpensDirective> opensForPackage = allOpens.computeIfAbsent(packge, p -> List.nil());
   916             for (OpensDirective d : opensForPackage) {
   917                 reportOpensConflict(tree, packge);
   918             }
   919 
   920             List<ModuleSymbol> toModules = null;
   921             if (tree.moduleNames != null) {
   922                 Set<ModuleSymbol> to = new LinkedHashSet<>();
   923                 for (JCExpression n: tree.moduleNames) {
   924                     ModuleSymbol msym = lookupModule(n);
   925                     chk.checkModuleExists(n.pos(), msym);
   926                     for (OpensDirective d : opensForPackage) {
   927                         checkDuplicateOpensToModule(n, msym, d);
   928                     }
   929                     if (!to.add(msym)) {
   930                         reportOpensConflictToModule(n, msym);
   931                     }
   932                 }
   933                 toModules = List.from(to);
   934             }
   935 
   936             if (toModules == null || !toModules.isEmpty()) {
   937                 Set<OpensFlag> flags = EnumSet.noneOf(OpensFlag.class);
   938                 OpensDirective d = new OpensDirective(packge, toModules, flags);
   939                 sym.opens = sym.opens.prepend(d);
   940                 tree.directive = d;
   941 
   942                 allOpens.put(packge, opensForPackage.prepend(d));
   943             }
   944         }
   945 
   946         private void reportOpensConflict(JCOpens tree, PackageSymbol packge) {
   947             log.error(tree.qualid.pos(), Errors.ConflictingOpens(packge));
   948         }
   949 
   950         private void checkDuplicateOpensToModule(JCExpression name, ModuleSymbol msym,
   951                 OpensDirective d) {
   952             if (d.modules != null) {
   953                 for (ModuleSymbol other : d.modules) {
   954                     if (msym == other) {
   955                         reportOpensConflictToModule(name, msym);
   956                     }
   957                 }
   958             }
   959         }
   960 
   961         private void reportOpensConflictToModule(JCExpression name, ModuleSymbol msym) {
   962             log.error(name.pos(), Errors.ConflictingOpensToModule(msym));
   963         }
   964 
   965         @Override
   966         public void visitProvides(JCProvides tree) { }
   967 
   968         @Override
   969         public void visitUses(JCUses tree) { }
   970 
   971         private void ensureJavaBase() {
   972             if (sym.name == names.java_base)
   973                 return;
   974 
   975             for (RequiresDirective d: sym.requires) {
   976                 if (d.module.name == names.java_base)
   977                     return;
   978             }
   979 
   980             ModuleSymbol java_base = syms.enterModule(names.java_base);
   981             Directive.RequiresDirective d =
   982                     new Directive.RequiresDirective(java_base,
   983                             EnumSet.of(Directive.RequiresFlag.MANDATED));
   984             sym.requires = sym.requires.prepend(d);
   985         }
   986 
   987         private ModuleSymbol lookupModule(JCExpression moduleName) {
   988             Name name = TreeInfo.fullName(moduleName);
   989             ModuleSymbol msym = moduleFinder.findModule(name);
   990             TreeInfo.setSymbol(moduleName, msym);
   991             return msym;
   992         }
   993     }
   994 
   995     public Completer getUsesProvidesCompleter() {
   996         return sym -> {
   997             ModuleSymbol msym = (ModuleSymbol) sym;
   998 
   999             msym.complete();
  1000 
  1001             Env<AttrContext> env = typeEnvs.get(msym);
  1002             UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env);
  1003             JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
  1004             JCModuleDecl decl = env.toplevel.getModuleDecl();
  1005             DiagnosticPosition prevLintPos = deferredLintHandler.setPos(decl.pos());
  1006 
  1007             try {
  1008                 decl.accept(v);
  1009             } finally {
  1010                 log.useSource(prev);
  1011                 deferredLintHandler.setPos(prevLintPos);
  1012             }
  1013         };
  1014     }
  1015 
  1016     class UsesProvidesVisitor extends JCTree.Visitor {
  1017         private final ModuleSymbol msym;
  1018         private final Env<AttrContext> env;
  1019 
  1020         private final Set<ClassSymbol> allUses = new HashSet<>();
  1021         private final Map<ClassSymbol, Set<ClassSymbol>> allProvides = new HashMap<>();
  1022 
  1023         public UsesProvidesVisitor(ModuleSymbol msym, Env<AttrContext> env) {
  1024             this.msym = msym;
  1025             this.env = env;
  1026         }
  1027 
  1028         @Override @SuppressWarnings("unchecked")
  1029         public void visitModuleDef(JCModuleDecl tree) {
  1030             msym.directives = List.nil();
  1031             msym.provides = List.nil();
  1032             msym.uses = List.nil();
  1033             tree.directives.forEach(t -> t.accept(this));
  1034             msym.directives = msym.directives.reverse();
  1035             msym.provides = msym.provides.reverse();
  1036             msym.uses = msym.uses.reverse();
  1037 
  1038             if (msym.requires.nonEmpty() && msym.requires.head.flags.contains(RequiresFlag.MANDATED))
  1039                 msym.directives = msym.directives.prepend(msym.requires.head);
  1040 
  1041             msym.directives = msym.directives.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet())));
  1042 
  1043             checkForCorrectness();
  1044         }
  1045 
  1046         @Override
  1047         public void visitExports(JCExports tree) {
  1048             Iterable<Symbol> packageContent = tree.directive.packge.members().getSymbols();
  1049             List<JavaFileObject> filesToCheck = List.nil();
  1050             boolean packageNotEmpty = false;
  1051             for (Symbol sym : packageContent) {
  1052                 if (sym.kind != Kinds.Kind.TYP)
  1053                     continue;
  1054                 ClassSymbol csym = (ClassSymbol) sym;
  1055                 if (sym.completer.isTerminal() ||
  1056                     csym.classfile.getKind() == Kind.CLASS) {
  1057                     packageNotEmpty = true;
  1058                     filesToCheck = List.nil();
  1059                     break;
  1060                 }
  1061                 if (csym.classfile.getKind() == Kind.SOURCE) {
  1062                     filesToCheck = filesToCheck.prepend(csym.classfile);
  1063                 }
  1064             }
  1065             for (JavaFileObject jfo : filesToCheck) {
  1066                 if (findPackageInFile.findPackageNameOf(jfo) == tree.directive.packge.fullname) {
  1067                     packageNotEmpty = true;
  1068                     break;
  1069                 }
  1070             }
  1071             if (!packageNotEmpty) {
  1072                 log.error(tree.qualid.pos(), Errors.PackageEmptyOrNotFound(tree.directive.packge));
  1073             }
  1074             msym.directives = msym.directives.prepend(tree.directive);
  1075         }
  1076 
  1077         @Override
  1078         public void visitOpens(JCOpens tree) {
  1079             chk.checkPackageExistsForOpens(tree.qualid, tree.directive.packge);
  1080             msym.directives = msym.directives.prepend(tree.directive);
  1081         }
  1082 
  1083         MethodSymbol noArgsConstructor(ClassSymbol tsym) {
  1084             for (Symbol sym : tsym.members().getSymbolsByName(names.init)) {
  1085                 MethodSymbol mSym = (MethodSymbol)sym;
  1086                 if (mSym.params().isEmpty()) {
  1087                     return mSym;
  1088                 }
  1089             }
  1090             return null;
  1091         }
  1092 
  1093         MethodSymbol factoryMethod(ClassSymbol tsym) {
  1094             for (Symbol sym : tsym.members().getSymbolsByName(names.provider, sym -> sym.kind == MTH)) {
  1095                 MethodSymbol mSym = (MethodSymbol)sym;
  1096                 if (mSym.isStatic() && (mSym.flags() & Flags.PUBLIC) != 0 && mSym.params().isEmpty()) {
  1097                     return mSym;
  1098                 }
  1099             }
  1100             return null;
  1101         }
  1102 
  1103         Map<Directive.ProvidesDirective, JCProvides> directiveToTreeMap = new HashMap<>();
  1104 
  1105         @Override
  1106         public void visitProvides(JCProvides tree) {
  1107             Type st = attr.attribType(tree.serviceName, env, syms.objectType);
  1108             ClassSymbol service = (ClassSymbol) st.tsym;
  1109             if (allProvides.containsKey(service)) {
  1110                 log.error(tree.serviceName.pos(), Errors.RepeatedProvidesForService(service));
  1111             }
  1112             ListBuffer<ClassSymbol> impls = new ListBuffer<>();
  1113             for (JCExpression implName : tree.implNames) {
  1114                 Type it;
  1115                 boolean prevVisitingServiceImplementation = env.info.visitingServiceImplementation;
  1116                 try {
  1117                     env.info.visitingServiceImplementation = true;
  1118                     it = attr.attribType(implName, env, syms.objectType);
  1119                 } finally {
  1120                     env.info.visitingServiceImplementation = prevVisitingServiceImplementation;
  1121                 }
  1122                 ClassSymbol impl = (ClassSymbol) it.tsym;
  1123                 if ((impl.flags_field & PUBLIC) == 0) {
  1124                     log.error(implName.pos(), Errors.NotDefPublic(impl, impl.location()));
  1125                 }
  1126                 //find provider factory:
  1127                 MethodSymbol factory = factoryMethod(impl);
  1128                 if (factory != null) {
  1129                     Type returnType = factory.type.getReturnType();
  1130                     if (!types.isSubtype(returnType, st)) {
  1131                         log.error(implName.pos(), Errors.ServiceImplementationProviderReturnMustBeSubtypeOfServiceInterface);
  1132                     }
  1133                 } else {
  1134                     if (!types.isSubtype(it, st)) {
  1135                         log.error(implName.pos(), Errors.ServiceImplementationMustBeSubtypeOfServiceInterface);
  1136                     } else if ((impl.flags() & ABSTRACT) != 0) {
  1137                         log.error(implName.pos(), Errors.ServiceImplementationIsAbstract(impl));
  1138                     } else if (impl.isInner()) {
  1139                         log.error(implName.pos(), Errors.ServiceImplementationIsInner(impl));
  1140                     } else {
  1141                         MethodSymbol constr = noArgsConstructor(impl);
  1142                         if (constr == null) {
  1143                             log.error(implName.pos(), Errors.ServiceImplementationDoesntHaveANoArgsConstructor(impl));
  1144                         } else if ((constr.flags() & PUBLIC) == 0) {
  1145                             log.error(implName.pos(), Errors.ServiceImplementationNoArgsConstructorNotPublic(impl));
  1146                         }
  1147                     }
  1148                 }
  1149                 if (it.hasTag(CLASS)) {
  1150                     if (allProvides.computeIfAbsent(service, s -> new HashSet<>()).add(impl)) {
  1151                         impls.append(impl);
  1152                     } else {
  1153                         log.error(implName.pos(), Errors.DuplicateProvides(service, impl));
  1154                     }
  1155                 }
  1156             }
  1157             if (st.hasTag(CLASS) && !impls.isEmpty()) {
  1158                 Directive.ProvidesDirective d = new Directive.ProvidesDirective(service, impls.toList());
  1159                 msym.provides = msym.provides.prepend(d);
  1160                 msym.directives = msym.directives.prepend(d);
  1161                 directiveToTreeMap.put(d, tree);
  1162             }
  1163         }
  1164 
  1165         @Override
  1166         public void visitRequires(JCRequires tree) {
  1167             if (tree.directive != null && allModules().contains(tree.directive.module)) {
  1168                 chk.checkDeprecated(tree.moduleName.pos(), msym, tree.directive.module);
  1169                 chk.checkModuleRequires(tree.moduleName.pos(), tree.directive);
  1170                 msym.directives = msym.directives.prepend(tree.directive);
  1171             }
  1172         }
  1173 
  1174         @Override
  1175         public void visitUses(JCUses tree) {
  1176             Type st = attr.attribType(tree.qualid, env, syms.objectType);
  1177             Symbol sym = TreeInfo.symbol(tree.qualid);
  1178             if ((sym.flags() & ENUM) != 0) {
  1179                 log.error(tree.qualid.pos(), Errors.ServiceDefinitionIsEnum(st.tsym));
  1180             } else if (st.hasTag(CLASS)) {
  1181                 ClassSymbol service = (ClassSymbol) st.tsym;
  1182                 if (allUses.add(service)) {
  1183                     Directive.UsesDirective d = new Directive.UsesDirective(service);
  1184                     msym.uses = msym.uses.prepend(d);
  1185                     msym.directives = msym.directives.prepend(d);
  1186                 } else {
  1187                     log.error(tree.pos(), Errors.DuplicateUses(service));
  1188                 }
  1189             }
  1190         }
  1191 
  1192         private void checkForCorrectness() {
  1193             for (Directive.ProvidesDirective provides : msym.provides) {
  1194                 JCProvides tree = directiveToTreeMap.get(provides);
  1195                 for (ClassSymbol impl : provides.impls) {
  1196                     /* The implementation must be defined in the same module as the provides directive
  1197                      * (else, error)
  1198                      */
  1199                     PackageSymbol implementationDefiningPackage = impl.packge();
  1200                     if (implementationDefiningPackage.modle != msym) {
  1201                         // TODO: should use tree for the implentation name, not the entire provides tree
  1202                         // TODO: should improve error message to identify the implementation type
  1203                         log.error(tree.pos(), Errors.ServiceImplementationNotInRightModule(implementationDefiningPackage.modle));
  1204                     }
  1205 
  1206                     /* There is no inherent requirement that module that provides a service should actually
  1207                      * use it itself. However, it is a pointless declaration if the service package is not
  1208                      * exported and there is no uses for the service.
  1209                      */
  1210                     PackageSymbol interfaceDeclaringPackage = provides.service.packge();
  1211                     boolean isInterfaceDeclaredInCurrentModule = interfaceDeclaringPackage.modle == msym;
  1212                     boolean isInterfaceExportedFromAReadableModule =
  1213                             msym.visiblePackages.get(interfaceDeclaringPackage.fullname) == interfaceDeclaringPackage;
  1214                     if (isInterfaceDeclaredInCurrentModule && !isInterfaceExportedFromAReadableModule) {
  1215                         // ok the interface is declared in this module. Let's check if it's exported
  1216                         boolean warn = true;
  1217                         for (ExportsDirective export : msym.exports) {
  1218                             if (interfaceDeclaringPackage == export.packge) {
  1219                                 warn = false;
  1220                                 break;
  1221                             }
  1222                         }
  1223                         if (warn) {
  1224                             for (UsesDirective uses : msym.uses) {
  1225                                 if (provides.service == uses.service) {
  1226                                     warn = false;
  1227                                     break;
  1228                                 }
  1229                             }
  1230                         }
  1231                         if (warn) {
  1232                             log.warning(tree.pos(), Warnings.ServiceProvidedButNotExportedOrUsed(provides.service));
  1233                         }
  1234                     }
  1235                 }
  1236             }
  1237         }
  1238     }
  1239 
  1240     private Set<ModuleSymbol> allModules;
  1241 
  1242     public Set<ModuleSymbol> allModules() {
  1243         Assert.checkNonNull(allModules);
  1244         return allModules;
  1245     }
  1246 
  1247     private void setupAllModules() {
  1248         Assert.checkNonNull(rootModules);
  1249         Assert.checkNull(allModules);
  1250 
  1251         Set<ModuleSymbol> observable;
  1252 
  1253         if (limitModsOpt == null && extraLimitMods.isEmpty()) {
  1254             observable = null;
  1255         } else {
  1256             Set<ModuleSymbol> limitMods = new HashSet<>();
  1257             if (limitModsOpt != null) {
  1258                 for (String limit : limitModsOpt.split(",")) {
  1259                     if (!isValidName(limit))
  1260                         continue;
  1261                     limitMods.add(syms.enterModule(names.fromString(limit)));
  1262                 }
  1263             }
  1264             for (String limit : extraLimitMods) {
  1265                 limitMods.add(syms.enterModule(names.fromString(limit)));
  1266             }
  1267             observable = computeTransitiveClosure(limitMods, null);
  1268             observable.addAll(rootModules);
  1269             if (lintOptions) {
  1270                 for (ModuleSymbol msym : limitMods) {
  1271                     if (!observable.contains(msym)) {
  1272                         log.warning(LintCategory.OPTIONS,
  1273                                 Warnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym));
  1274                     }
  1275                 }
  1276             }
  1277         }
  1278 
  1279         Predicate<ModuleSymbol> observablePred = sym ->
  1280              (observable == null) ? (moduleFinder.findModule(sym).kind != ERR) : observable.contains(sym);
  1281         Predicate<ModuleSymbol> systemModulePred = sym -> (sym.flags() & Flags.SYSTEM_MODULE) != 0;
  1282         Set<ModuleSymbol> enabledRoot = new LinkedHashSet<>();
  1283 
  1284         if (rootModules.contains(syms.unnamedModule)) {
  1285             ModuleSymbol javaSE = syms.getModule(java_se);
  1286             Predicate<ModuleSymbol> jdkModulePred;
  1287 
  1288             if (javaSE != null && (observable == null || observable.contains(javaSE))) {
  1289                 jdkModulePred = sym -> {
  1290                     sym.complete();
  1291                     return   !sym.name.startsWith(java_)
  1292                            && sym.exports.stream().anyMatch(e -> e.modules == null);
  1293                 };
  1294                 enabledRoot.add(javaSE);
  1295             } else {
  1296                 jdkModulePred = sym -> true;
  1297             }
  1298 
  1299             Predicate<ModuleSymbol> noIncubatorPred = sym -> {
  1300                 sym.complete();
  1301                 return !sym.resolutionFlags.contains(ModuleResolutionFlags.DO_NOT_RESOLVE_BY_DEFAULT);
  1302             };
  1303 
  1304             for (ModuleSymbol sym : new HashSet<>(syms.getAllModules())) {
  1305                 try {
  1306                     if (systemModulePred.test(sym) && observablePred.test(sym) && jdkModulePred.test(sym) && noIncubatorPred.test(sym)) {
  1307                         enabledRoot.add(sym);
  1308                     }
  1309                 } catch (CompletionFailure ex) {
  1310                     chk.completionError(null, ex);
  1311                 }
  1312             }
  1313         }
  1314 
  1315         enabledRoot.addAll(rootModules);
  1316 
  1317         if (addModsOpt != null || !extraAddMods.isEmpty()) {
  1318             Set<String> fullAddMods = new HashSet<>();
  1319             fullAddMods.addAll(extraAddMods);
  1320 
  1321             if (addModsOpt != null) {
  1322                 fullAddMods.addAll(Arrays.asList(addModsOpt.split(",")));
  1323             }
  1324 
  1325             for (String added : fullAddMods) {
  1326                 Stream<ModuleSymbol> modules;
  1327                 switch (added) {
  1328                     case ALL_SYSTEM:
  1329                         modules = new HashSet<>(syms.getAllModules())
  1330                                 .stream()
  1331                                 .filter(systemModulePred.and(observablePred));
  1332                         break;
  1333                     case ALL_MODULE_PATH:
  1334                         modules = new HashSet<>(syms.getAllModules())
  1335                                 .stream()
  1336                                 .filter(systemModulePred.negate().and(observablePred));
  1337                         break;
  1338                     default:
  1339                         if (!isValidName(added))
  1340                             continue;
  1341                         modules = Stream.of(syms.enterModule(names.fromString(added)));
  1342                         break;
  1343                 }
  1344                 modules.forEach(sym -> {
  1345                     enabledRoot.add(sym);
  1346                     if (observable != null)
  1347                         observable.add(sym);
  1348                 });
  1349             }
  1350         }
  1351 
  1352         Set<ModuleSymbol> result = computeTransitiveClosure(enabledRoot, observable);
  1353 
  1354         result.add(syms.unnamedModule);
  1355 
  1356         boolean hasAutomatic = result.stream().anyMatch(IS_AUTOMATIC);
  1357 
  1358         if (hasAutomatic) {
  1359             syms.getAllModules()
  1360                 .stream()
  1361                 .filter(IS_AUTOMATIC)
  1362                 .forEach(result::add);
  1363         }
  1364 
  1365         String incubatingModules = result.stream()
  1366                 .filter(msym -> msym.resolutionFlags.contains(ModuleResolutionFlags.WARN_INCUBATING))
  1367                 .map(msym -> msym.name.toString())
  1368                 .collect(Collectors.joining(","));
  1369 
  1370         if (!incubatingModules.isEmpty()) {
  1371             log.warning(Warnings.IncubatingModules(incubatingModules));
  1372         }
  1373 
  1374         allModules = result;
  1375 
  1376         //add module versions from options, if any:
  1377         if (moduleVersionOpt != null) {
  1378             Name version = names.fromString(moduleVersionOpt);
  1379             rootModules.forEach(m -> m.version = version);
  1380         }
  1381     }
  1382     //where:
  1383         private static final Predicate<ModuleSymbol> IS_AUTOMATIC =
  1384                 m -> (m.flags_field & Flags.AUTOMATIC_MODULE) != 0;
  1385 
  1386     public boolean isInModuleGraph(ModuleSymbol msym) {
  1387         return allModules == null || allModules.contains(msym);
  1388     }
  1389 
  1390     private Set<ModuleSymbol> computeTransitiveClosure(Set<? extends ModuleSymbol> base, Set<ModuleSymbol> observable) {
  1391         List<ModuleSymbol> primaryTodo = List.nil();
  1392         List<ModuleSymbol> secondaryTodo = List.nil();
  1393 
  1394         for (ModuleSymbol ms : base) {
  1395             primaryTodo = primaryTodo.prepend(ms);
  1396         }
  1397 
  1398         Set<ModuleSymbol> result = new LinkedHashSet<>();
  1399         result.add(syms.java_base);
  1400 
  1401         while (primaryTodo.nonEmpty() || secondaryTodo.nonEmpty()) {
  1402             try {
  1403                 ModuleSymbol current;
  1404                 boolean isPrimaryTodo;
  1405                 if (primaryTodo.nonEmpty()) {
  1406                     current = primaryTodo.head;
  1407                     primaryTodo = primaryTodo.tail;
  1408                     isPrimaryTodo = true;
  1409                 } else {
  1410                     current = secondaryTodo.head;
  1411                     secondaryTodo = secondaryTodo.tail;
  1412                     isPrimaryTodo = false;
  1413                 }
  1414                 if (observable != null && !observable.contains(current))
  1415                     continue;
  1416                 if (!result.add(current) || current == syms.unnamedModule || ((current.flags_field & Flags.AUTOMATIC_MODULE) != 0))
  1417                     continue;
  1418                 current.complete();
  1419                 if (current.kind == ERR && isPrimaryTodo && warnedMissing.add(current)) {
  1420                     log.error(Errors.ModuleNotFound(current));
  1421                 }
  1422                 for (RequiresDirective rd : current.requires) {
  1423                     if (rd.module == syms.java_base) continue;
  1424                     if ((rd.isTransitive() && isPrimaryTodo) || base.contains(current)) {
  1425                         primaryTodo = primaryTodo.prepend(rd.module);
  1426                     } else {
  1427                         secondaryTodo = secondaryTodo.prepend(rd.module);
  1428                     }
  1429                 }
  1430             } catch (CompletionFailure ex) {
  1431                 chk.completionError(null, ex);
  1432             }
  1433         }
  1434 
  1435         return result;
  1436     }
  1437 
  1438     public ModuleSymbol getObservableModule(Name name) {
  1439         ModuleSymbol mod = syms.getModule(name);
  1440 
  1441         if (allModules().contains(mod)) {
  1442             return mod;
  1443         }
  1444 
  1445         return null;
  1446     }
  1447 
  1448     private Completer getUnnamedModuleCompleter() {
  1449         moduleFinder.findAllModules();
  1450         return new Symbol.Completer() {
  1451             @Override
  1452             public void complete(Symbol sym) throws CompletionFailure {
  1453                 if (inInitModules) {
  1454                     sym.completer = this;
  1455                     return ;
  1456                 }
  1457                 ModuleSymbol msym = (ModuleSymbol) sym;
  1458                 Set<ModuleSymbol> allModules = new HashSet<>(allModules());
  1459                 allModules.remove(syms.unnamedModule);
  1460                 for (ModuleSymbol m : allModules) {
  1461                     m.complete();
  1462                 }
  1463                 initVisiblePackages(msym, allModules);
  1464             }
  1465 
  1466             @Override
  1467             public String toString() {
  1468                 return "unnamedModule Completer";
  1469             }
  1470         };
  1471     }
  1472 
  1473     private final Map<ModuleSymbol, Set<ModuleSymbol>> requiresTransitiveCache = new HashMap<>();
  1474 
  1475     private void completeModule(ModuleSymbol msym) {
  1476         if (inInitModules) {
  1477             msym.completer = sym -> completeModule(msym);
  1478             return ;
  1479         }
  1480 
  1481         if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) {
  1482             completeAutomaticModule(msym);
  1483         }
  1484 
  1485         Assert.checkNonNull(msym.requires);
  1486 
  1487         initAddReads();
  1488 
  1489         msym.requires = msym.requires.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet())));
  1490 
  1491         List<RequiresDirective> requires = msym.requires;
  1492 
  1493         while (requires.nonEmpty()) {
  1494             if (!allModules().contains(requires.head.module)) {
  1495                 Env<AttrContext> env = typeEnvs.get(msym);
  1496                 if (env != null) {
  1497                     JavaFileObject origSource = log.useSource(env.toplevel.sourcefile);
  1498                     try {
  1499                         log.error(/*XXX*/env.tree, Errors.ModuleNotFound(requires.head.module));
  1500                     } finally {
  1501                         log.useSource(origSource);
  1502                     }
  1503                 } else {
  1504                     Assert.check((msym.flags() & Flags.AUTOMATIC_MODULE) == 0);
  1505                 }
  1506                 msym.requires = List.filter(msym.requires, requires.head);
  1507             }
  1508             requires = requires.tail;
  1509         }
  1510 
  1511         Set<ModuleSymbol> readable = new LinkedHashSet<>();
  1512         Set<ModuleSymbol> requiresTransitive = new HashSet<>();
  1513 
  1514         for (RequiresDirective d : msym.requires) {
  1515             d.module.complete();
  1516             readable.add(d.module);
  1517             Set<ModuleSymbol> s = retrieveRequiresTransitive(d.module);
  1518             Assert.checkNonNull(s, () -> "no entry in cache for " + d.module);
  1519             readable.addAll(s);
  1520             if (d.flags.contains(RequiresFlag.TRANSITIVE)) {
  1521                 requiresTransitive.add(d.module);
  1522                 requiresTransitive.addAll(s);
  1523             }
  1524         }
  1525 
  1526         requiresTransitiveCache.put(msym, requiresTransitive);
  1527         initVisiblePackages(msym, readable);
  1528         for (ExportsDirective d: msym.exports) {
  1529             if (d.packge != null) {
  1530                 d.packge.modle = msym;
  1531             }
  1532         }
  1533 
  1534     }
  1535 
  1536     private Set<ModuleSymbol> retrieveRequiresTransitive(ModuleSymbol msym) {
  1537         Set<ModuleSymbol> requiresTransitive = requiresTransitiveCache.get(msym);
  1538 
  1539         if (requiresTransitive == null) {
  1540             //the module graph may contain cycles involving automatic modules or --add-reads edges
  1541             requiresTransitive = new HashSet<>();
  1542 
  1543             Set<ModuleSymbol> seen = new HashSet<>();
  1544             List<ModuleSymbol> todo = List.of(msym);
  1545 
  1546             while (todo.nonEmpty()) {
  1547                 ModuleSymbol current = todo.head;
  1548                 todo = todo.tail;
  1549                 if (!seen.add(current))
  1550                     continue;
  1551                 requiresTransitive.add(current);
  1552                 current.complete();
  1553                 Iterable<? extends RequiresDirective> requires;
  1554                 if (current != syms.unnamedModule) {
  1555                     Assert.checkNonNull(current.requires, () -> current + ".requires == null; " + msym);
  1556                     requires = current.requires;
  1557                     for (RequiresDirective rd : requires) {
  1558                         if (rd.isTransitive())
  1559                             todo = todo.prepend(rd.module);
  1560                     }
  1561                 } else {
  1562                     for (ModuleSymbol mod : allModules()) {
  1563                         todo = todo.prepend(mod);
  1564                     }
  1565                 }
  1566             }
  1567 
  1568             requiresTransitive.remove(msym);
  1569         }
  1570 
  1571         return requiresTransitive;
  1572     }
  1573 
  1574     private void initVisiblePackages(ModuleSymbol msym, Collection<ModuleSymbol> readable) {
  1575         initAddExports();
  1576 
  1577         msym.visiblePackages = new LinkedHashMap<>();
  1578         msym.readModules = new HashSet<>(readable);
  1579 
  1580         Map<Name, ModuleSymbol> seen = new HashMap<>();
  1581 
  1582         for (ModuleSymbol rm : readable) {
  1583             if (rm == syms.unnamedModule)
  1584                 continue;
  1585             addVisiblePackages(msym, seen, rm, rm.exports);
  1586         }
  1587 
  1588         addExports.forEach((exportsFrom, exports) -> {
  1589             addVisiblePackages(msym, seen, exportsFrom, exports);
  1590         });
  1591     }
  1592 
  1593     private void addVisiblePackages(ModuleSymbol msym,
  1594                                     Map<Name, ModuleSymbol> seenPackages,
  1595                                     ModuleSymbol exportsFrom,
  1596                                     Collection<ExportsDirective> exports) {
  1597         for (ExportsDirective d : exports) {
  1598             if (d.modules == null || d.modules.contains(msym)) {
  1599                 Name packageName = d.packge.fullname;
  1600                 ModuleSymbol previousModule = seenPackages.get(packageName);
  1601 
  1602                 if (previousModule != null && previousModule != exportsFrom) {
  1603                     Env<AttrContext> env = typeEnvs.get(msym);
  1604                     JavaFileObject origSource = env != null ? log.useSource(env.toplevel.sourcefile)
  1605                                                             : null;
  1606                     DiagnosticPosition pos = env != null ? env.tree.pos() : null;
  1607                     try {
  1608                         log.error(pos, Errors.PackageClashFromRequires(msym, packageName,
  1609                                                                       previousModule, exportsFrom));
  1610                     } finally {
  1611                         if (env != null)
  1612                             log.useSource(origSource);
  1613                     }
  1614                     continue;
  1615                 }
  1616 
  1617                 seenPackages.put(packageName, exportsFrom);
  1618                 msym.visiblePackages.put(d.packge.fullname, d.packge);
  1619             }
  1620         }
  1621     }
  1622 
  1623     private void initAddExports() {
  1624         if (addExports != null)
  1625             return;
  1626 
  1627         addExports = new LinkedHashMap<>();
  1628         Set<ModuleSymbol> unknownModules = new HashSet<>();
  1629 
  1630         if (addExportsOpt == null)
  1631             return;
  1632 
  1633         Pattern ep = Pattern.compile("([^/]+)/([^=]+)=(.*)");
  1634         for (String s: addExportsOpt.split("\0+")) {
  1635             if (s.isEmpty())
  1636                 continue;
  1637             Matcher em = ep.matcher(s);
  1638             if (!em.matches()) {
  1639                 continue;
  1640             }
  1641 
  1642             // Terminology comes from
  1643             //  --add-exports module/package=target,...
  1644             // Compare to
  1645             //  module module { exports package to target, ... }
  1646             String moduleName = em.group(1);
  1647             String packageName = em.group(2);
  1648             String targetNames = em.group(3);
  1649 
  1650             if (!isValidName(moduleName))
  1651                 continue;
  1652 
  1653             ModuleSymbol msym = syms.enterModule(names.fromString(moduleName));
  1654             if (!isKnownModule(msym, unknownModules))
  1655                 continue;
  1656 
  1657             if (!isValidName(packageName))
  1658                 continue;
  1659             PackageSymbol p = syms.enterPackage(msym, names.fromString(packageName));
  1660             p.modle = msym;  // TODO: do we need this?
  1661 
  1662             List<ModuleSymbol> targetModules = List.nil();
  1663             for (String toModule : targetNames.split("[ ,]+")) {
  1664                 ModuleSymbol m;
  1665                 if (toModule.equals("ALL-UNNAMED")) {
  1666                     m = syms.unnamedModule;
  1667                 } else {
  1668                     if (!isValidName(toModule))
  1669                         continue;
  1670                     m = syms.enterModule(names.fromString(toModule));
  1671                     if (!isKnownModule(m, unknownModules))
  1672                         continue;
  1673                 }
  1674                 targetModules = targetModules.prepend(m);
  1675             }
  1676 
  1677             Set<ExportsDirective> extra = addExports.computeIfAbsent(msym, _x -> new LinkedHashSet<>());
  1678             ExportsDirective d = new ExportsDirective(p, targetModules);
  1679             extra.add(d);
  1680         }
  1681     }
  1682 
  1683     private boolean isKnownModule(ModuleSymbol msym, Set<ModuleSymbol> unknownModules) {
  1684         if (allModules.contains(msym)) {
  1685             return true;
  1686         }
  1687 
  1688         if (!unknownModules.contains(msym)) {
  1689             if (lintOptions) {
  1690                 log.warning(LintCategory.OPTIONS,
  1691                         Warnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym));
  1692             }
  1693             unknownModules.add(msym);
  1694         }
  1695         return false;
  1696     }
  1697 
  1698     private void initAddReads() {
  1699         if (addReads != null)
  1700             return;
  1701 
  1702         addReads = new LinkedHashMap<>();
  1703 
  1704         if (addReadsOpt == null)
  1705             return;
  1706 
  1707         Pattern rp = Pattern.compile("([^=]+)=(.*)");
  1708         for (String s : addReadsOpt.split("\0+")) {
  1709             if (s.isEmpty())
  1710                 continue;
  1711             Matcher rm = rp.matcher(s);
  1712             if (!rm.matches()) {
  1713                 continue;
  1714             }
  1715 
  1716             // Terminology comes from
  1717             //  --add-reads source-module=target-module,...
  1718             // Compare to
  1719             //  module source-module { requires target-module; ... }
  1720             String sourceName = rm.group(1);
  1721             String targetNames = rm.group(2);
  1722 
  1723             if (!isValidName(sourceName))
  1724                 continue;
  1725 
  1726             ModuleSymbol msym = syms.enterModule(names.fromString(sourceName));
  1727             if (!allModules.contains(msym)) {
  1728                 if (lintOptions) {
  1729                     log.warning(Warnings.ModuleForOptionNotFound(Option.ADD_READS, msym));
  1730                 }
  1731                 continue;
  1732             }
  1733 
  1734             for (String targetName : targetNames.split("[ ,]+", -1)) {
  1735                 ModuleSymbol targetModule;
  1736                 if (targetName.equals("ALL-UNNAMED")) {
  1737                     targetModule = syms.unnamedModule;
  1738                 } else {
  1739                     if (!isValidName(targetName))
  1740                         continue;
  1741                     targetModule = syms.enterModule(names.fromString(targetName));
  1742                     if (!allModules.contains(targetModule)) {
  1743                         if (lintOptions) {
  1744                             log.warning(LintCategory.OPTIONS, Warnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule));
  1745                         }
  1746                         continue;
  1747                     }
  1748                 }
  1749                 addReads.computeIfAbsent(msym, m -> new HashSet<>())
  1750                         .add(new RequiresDirective(targetModule, EnumSet.of(RequiresFlag.EXTRA)));
  1751             }
  1752         }
  1753     }
  1754 
  1755     private void checkCyclicDependencies(JCModuleDecl mod) {
  1756         for (JCDirective d : mod.directives) {
  1757             JCRequires rd;
  1758             if (!d.hasTag(Tag.REQUIRES) || (rd = (JCRequires) d).directive == null)
  1759                 continue;
  1760             Set<ModuleSymbol> nonSyntheticDeps = new HashSet<>();
  1761             List<ModuleSymbol> queue = List.of(rd.directive.module);
  1762             while (queue.nonEmpty()) {
  1763                 ModuleSymbol current = queue.head;
  1764                 queue = queue.tail;
  1765                 if (!nonSyntheticDeps.add(current))
  1766                     continue;
  1767                 current.complete();
  1768                 if ((current.flags() & Flags.ACYCLIC) != 0)
  1769                     continue;
  1770                 if (current.kind != MDL)
  1771                     continue;
  1772                 Assert.checkNonNull(current.requires, current::toString);
  1773                 for (RequiresDirective dep : current.requires) {
  1774                     if (!dep.flags.contains(RequiresFlag.EXTRA))
  1775                         queue = queue.prepend(dep.module);
  1776                 }
  1777             }
  1778             if (nonSyntheticDeps.contains(mod.sym)) {
  1779                 log.error(rd.moduleName.pos(), Errors.CyclicRequires(rd.directive.module));
  1780             }
  1781             mod.sym.flags_field |= Flags.ACYCLIC;
  1782         }
  1783     }
  1784 
  1785     private boolean isValidName(CharSequence name) {
  1786         return SourceVersion.isName(name, Source.toSourceVersion(source));
  1787     }
  1788 
  1789     // DEBUG
  1790     private String toString(ModuleSymbol msym) {
  1791         return msym.name + "["
  1792                 + "kind:" + msym.kind + ";"
  1793                 + "locn:" + toString(msym.sourceLocation) + "," + toString(msym.classLocation) + ";"
  1794                 + "info:" + toString(msym.module_info.sourcefile) + ","
  1795                             + toString(msym.module_info.classfile) + ","
  1796                             + msym.module_info.completer
  1797                 + "]";
  1798     }
  1799 
  1800     // DEBUG
  1801     String toString(Location locn) {
  1802         return (locn == null) ? "--" : locn.getName();
  1803     }
  1804 
  1805     // DEBUG
  1806     String toString(JavaFileObject fo) {
  1807         return (fo == null) ? "--" : fo.getName();
  1808     }
  1809 
  1810     public void newRound() {
  1811         allModules = null;
  1812         rootModules = null;
  1813         warnedMissing.clear();
  1814     }
  1815 
  1816     public interface PackageNameFinder {
  1817         public Name findPackageNameOf(JavaFileObject jfo);
  1818     }
  1819 }