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