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