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