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