Modules.java revision 3747:80b576bd3631
175295Sdes/* 2230132Suqs * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. 375295Sdes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 475295Sdes * 575295Sdes * This code is free software; you can redistribute it and/or modify it 675295Sdes * under the terms of the GNU General Public License version 2 only, as 775295Sdes * published by the Free Software Foundation. Oracle designates this 875295Sdes * particular file as subject to the "Classpath" exception as provided 975295Sdes * by Oracle in the LICENSE file that accompanied this code. 1075295Sdes * 1175295Sdes * This code is distributed in the hope that it will be useful, but WITHOUT 1275295Sdes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1375295Sdes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1475295Sdes * version 2 for more details (a copy is included in the LICENSE file that 1575295Sdes * accompanied this code). 1675295Sdes * 1775295Sdes * You should have received a copy of the GNU General Public License version 1875295Sdes * 2 along with this work; if not, write to the Free Software Foundation, 1975295Sdes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2075295Sdes * 2175295Sdes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2275295Sdes * or visit www.oracle.com if you need additional information or have any 2375295Sdes * questions. 2475295Sdes */ 2575295Sdes 2675295Sdes 2775295Sdespackage com.sun.tools.javac.comp; 2875295Sdes 29143592Sdesimport java.io.IOException; 30143592Sdesimport java.util.Arrays; 31143592Sdesimport java.util.Collection; 32143592Sdesimport java.util.Collections; 33143592Sdesimport java.util.EnumSet; 3475295Sdesimport java.util.HashMap; 3575295Sdesimport java.util.HashSet; 3675295Sdesimport java.util.LinkedHashMap; 3784811Sjhbimport java.util.LinkedHashSet; 3875295Sdesimport java.util.Map; 3975295Sdesimport java.util.Set; 4075295Sdesimport java.util.function.Consumer; 4177965Sdesimport java.util.function.Predicate; 4275295Sdesimport java.util.regex.Matcher; 4375295Sdesimport java.util.regex.Pattern; 4475295Sdesimport java.util.stream.Stream; 4575295Sdes 4675295Sdesimport javax.lang.model.SourceVersion; 4775295Sdesimport javax.tools.JavaFileManager; 4875295Sdesimport javax.tools.JavaFileManager.Location; 4975295Sdesimport javax.tools.JavaFileObject; 5085128Sdesimport javax.tools.JavaFileObject.Kind; 5185128Sdesimport javax.tools.StandardLocation; 5275295Sdes 5375295Sdesimport com.sun.tools.javac.code.ClassFinder; 5475295Sdesimport com.sun.tools.javac.code.Directive; 55293595Sdchaginimport com.sun.tools.javac.code.Directive.ExportsDirective; 56168764Sdesimport com.sun.tools.javac.code.Directive.RequiresDirective; 57168764Sdesimport com.sun.tools.javac.code.Directive.RequiresFlag; 58168764Sdesimport com.sun.tools.javac.code.Directive.UsesDirective; 59293595Sdchaginimport com.sun.tools.javac.code.Flags; 60168764Sdesimport com.sun.tools.javac.code.Kinds; 6185940Sdesimport com.sun.tools.javac.code.Lint.LintCategory; 6285940Sdesimport com.sun.tools.javac.code.ModuleFinder; 6385940Sdesimport com.sun.tools.javac.code.Source; 6485940Sdesimport com.sun.tools.javac.code.Symbol; 6575295Sdesimport com.sun.tools.javac.code.Symbol.ClassSymbol; 66168764Sdesimport com.sun.tools.javac.code.Symbol.Completer; 67168764Sdesimport com.sun.tools.javac.code.Symbol.CompletionFailure; 68168764Sdesimport com.sun.tools.javac.code.Symbol.MethodSymbol; 69168764Sdesimport com.sun.tools.javac.code.Symbol.ModuleSymbol; 70168764Sdesimport com.sun.tools.javac.code.Symbol.PackageSymbol; 71168764Sdesimport com.sun.tools.javac.code.Symtab; 72168764Sdesimport com.sun.tools.javac.code.Type; 73168764Sdesimport com.sun.tools.javac.code.Types; 74168764Sdesimport com.sun.tools.javac.jvm.ClassWriter; 75168764Sdesimport com.sun.tools.javac.jvm.JNIWriter; 76184205Sdesimport com.sun.tools.javac.main.Option; 77168764Sdesimport com.sun.tools.javac.resources.CompilerProperties.Errors; 78168764Sdesimport com.sun.tools.javac.resources.CompilerProperties.Warnings; 79168764Sdesimport com.sun.tools.javac.tree.JCTree; 80168764Sdesimport com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 81168764Sdesimport com.sun.tools.javac.tree.JCTree.JCExports; 82168764Sdesimport com.sun.tools.javac.tree.JCTree.JCExpression; 83168764Sdesimport com.sun.tools.javac.tree.JCTree.JCModuleDecl; 84168764Sdesimport com.sun.tools.javac.tree.JCTree.JCPackageDecl; 85168764Sdesimport com.sun.tools.javac.tree.JCTree.JCProvides; 8685128Sdesimport com.sun.tools.javac.tree.JCTree.JCRequires; 8785128Sdesimport com.sun.tools.javac.tree.JCTree.JCUses; 88168764Sdesimport com.sun.tools.javac.tree.TreeInfo; 89168764Sdesimport com.sun.tools.javac.util.Assert; 9085128Sdesimport com.sun.tools.javac.util.Context; 91168764Sdesimport com.sun.tools.javac.util.JCDiagnostic; 92168764Sdesimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 93168764Sdesimport com.sun.tools.javac.util.List; 94168764Sdesimport com.sun.tools.javac.util.ListBuffer; 9585128Sdesimport com.sun.tools.javac.util.Log; 9687599Sobrienimport com.sun.tools.javac.util.Name; 97168764Sdesimport com.sun.tools.javac.util.Names; 98168764Sdesimport com.sun.tools.javac.util.Options; 9985128Sdes 10087599Sobrienimport static com.sun.tools.javac.code.Flags.UNATTRIBUTED; 10185128Sdesimport static com.sun.tools.javac.code.Kinds.Kind.MDL; 10285128Sdesimport static com.sun.tools.javac.code.TypeTag.CLASS; 10385128Sdes 10487599Sobrienimport com.sun.tools.javac.tree.JCTree.JCDirective; 10585128Sdesimport com.sun.tools.javac.tree.JCTree.Tag; 106168764Sdesimport com.sun.tools.javac.util.Abort; 107168764Sdesimport com.sun.tools.javac.util.Position; 108168764Sdes 109168764Sdesimport static com.sun.tools.javac.code.Flags.ABSTRACT; 110168764Sdesimport static com.sun.tools.javac.code.Flags.ENUM; 111168764Sdesimport static com.sun.tools.javac.code.Flags.PUBLIC; 112168764Sdesimport static com.sun.tools.javac.tree.JCTree.Tag.MODULEDEF; 113168764Sdes 114168764Sdes/** 115168764Sdes * TODO: fill in 116168764Sdes * 117168764Sdes * <p><b>This is NOT part of any supported API. 118168764Sdes * If you write code that depends on this, you do so at your own risk. 119168764Sdes * This code and its internal interfaces are subject to change or 12097940Sdes * deletion without notice.</b> 121168764Sdes */ 122168764Sdespublic class Modules extends JCTree.Visitor { 123168764Sdes private static final String ALL_SYSTEM = "ALL-SYSTEM"; 124168764Sdes private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; 125168764Sdes 126103314Snjl private final Log log; 127168764Sdes private final Names names; 128168764Sdes private final Symtab syms; 129168764Sdes private final Attr attr; 13085128Sdes private final TypeEnvs typeEnvs; 13185128Sdes private final Types types; 13285128Sdes private final JavaFileManager fileManager; 133168764Sdes private final ModuleFinder moduleFinder; 13485128Sdes private final Source source; 135168764Sdes private final boolean allowModules; 136168764Sdes 13785128Sdes public final boolean multiModuleMode; 138168764Sdes 139168764Sdes private final String moduleOverride; 14097940Sdes 141168764Sdes private final Name java_se; 142168764Sdes private final Name java_; 143168764Sdes 14497940Sdes ModuleSymbol defaultModule; 145168764Sdes 146168764Sdes private final String addExportsOpt; 147168764Sdes private Map<ModuleSymbol, Set<ExportsDirective>> addExports; 148168764Sdes private final String addReadsOpt; 149168764Sdes private Map<ModuleSymbol, Set<RequiresDirective>> addReads; 150168764Sdes private final String addModsOpt; 151168764Sdes private final Set<String> extraAddMods = new HashSet<>(); 152168764Sdes private final String limitModsOpt; 15385128Sdes private final Set<String> extraLimitMods = new HashSet<>(); 154168764Sdes 155168764Sdes private final boolean lintOptions; 156168764Sdes 15797940Sdes private Set<ModuleSymbol> rootModules = null; 158168764Sdes 159168764Sdes public static Modules instance(Context context) { 160168764Sdes Modules instance = context.get(Modules.class); 161168764Sdes if (instance == null) 162168764Sdes instance = new Modules(context); 163168764Sdes return instance; 164168764Sdes } 16597940Sdes 166168764Sdes protected Modules(Context context) { 167168764Sdes context.put(Modules.class, this); 168168764Sdes log = Log.instance(context); 169168764Sdes names = Names.instance(context); 17085128Sdes syms = Symtab.instance(context); 17185128Sdes attr = Attr.instance(context); 17285128Sdes typeEnvs = TypeEnvs.instance(context); 17385128Sdes moduleFinder = ModuleFinder.instance(context); 17485128Sdes types = Types.instance(context); 17585128Sdes fileManager = context.get(JavaFileManager.class); 176123248Sdes source = Source.instance(context); 177167482Sdes allowModules = source.allowModules(); 178167482Sdes Options options = Options.instance(context); 17985128Sdes 180168764Sdes lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option); 18185128Sdes 182168764Sdes moduleOverride = options.get(Option.XMODULE); 183168764Sdes 184168764Sdes multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH); 185168764Sdes ClassWriter classWriter = ClassWriter.instance(context); 186168764Sdes classWriter.multiModuleMode = multiModuleMode; 187168764Sdes JNIWriter jniWriter = JNIWriter.instance(context); 188168764Sdes jniWriter.multiModuleMode = multiModuleMode; 189168764Sdes 19085128Sdes java_se = names.fromString("java.se"); 191168764Sdes java_ = names.fromString("java."); 19285128Sdes 19385128Sdes addExportsOpt = options.get(Option.ADD_EXPORTS); 19485128Sdes addReadsOpt = options.get(Option.ADD_READS); 19585128Sdes addModsOpt = options.get(Option.ADD_MODULES); 19685128Sdes limitModsOpt = options.get(Option.LIMIT_MODULES); 19785128Sdes } 198123248Sdes 199167482Sdes int depth = -1; 200167482Sdes private void dprintln(String msg) { 20185128Sdes for (int i = 0; i < depth; i++) 202168764Sdes System.err.print(" "); 20385128Sdes System.err.println(msg); 204168764Sdes } 205168764Sdes 206168764Sdes public void addExtraAddModules(String... extras) { 207168764Sdes extraAddMods.addAll(Arrays.asList(extras)); 208168764Sdes } 209168764Sdes 210168764Sdes public void addExtraLimitModules(String... extras) { 21185128Sdes extraLimitMods.addAll(Arrays.asList(extras)); 212168764Sdes } 21385128Sdes 21485128Sdes boolean inInitModules; 21585128Sdes public void initModules(List<JCCompilationUnit> trees) { 21685128Sdes Assert.check(!inInitModules); 21785128Sdes try { 21885128Sdes inInitModules = true; 219123248Sdes Assert.checkNull(rootModules); 220168387Sdes enter(trees, modules -> { 221167482Sdes Assert.checkNull(rootModules); 22285128Sdes Assert.checkNull(allModules); 223168764Sdes this.rootModules = modules; 22485128Sdes setupAllModules(); //initialize the module graph 225168764Sdes Assert.checkNonNull(allModules); 226168764Sdes inInitModules = false; 227168764Sdes }, null); 228168764Sdes } finally { 229168764Sdes inInitModules = false; 230168764Sdes } 231168764Sdes } 232168764Sdes 233168764Sdes public boolean enter(List<JCCompilationUnit> trees, ClassSymbol c) { 23485128Sdes Assert.check(rootModules != null || inInitModules || !allowModules); 23585128Sdes return enter(trees, modules -> {}, c); 23685128Sdes } 237123248Sdes 238123248Sdes private boolean enter(List<JCCompilationUnit> trees, Consumer<Set<ModuleSymbol>> init, ClassSymbol c) { 239123248Sdes if (!allowModules) { 240123248Sdes for (JCCompilationUnit tree: trees) { 241123248Sdes tree.modle = syms.noModule; 242168764Sdes } 243123248Sdes defaultModule = syms.noModule; 244168764Sdes return true; 245168764Sdes } 246168764Sdes 247168720Sdes int startErrors = log.nerrors; 248168764Sdes 249168764Sdes depth++; 250123248Sdes try { 251123248Sdes // scan trees for module defs 252123248Sdes Set<ModuleSymbol> roots = enterModules(trees, c); 253168764Sdes 254168764Sdes setCompilationUnitModules(trees, roots); 25585128Sdes 25685128Sdes init.accept(roots); 257168764Sdes 25885128Sdes for (ModuleSymbol msym: roots) { 259168764Sdes msym.complete(); 26097940Sdes } 261168764Sdes } catch (CompletionFailure ex) { 26287599Sobrien log.error(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE, Position.NOPOS, "cant.access", ex.sym, ex.getDetailValue()); 263168764Sdes if (ex instanceof ClassFinder.BadClassFile) throw new Abort(); 26487599Sobrien } finally { 26585128Sdes depth--; 266168764Sdes } 267168764Sdes 268168764Sdes return (log.nerrors == startErrors); 26985128Sdes } 270168764Sdes 271168764Sdes public Completer getCompleter() { 272168764Sdes return mainCompleter; 273168764Sdes } 274168764Sdes 275168764Sdes public ModuleSymbol getDefaultModule() { 276168764Sdes return defaultModule; 277168764Sdes } 278168764Sdes 279168764Sdes private Set<ModuleSymbol> enterModules(List<JCCompilationUnit> trees, ClassSymbol c) { 280168764Sdes Set<ModuleSymbol> modules = new LinkedHashSet<>(); 28185128Sdes for (JCCompilationUnit tree : trees) { 282168764Sdes JavaFileObject prev = log.useSource(tree.sourcefile); 28385128Sdes try { 28485128Sdes enterModule(tree, c, modules); 285168764Sdes } finally { 286168764Sdes log.useSource(prev); 287168764Sdes } 288167482Sdes } 289168764Sdes return modules; 290168764Sdes } 291168387Sdes 292168764Sdes 293168764Sdes private void enterModule(JCCompilationUnit toplevel, ClassSymbol c, Set<ModuleSymbol> modules) { 294168764Sdes boolean isModuleInfo = toplevel.sourcefile.isNameCompatible("module-info", Kind.SOURCE); 295184205Sdes boolean isModuleDecl = toplevel.defs.nonEmpty() && toplevel.defs.head.hasTag(MODULEDEF); 29685128Sdes if (isModuleInfo && isModuleDecl) { 29785128Sdes JCModuleDecl decl = (JCModuleDecl) toplevel.defs.head; 29885128Sdes Name name = TreeInfo.fullName(decl.qualId); 29985128Sdes ModuleSymbol sym; 30085128Sdes if (c != null) { 30175295Sdes sym = (ModuleSymbol) c.owner; 30275295Sdes Assert.checkNonNull(sym.name); 30375295Sdes Name treeName = TreeInfo.fullName(decl.qualId); 304191990Sattilio if (sym.name != treeName) { 30575295Sdes log.error(decl.pos(), Errors.ModuleNameMismatch(name, sym.name)); 30675295Sdes } 30797940Sdes } else { 30875295Sdes sym = syms.enterModule(name); 30975295Sdes if (sym.module_info.sourcefile != null && sym.module_info.sourcefile != toplevel.sourcefile) { 31097940Sdes log.error(decl.pos(), Errors.DuplicateModule(sym)); 311168637Sdes return; 31275295Sdes } 313168637Sdes } 314172697Salfred sym.completer = getSourceCompleter(toplevel); 31575295Sdes sym.module_info.sourcefile = toplevel.sourcefile; 31675295Sdes decl.sym = sym; 31775295Sdes 318138495Sphk if (multiModuleMode || modules.isEmpty()) { 31975295Sdes modules.add(sym); 32075295Sdes } else { 32175295Sdes log.error(toplevel.pos(), Errors.TooManyModules); 32275295Sdes } 32375295Sdes 32475295Sdes Env<AttrContext> provisionalEnv = new Env<>(decl, null); 32575295Sdes 32675295Sdes provisionalEnv.toplevel = toplevel; 32775295Sdes typeEnvs.put(sym, provisionalEnv); 32875295Sdes } else if (isModuleInfo) { 32975295Sdes if (multiModuleMode) { 33075295Sdes JCTree tree = toplevel.defs.isEmpty() ? toplevel : toplevel.defs.head; 331168764Sdes log.error(tree.pos(), Errors.ExpectedModule); 332158611Skbyanc } 333158611Skbyanc } else if (isModuleDecl) { 334230249Smckusick JCTree tree = toplevel.defs.head; 335158611Skbyanc log.error(tree.pos(), Errors.ModuleDeclSbInModuleInfoJava); 336168764Sdes } 337168764Sdes } 338168764Sdes 339168764Sdes private void setCompilationUnitModules(List<JCCompilationUnit> trees, Set<ModuleSymbol> rootModules) { 340158611Skbyanc // update the module for each compilation unit 341158611Skbyanc if (multiModuleMode) { 342158611Skbyanc checkNoAllModulePath(); 34375295Sdes for (JCCompilationUnit tree: trees) { 34475295Sdes if (tree.defs.isEmpty()) { 34575295Sdes tree.modle = syms.unnamedModule; 346191990Sattilio continue; 34775295Sdes } 34875295Sdes 34975295Sdes JavaFileObject prev = log.useSource(tree.sourcefile); 350191990Sattilio try { 351191990Sattilio Location locn = getModuleLocation(tree); 35275295Sdes if (locn != null) { 35375295Sdes Name name = names.fromString(fileManager.inferModuleName(locn)); 35475295Sdes ModuleSymbol msym; 35575295Sdes if (tree.defs.head.hasTag(MODULEDEF)) { 35675295Sdes JCModuleDecl decl = (JCModuleDecl) tree.defs.head; 35775295Sdes msym = decl.sym; 35875295Sdes if (msym.name != name) { 359191990Sattilio log.error(decl.qualId, Errors.ModuleNameMismatch(msym.name, name)); 36075295Sdes } 36175295Sdes } else { 36275295Sdes msym = syms.enterModule(name); 36375295Sdes } 364168764Sdes if (msym.sourceLocation == null) { 36575295Sdes msym.sourceLocation = locn; 36675295Sdes if (fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) { 36775295Sdes msym.classLocation = fileManager.getModuleLocation( 36875295Sdes StandardLocation.CLASS_OUTPUT, msym.name.toString()); 36975295Sdes } 37075295Sdes } 371191990Sattilio tree.modle = msym; 37275295Sdes rootModules.add(msym); 373138495Sphk } else { 37475295Sdes log.error(tree.pos(), Errors.UnnamedPkgNotAllowedNamedModules); 37575295Sdes tree.modle = syms.errModule; 37675295Sdes } 37775295Sdes } catch (IOException e) { 37875295Sdes throw new Error(e); // FIXME 37975295Sdes } finally { 38075295Sdes log.useSource(prev); 38175295Sdes } 38275295Sdes } 38385128Sdes if (syms.unnamedModule.sourceLocation == null) { 38485128Sdes syms.unnamedModule.completer = getUnnamedModuleCompleter(); 38585128Sdes syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH; 386168720Sdes syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH; 38797940Sdes } 388168764Sdes defaultModule = syms.unnamedModule; 389168764Sdes } else { 39085128Sdes if (defaultModule == null) { 391168764Sdes switch (rootModules.size()) { 39285128Sdes case 0: 393168764Sdes defaultModule = moduleFinder.findSingleModule(); 394168764Sdes if (defaultModule == syms.unnamedModule) { 39585128Sdes if (moduleOverride != null) { 39685128Sdes checkNoAllModulePath(); 39785128Sdes defaultModule = moduleFinder.findModule(names.fromString(moduleOverride)); 39885128Sdes defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 39985128Sdes } else { 40085128Sdes // Question: why not do findAllModules and initVisiblePackages here? 40185128Sdes // i.e. body of unnamedModuleCompleter 40285128Sdes defaultModule.completer = getUnnamedModuleCompleter(); 40397940Sdes defaultModule.classLocation = StandardLocation.CLASS_PATH; 40484383Sdes } 40584383Sdes } else { 40675295Sdes checkSpecifiedModule(trees, Errors.ModuleInfoWithXmoduleClasspath); 40775295Sdes checkNoAllModulePath(); 40875295Sdes defaultModule.complete(); 40975295Sdes // Question: why not do completeModule here? 41075295Sdes defaultModule.completer = new Completer() { 41175295Sdes @Override 41275295Sdes public void complete(Symbol sym) throws CompletionFailure { 41375295Sdes completeModule((ModuleSymbol) sym); 41475295Sdes } 41585128Sdes }; 41697940Sdes } 417168720Sdes rootModules.add(defaultModule); 418168720Sdes break; 41985128Sdes case 1: 42085128Sdes checkSpecifiedModule(trees, Errors.ModuleInfoWithXmoduleSourcepath); 421168637Sdes checkNoAllModulePath(); 42284383Sdes defaultModule = rootModules.iterator().next(); 42384383Sdes defaultModule.classLocation = StandardLocation.CLASS_OUTPUT; 42485128Sdes break; 42585128Sdes default: 42675295Sdes Assert.error("too many modules"); 42775295Sdes } 42875295Sdes defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 42975295Sdes } else if (rootModules.size() == 1 && defaultModule == rootModules.iterator().next()) { 43075295Sdes defaultModule.complete(); 43175295Sdes defaultModule.completer = sym -> completeModule((ModuleSymbol) sym); 43275295Sdes } else { 43375295Sdes Assert.check(rootModules.isEmpty()); 43475295Sdes rootModules.add(defaultModule); 43575295Sdes } 43675295Sdes 43775295Sdes if (defaultModule != syms.unnamedModule) { 43875295Sdes syms.unnamedModule.completer = getUnnamedModuleCompleter(); 43975295Sdes if (moduleOverride == null) { 44075295Sdes syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH; 44175295Sdes } 44275295Sdes syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH; 443132199Sphk } 44475295Sdes 44575295Sdes for (JCCompilationUnit tree: trees) { 44675295Sdes tree.modle = defaultModule; 44775295Sdes } 44875295Sdes } 44975295Sdes } 45075295Sdes 45175295Sdes private Location getModuleLocation(JCCompilationUnit tree) throws IOException { 45275295Sdes switch (tree.defs.head.getTag()) { 45375295Sdes case MODULEDEF: 45475295Sdes return getModuleLocation(tree.sourcefile, null); 45575295Sdes 45675295Sdes case PACKAGEDEF: 45775295Sdes JCPackageDecl pkg = (JCPackageDecl) tree.defs.head; 45886969Sdes return getModuleLocation(tree.sourcefile, TreeInfo.fullName(pkg.pid)); 459 460 default: 461 // code in unnamed module 462 return null; 463 } 464 } 465 466 private Location getModuleLocation(JavaFileObject fo, Name pkgName) throws IOException { 467 // For now, just check module source path. 468 // We may want to check source path as well. 469 return fileManager.getModuleLocation(StandardLocation.MODULE_SOURCE_PATH, 470 fo, (pkgName == null) ? null : pkgName.toString()); 471 } 472 473 private void checkSpecifiedModule(List<JCCompilationUnit> trees, JCDiagnostic.Error error) { 474 if (moduleOverride != null) { 475 JavaFileObject prev = log.useSource(trees.head.sourcefile); 476 try { 477 log.error(trees.head.pos(), error); 478 } finally { 479 log.useSource(prev); 480 } 481 } 482 } 483 484 private void checkNoAllModulePath() { 485 if (addModsOpt != null && Arrays.asList(addModsOpt.split(",")).contains(ALL_MODULE_PATH)) { 486 log.error(Errors.AddmodsAllModulePathInvalid); 487 } 488 } 489 490 private final Completer mainCompleter = new Completer() { 491 @Override 492 public void complete(Symbol sym) throws CompletionFailure { 493 ModuleSymbol msym = moduleFinder.findModule((ModuleSymbol) sym); 494 495 if (msym.kind == Kinds.Kind.ERR) { 496 log.error(Errors.ModuleNotFound(msym)); 497 //make sure the module is initialized: 498 msym.directives = List.nil(); 499 msym.exports = List.nil(); 500 msym.provides = List.nil(); 501 msym.requires = List.nil(); 502 msym.uses = List.nil(); 503 } else if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 504 setupAutomaticModule(msym); 505 } else { 506 msym.module_info.complete(); 507 } 508 509 // If module-info comes from a .java file, the underlying 510 // call of classFinder.fillIn will have called through the 511 // source completer, to Enter, and then to Modules.enter, 512 // which will call completeModule. 513 // But, if module-info comes from a .class file, the underlying 514 // call of classFinder.fillIn will just call ClassReader to read 515 // the .class file, and so we call completeModule here. 516 if (msym.module_info.classfile == null || msym.module_info.classfile.getKind() == Kind.CLASS) { 517 completeModule(msym); 518 } 519 } 520 521 @Override 522 public String toString() { 523 return "mainCompleter"; 524 } 525 }; 526 527 private void setupAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 528 try { 529 ListBuffer<Directive> directives = new ListBuffer<>(); 530 ListBuffer<ExportsDirective> exports = new ListBuffer<>(); 531 Set<String> seenPackages = new HashSet<>(); 532 533 for (JavaFileObject clazz : fileManager.list(msym.classLocation, "", EnumSet.of(Kind.CLASS), true)) { 534 String binName = fileManager.inferBinaryName(msym.classLocation, clazz); 535 String pack = binName.lastIndexOf('.') != (-1) ? binName.substring(0, binName.lastIndexOf('.')) : ""; //unnamed package???? 536 if (seenPackages.add(pack)) { 537 ExportsDirective d = new ExportsDirective(syms.enterPackage(msym, names.fromString(pack)), null); 538 directives.add(d); 539 exports.add(d); 540 } 541 } 542 543 msym.exports = exports.toList(); 544 msym.provides = List.nil(); 545 msym.requires = List.nil(); 546 msym.uses = List.nil(); 547 msym.directives = directives.toList(); 548 msym.flags_field |= Flags.ACYCLIC; 549 } catch (IOException ex) { 550 throw new IllegalStateException(ex); 551 } 552 } 553 554 private void completeAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 555 ListBuffer<Directive> directives = new ListBuffer<>(); 556 557 directives.addAll(msym.directives); 558 559 ListBuffer<RequiresDirective> requires = new ListBuffer<>(); 560 561 for (ModuleSymbol ms : allModules()) { 562 if (ms == syms.unnamedModule || ms == msym) 563 continue; 564 Set<RequiresFlag> flags = (ms.flags_field & Flags.AUTOMATIC_MODULE) != 0 ? 565 EnumSet.of(RequiresFlag.PUBLIC) : EnumSet.noneOf(RequiresFlag.class); 566 RequiresDirective d = new RequiresDirective(ms, flags); 567 directives.add(d); 568 requires.add(d); 569 } 570 571 RequiresDirective requiresUnnamed = new RequiresDirective(syms.unnamedModule); 572 directives.add(requiresUnnamed); 573 requires.add(requiresUnnamed); 574 575 msym.requires = requires.toList(); 576 msym.directives = directives.toList(); 577 } 578 579 private Completer getSourceCompleter(JCCompilationUnit tree) { 580 return new Completer() { 581 @Override 582 public void complete(Symbol sym) throws CompletionFailure { 583 ModuleSymbol msym = (ModuleSymbol) sym; 584 msym.flags_field |= UNATTRIBUTED; 585 ModuleVisitor v = new ModuleVisitor(); 586 JavaFileObject prev = log.useSource(tree.sourcefile); 587 try { 588 tree.defs.head.accept(v); 589 checkCyclicDependencies((JCModuleDecl) tree.defs.head); 590 completeModule(msym); 591 } finally { 592 log.useSource(prev); 593 msym.flags_field &= ~UNATTRIBUTED; 594 } 595 } 596 597 @Override 598 public String toString() { 599 return "SourceCompleter: " + tree.sourcefile.getName(); 600 } 601 602 }; 603 } 604 605 class ModuleVisitor extends JCTree.Visitor { 606 private ModuleSymbol sym; 607 private final Set<ModuleSymbol> allRequires = new HashSet<>(); 608 private final Set<PackageSymbol> allExports = new HashSet<>(); 609 610 @Override 611 public void visitModuleDef(JCModuleDecl tree) { 612 sym = Assert.checkNonNull(tree.sym); 613 614 sym.requires = List.nil(); 615 sym.exports = List.nil(); 616 tree.directives.forEach(t -> t.accept(this)); 617 sym.requires = sym.requires.reverse(); 618 sym.exports = sym.exports.reverse(); 619 ensureJavaBase(); 620 } 621 622 @Override 623 public void visitRequires(JCRequires tree) { 624 ModuleSymbol msym = lookupModule(tree.moduleName); 625 if (msym.kind != MDL) { 626 log.error(tree.moduleName.pos(), Errors.ModuleNotFound(msym)); 627 } else if (allRequires.contains(msym)) { 628 log.error(tree.moduleName.pos(), Errors.DuplicateRequires(msym)); 629 } else { 630 allRequires.add(msym); 631 Set<RequiresFlag> flags = EnumSet.noneOf(RequiresFlag.class); 632 if (tree.isPublic) 633 flags.add(RequiresFlag.PUBLIC); 634 RequiresDirective d = new RequiresDirective(msym, flags); 635 tree.directive = d; 636 sym.requires = sym.requires.prepend(d); 637 } 638 } 639 640 @Override 641 public void visitExports(JCExports tree) { 642 Name name = TreeInfo.fullName(tree.qualid); 643 PackageSymbol packge = syms.enterPackage(sym, name); 644 attr.setPackageSymbols(tree.qualid, packge); 645 if (!allExports.add(packge)) { 646 log.error(tree.qualid.pos(), Errors.DuplicateExports(packge)); 647 } 648 649 List<ModuleSymbol> toModules = null; 650 if (tree.moduleNames != null) { 651 Set<ModuleSymbol> to = new HashSet<>(); 652 for (JCExpression n: tree.moduleNames) { 653 ModuleSymbol msym = lookupModule(n); 654 if (msym.kind != MDL) { 655 log.error(n.pos(), Errors.ModuleNotFound(msym)); 656 } else if (!to.add(msym)) { 657 log.error(n.pos(), Errors.DuplicateExports(msym)); 658 } 659 } 660 toModules = List.from(to); 661 } 662 663 if (toModules == null || !toModules.isEmpty()) { 664 ExportsDirective d = new ExportsDirective(packge, toModules); 665 tree.directive = d; 666 sym.exports = sym.exports.prepend(d); 667 } 668 } 669 670 @Override 671 public void visitProvides(JCProvides tree) { } 672 673 @Override 674 public void visitUses(JCUses tree) { } 675 676 private void ensureJavaBase() { 677 if (sym.name == names.java_base) 678 return; 679 680 for (RequiresDirective d: sym.requires) { 681 if (d.module.name == names.java_base) 682 return; 683 } 684 685 ModuleSymbol java_base = syms.enterModule(names.java_base); 686 Directive.RequiresDirective d = 687 new Directive.RequiresDirective(java_base, 688 EnumSet.of(Directive.RequiresFlag.MANDATED)); 689 sym.requires = sym.requires.prepend(d); 690 } 691 692 private ModuleSymbol lookupModule(JCExpression moduleName) { 693 Name name = TreeInfo.fullName(moduleName); 694 ModuleSymbol msym = moduleFinder.findModule(name); 695 TreeInfo.setSymbol(moduleName, msym); 696 return msym; 697 } 698 } 699 700 public Completer getUsesProvidesCompleter() { 701 return sym -> { 702 ModuleSymbol msym = (ModuleSymbol) sym; 703 704 msym.complete(); 705 706 Env<AttrContext> env = typeEnvs.get(msym); 707 UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env); 708 JavaFileObject prev = log.useSource(env.toplevel.sourcefile); 709 try { 710 env.toplevel.defs.head.accept(v); 711 } finally { 712 log.useSource(prev); 713 } 714 }; 715 } 716 717 class UsesProvidesVisitor extends JCTree.Visitor { 718 private final ModuleSymbol msym; 719 private final Env<AttrContext> env; 720 721 private final Set<Directive.UsesDirective> allUses = new HashSet<>(); 722 private final Set<Directive.ProvidesDirective> allProvides = new HashSet<>(); 723 724 public UsesProvidesVisitor(ModuleSymbol msym, Env<AttrContext> env) { 725 this.msym = msym; 726 this.env = env; 727 } 728 729 @Override @SuppressWarnings("unchecked") 730 public void visitModuleDef(JCModuleDecl tree) { 731 msym.directives = List.nil(); 732 msym.provides = List.nil(); 733 msym.uses = List.nil(); 734 tree.directives.forEach(t -> t.accept(this)); 735 msym.directives = msym.directives.reverse(); 736 msym.provides = msym.provides.reverse(); 737 msym.uses = msym.uses.reverse(); 738 739 if (msym.requires.nonEmpty() && msym.requires.head.flags.contains(RequiresFlag.MANDATED)) 740 msym.directives = msym.directives.prepend(msym.requires.head); 741 742 msym.directives = msym.directives.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 743 744 checkForCorrectness(); 745 } 746 747 @Override 748 public void visitExports(JCExports tree) { 749 if (tree.directive.packge.members().isEmpty()) { 750 log.error(tree.qualid.pos(), Errors.PackageEmptyOrNotFound(tree.directive.packge)); 751 } 752 msym.directives = msym.directives.prepend(tree.directive); 753 } 754 755 MethodSymbol noArgsConstructor(ClassSymbol tsym) { 756 for (Symbol sym : tsym.members().getSymbolsByName(names.init)) { 757 MethodSymbol mSym = (MethodSymbol)sym; 758 if (mSym.params().isEmpty()) { 759 return mSym; 760 } 761 } 762 return null; 763 } 764 765 Map<Directive.ProvidesDirective, JCProvides> directiveToTreeMap = new HashMap<>(); 766 767 @Override 768 public void visitProvides(JCProvides tree) { 769 Type st = attr.attribType(tree.serviceName, env, syms.objectType); 770 Type it = attr.attribType(tree.implName, env, syms.objectType); 771 ClassSymbol service = (ClassSymbol) st.tsym; 772 ClassSymbol impl = (ClassSymbol) it.tsym; 773 if (!types.isSubtype(it, st)) { 774 log.error(tree.implName.pos(), Errors.ServiceImplementationMustBeSubtypeOfServiceInterface); 775 } 776 if ((impl.flags() & ABSTRACT) != 0) { 777 log.error(tree.implName.pos(), Errors.ServiceImplementationIsAbstract(impl)); 778 } else if (impl.isInner()) { 779 log.error(tree.implName.pos(), Errors.ServiceImplementationIsInner(impl)); 780 } else if (service.isInner()) { 781 log.error(tree.serviceName.pos(), Errors.ServiceDefinitionIsInner(service)); 782 } else { 783 MethodSymbol constr = noArgsConstructor(impl); 784 if (constr == null) { 785 log.error(tree.implName.pos(), Errors.ServiceImplementationDoesntHaveANoArgsConstructor(impl)); 786 } else if ((constr.flags() & PUBLIC) == 0) { 787 log.error(tree.implName.pos(), Errors.ServiceImplementationNoArgsConstructorNotPublic(impl)); 788 } 789 } 790 if (st.hasTag(CLASS) && it.hasTag(CLASS)) { 791 Directive.ProvidesDirective d = new Directive.ProvidesDirective(service, impl); 792 if (!allProvides.add(d)) { 793 log.error(tree.pos(), Errors.DuplicateProvides(service, impl)); 794 } 795 msym.provides = msym.provides.prepend(d); 796 msym.directives = msym.directives.prepend(d); 797 directiveToTreeMap.put(d, tree); 798 } 799 } 800 801 @Override 802 public void visitRequires(JCRequires tree) { 803 if (tree.directive != null) { 804 msym.directives = msym.directives.prepend(tree.directive); 805 } 806 } 807 808 @Override 809 public void visitUses(JCUses tree) { 810 Type st = attr.attribType(tree.qualid, env, syms.objectType); 811 Symbol sym = TreeInfo.symbol(tree.qualid); 812 if ((sym.flags() & ENUM) != 0) { 813 log.error(tree.qualid.pos(), Errors.ServiceDefinitionIsEnum(st.tsym)); 814 } else if (st.hasTag(CLASS)) { 815 ClassSymbol service = (ClassSymbol) st.tsym; 816 Directive.UsesDirective d = new Directive.UsesDirective(service); 817 if (!allUses.add(d)) { 818 log.error(tree.pos(), Errors.DuplicateUses(service)); 819 } 820 msym.uses = msym.uses.prepend(d); 821 msym.directives = msym.directives.prepend(d); 822 } 823 } 824 825 private void checkForCorrectness() { 826 for (Directive.ProvidesDirective provides : allProvides) { 827 JCProvides tree = directiveToTreeMap.get(provides); 828 /* The implementation must be defined in the same module as the provides directive 829 * (else, error) 830 */ 831 PackageSymbol implementationDefiningPackage = provides.impl.packge(); 832 if (implementationDefiningPackage.modle != msym) { 833 log.error(tree.pos(), Errors.ServiceImplementationNotInRightModule(implementationDefiningPackage.modle)); 834 } 835 836 /* There is no inherent requirement that module that provides a service should actually 837 * use it itself. However, it is a pointless declaration if the service package is not 838 * exported and there is no uses for the service. 839 */ 840 PackageSymbol interfaceDeclaringPackage = provides.service.packge(); 841 boolean isInterfaceDeclaredInCurrentModule = interfaceDeclaringPackage.modle == msym; 842 boolean isInterfaceExportedFromAReadableModule = 843 msym.visiblePackages.get(interfaceDeclaringPackage.fullname) == interfaceDeclaringPackage; 844 if (isInterfaceDeclaredInCurrentModule && !isInterfaceExportedFromAReadableModule) { 845 // ok the interface is declared in this module. Let's check if it's exported 846 boolean warn = true; 847 for (ExportsDirective export : msym.exports) { 848 if (interfaceDeclaringPackage == export.packge) { 849 warn = false; 850 break; 851 } 852 } 853 if (warn) { 854 for (UsesDirective uses : msym.uses) { 855 if (provides.service == uses.service) { 856 warn = false; 857 break; 858 } 859 } 860 } 861 if (warn) { 862 log.warning(tree.pos(), Warnings.ServiceProvidedButNotExportedOrUsed(provides.service)); 863 } 864 } 865 } 866 } 867 } 868 869 private Set<ModuleSymbol> allModules; 870 871 public Set<ModuleSymbol> allModules() { 872 Assert.checkNonNull(allModules); 873 return allModules; 874 } 875 876 private void setupAllModules() { 877 Assert.checkNonNull(rootModules); 878 Assert.checkNull(allModules); 879 880 Set<ModuleSymbol> observable; 881 882 if (limitModsOpt == null && extraLimitMods.isEmpty()) { 883 observable = null; 884 } else { 885 Set<ModuleSymbol> limitMods = new HashSet<>(); 886 if (limitModsOpt != null) { 887 for (String limit : limitModsOpt.split(",")) { 888 if (!isValidName(limit)) 889 continue; 890 limitMods.add(syms.enterModule(names.fromString(limit))); 891 } 892 } 893 for (String limit : extraLimitMods) { 894 limitMods.add(syms.enterModule(names.fromString(limit))); 895 } 896 observable = computeTransitiveClosure(limitMods, null); 897 observable.addAll(rootModules); 898 if (lintOptions) { 899 for (ModuleSymbol msym : limitMods) { 900 if (!observable.contains(msym)) { 901 log.warning(LintCategory.OPTIONS, 902 Warnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym)); 903 } 904 } 905 } 906 } 907 908 Predicate<ModuleSymbol> observablePred = sym -> observable == null || observable.contains(sym); 909 Predicate<ModuleSymbol> systemModulePred = sym -> (sym.flags() & Flags.SYSTEM_MODULE) != 0; 910 Set<ModuleSymbol> enabledRoot = new LinkedHashSet<>(); 911 912 if (rootModules.contains(syms.unnamedModule)) { 913 ModuleSymbol javaSE = syms.getModule(java_se); 914 Predicate<ModuleSymbol> jdkModulePred; 915 916 if (javaSE != null && (observable == null || observable.contains(javaSE))) { 917 jdkModulePred = sym -> { 918 sym.complete(); 919 return !sym.name.startsWith(java_) 920 && sym.exports.stream().anyMatch(e -> e.modules == null); 921 }; 922 enabledRoot.add(javaSE); 923 } else { 924 jdkModulePred = sym -> true; 925 } 926 927 for (ModuleSymbol sym : new HashSet<>(syms.getAllModules())) { 928 if (systemModulePred.test(sym) && observablePred.test(sym) && jdkModulePred.test(sym)) { 929 enabledRoot.add(sym); 930 } 931 } 932 } 933 934 enabledRoot.addAll(rootModules); 935 936 if (addModsOpt != null || !extraAddMods.isEmpty()) { 937 Set<String> fullAddMods = new HashSet<>(); 938 fullAddMods.addAll(extraAddMods); 939 940 if (addModsOpt != null) { 941 fullAddMods.addAll(Arrays.asList(addModsOpt.split(","))); 942 } 943 944 for (String added : fullAddMods) { 945 Stream<ModuleSymbol> modules; 946 switch (added) { 947 case ALL_SYSTEM: 948 modules = syms.getAllModules() 949 .stream() 950 .filter(systemModulePred.and(observablePred)); 951 break; 952 case ALL_MODULE_PATH: 953 modules = syms.getAllModules() 954 .stream() 955 .filter(systemModulePred.negate().and(observablePred)); 956 break; 957 default: 958 if (!isValidName(added)) 959 continue; 960 modules = Stream.of(syms.enterModule(names.fromString(added))); 961 break; 962 } 963 modules.forEach(sym -> { 964 enabledRoot.add(sym); 965 if (observable != null) 966 observable.add(sym); 967 }); 968 } 969 } 970 971 Set<ModuleSymbol> result = computeTransitiveClosure(enabledRoot, observable); 972 973 result.add(syms.unnamedModule); 974 975 allModules = result; 976 } 977 978 private Set<ModuleSymbol> computeTransitiveClosure(Iterable<? extends ModuleSymbol> base, Set<ModuleSymbol> observable) { 979 List<ModuleSymbol> todo = List.nil(); 980 981 for (ModuleSymbol ms : base) { 982 todo = todo.prepend(ms); 983 } 984 985 Set<ModuleSymbol> result = new LinkedHashSet<>(); 986 result.add(syms.java_base); 987 988 while (todo.nonEmpty()) { 989 ModuleSymbol current = todo.head; 990 todo = todo.tail; 991 if (observable != null && !observable.contains(current)) 992 continue; 993 if (!result.add(current) || current == syms.unnamedModule || ((current.flags_field & Flags.AUTOMATIC_MODULE) != 0)) 994 continue; 995 current.complete(); 996 for (RequiresDirective rd : current.requires) { 997 todo = todo.prepend(rd.module); 998 } 999 } 1000 1001 return result; 1002 } 1003 1004 public ModuleSymbol getObservableModule(Name name) { 1005 ModuleSymbol mod = syms.getModule(name); 1006 1007 if (allModules().contains(mod)) { 1008 return mod; 1009 } 1010 1011 return null; 1012 } 1013 1014 private Completer getUnnamedModuleCompleter() { 1015 moduleFinder.findAllModules(); 1016 return new Symbol.Completer() { 1017 @Override 1018 public void complete(Symbol sym) throws CompletionFailure { 1019 if (inInitModules) { 1020 sym.completer = this; 1021 return ; 1022 } 1023 ModuleSymbol msym = (ModuleSymbol) sym; 1024 Set<ModuleSymbol> allModules = allModules(); 1025 for (ModuleSymbol m : allModules) { 1026 m.complete(); 1027 } 1028 initVisiblePackages(msym, allModules); 1029 } 1030 1031 @Override 1032 public String toString() { 1033 return "unnamedModule Completer"; 1034 } 1035 }; 1036 } 1037 1038 private final Map<ModuleSymbol, Set<ModuleSymbol>> requiresPublicCache = new HashMap<>(); 1039 1040 private void completeModule(ModuleSymbol msym) { 1041 if (inInitModules) { 1042 msym.completer = sym -> completeModule(msym); 1043 return ; 1044 } 1045 1046 if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 1047 completeAutomaticModule(msym); 1048 } 1049 1050 Assert.checkNonNull(msym.requires); 1051 1052 initAddReads(); 1053 1054 msym.requires = msym.requires.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 1055 1056 List<RequiresDirective> requires = msym.requires; 1057 List<RequiresDirective> previous = null; 1058 1059 while (requires.nonEmpty()) { 1060 if (!allModules().contains(requires.head.module)) { 1061 Env<AttrContext> env = typeEnvs.get(msym); 1062 if (env != null) { 1063 JavaFileObject origSource = log.useSource(env.toplevel.sourcefile); 1064 try { 1065 log.error(/*XXX*/env.tree, Errors.ModuleNotFound(requires.head.module)); 1066 } finally { 1067 log.useSource(origSource); 1068 } 1069 } else { 1070 Assert.check((msym.flags() & Flags.AUTOMATIC_MODULE) == 0); 1071 } 1072 if (previous != null) { 1073 previous.tail = requires.tail; 1074 } else { 1075 msym.requires.tail = requires.tail; 1076 } 1077 } else { 1078 previous = requires; 1079 } 1080 requires = requires.tail; 1081 } 1082 1083 Set<ModuleSymbol> readable = new LinkedHashSet<>(); 1084 Set<ModuleSymbol> requiresPublic = new HashSet<>(); 1085 1086 for (RequiresDirective d : msym.requires) { 1087 d.module.complete(); 1088 readable.add(d.module); 1089 Set<ModuleSymbol> s = retrieveRequiresPublic(d.module); 1090 Assert.checkNonNull(s, () -> "no entry in cache for " + d.module); 1091 readable.addAll(s); 1092 if (d.flags.contains(RequiresFlag.PUBLIC)) { 1093 requiresPublic.add(d.module); 1094 requiresPublic.addAll(s); 1095 } 1096 } 1097 1098 requiresPublicCache.put(msym, requiresPublic); 1099 initVisiblePackages(msym, readable); 1100 for (ExportsDirective d: msym.exports) { 1101 d.packge.modle = msym; 1102 } 1103 1104 } 1105 1106 private Set<ModuleSymbol> retrieveRequiresPublic(ModuleSymbol msym) { 1107 Set<ModuleSymbol> requiresPublic = requiresPublicCache.get(msym); 1108 1109 if (requiresPublic == null) { 1110 //the module graph may contain cycles involving automatic modules or --add-reads edges 1111 requiresPublic = new HashSet<>(); 1112 1113 Set<ModuleSymbol> seen = new HashSet<>(); 1114 List<ModuleSymbol> todo = List.of(msym); 1115 1116 while (todo.nonEmpty()) { 1117 ModuleSymbol current = todo.head; 1118 todo = todo.tail; 1119 if (!seen.add(current)) 1120 continue; 1121 requiresPublic.add(current); 1122 current.complete(); 1123 Iterable<? extends RequiresDirective> requires; 1124 if (current != syms.unnamedModule) { 1125 Assert.checkNonNull(current.requires, () -> current + ".requires == null; " + msym); 1126 requires = current.requires; 1127 for (RequiresDirective rd : requires) { 1128 if (rd.isPublic()) 1129 todo = todo.prepend(rd.module); 1130 } 1131 } else { 1132 for (ModuleSymbol mod : allModules()) { 1133 todo = todo.prepend(mod); 1134 } 1135 } 1136 } 1137 1138 requiresPublic.remove(msym); 1139 } 1140 1141 return requiresPublic; 1142 } 1143 1144 private void initVisiblePackages(ModuleSymbol msym, Collection<ModuleSymbol> readable) { 1145 initAddExports(); 1146 1147 msym.visiblePackages = new LinkedHashMap<>(); 1148 1149 Map<Name, ModuleSymbol> seen = new HashMap<>(); 1150 1151 for (ModuleSymbol rm : readable) { 1152 if (rm == syms.unnamedModule) 1153 continue; 1154 addVisiblePackages(msym, seen, rm, rm.exports); 1155 } 1156 1157 addExports.forEach((exportsFrom, exports) -> { 1158 addVisiblePackages(msym, seen, exportsFrom, exports); 1159 }); 1160 } 1161 1162 private void addVisiblePackages(ModuleSymbol msym, 1163 Map<Name, ModuleSymbol> seenPackages, 1164 ModuleSymbol exportsFrom, 1165 Collection<ExportsDirective> exports) { 1166 for (ExportsDirective d : exports) { 1167 if (d.modules == null || d.modules.contains(msym)) { 1168 Name packageName = d.packge.fullname; 1169 ModuleSymbol previousModule = seenPackages.get(packageName); 1170 1171 if (previousModule != null && previousModule != exportsFrom) { 1172 Env<AttrContext> env = typeEnvs.get(msym); 1173 JavaFileObject origSource = env != null ? log.useSource(env.toplevel.sourcefile) 1174 : null; 1175 DiagnosticPosition pos = env != null ? env.tree.pos() : null; 1176 try { 1177 log.error(pos, Errors.PackageClashFromRequires(msym, packageName, 1178 previousModule, exportsFrom)); 1179 } finally { 1180 if (env != null) 1181 log.useSource(origSource); 1182 } 1183 continue; 1184 } 1185 1186 seenPackages.put(packageName, exportsFrom); 1187 msym.visiblePackages.put(d.packge.fullname, d.packge); 1188 } 1189 } 1190 } 1191 1192 private void initAddExports() { 1193 if (addExports != null) 1194 return; 1195 1196 addExports = new LinkedHashMap<>(); 1197 Set<ModuleSymbol> unknownModules = new HashSet<>(); 1198 1199 if (addExportsOpt == null) 1200 return; 1201 1202 Pattern ep = Pattern.compile("([^/]+)/([^=]+)=(.*)"); 1203 for (String s: addExportsOpt.split("\0+")) { 1204 if (s.isEmpty()) 1205 continue; 1206 Matcher em = ep.matcher(s); 1207 if (!em.matches()) { 1208 continue; 1209 } 1210 1211 // Terminology comes from 1212 // --add-exports module/package=target,... 1213 // Compare to 1214 // module module { exports package to target, ... } 1215 String moduleName = em.group(1); 1216 String packageName = em.group(2); 1217 String targetNames = em.group(3); 1218 1219 if (!isValidName(moduleName)) 1220 continue; 1221 1222 ModuleSymbol msym = syms.enterModule(names.fromString(moduleName)); 1223 if (!isKnownModule(msym, unknownModules)) 1224 continue; 1225 1226 if (!isValidName(packageName)) 1227 continue; 1228 PackageSymbol p = syms.enterPackage(msym, names.fromString(packageName)); 1229 p.modle = msym; // TODO: do we need this? 1230 1231 List<ModuleSymbol> targetModules = List.nil(); 1232 for (String toModule : targetNames.split("[ ,]+")) { 1233 ModuleSymbol m; 1234 if (toModule.equals("ALL-UNNAMED")) { 1235 m = syms.unnamedModule; 1236 } else { 1237 if (!isValidName(toModule)) 1238 continue; 1239 m = syms.enterModule(names.fromString(toModule)); 1240 if (!isKnownModule(m, unknownModules)) 1241 continue; 1242 } 1243 targetModules = targetModules.prepend(m); 1244 } 1245 1246 Set<ExportsDirective> extra = addExports.computeIfAbsent(msym, _x -> new LinkedHashSet<>()); 1247 ExportsDirective d = new ExportsDirective(p, targetModules); 1248 extra.add(d); 1249 } 1250 } 1251 1252 private boolean isKnownModule(ModuleSymbol msym, Set<ModuleSymbol> unknownModules) { 1253 if (allModules.contains(msym)) { 1254 return true; 1255 } 1256 1257 if (!unknownModules.contains(msym)) { 1258 if (lintOptions) { 1259 log.warning(LintCategory.OPTIONS, 1260 Warnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym)); 1261 } 1262 unknownModules.add(msym); 1263 } 1264 return false; 1265 } 1266 1267 private void initAddReads() { 1268 if (addReads != null) 1269 return; 1270 1271 addReads = new LinkedHashMap<>(); 1272 1273 if (addReadsOpt == null) 1274 return; 1275 1276 Pattern rp = Pattern.compile("([^=]+)=(.*)"); 1277 for (String s : addReadsOpt.split("\0+")) { 1278 if (s.isEmpty()) 1279 continue; 1280 Matcher rm = rp.matcher(s); 1281 if (!rm.matches()) { 1282 continue; 1283 } 1284 1285 // Terminology comes from 1286 // --add-reads source-module=target-module,... 1287 // Compare to 1288 // module source-module { requires target-module; ... } 1289 String sourceName = rm.group(1); 1290 String targetNames = rm.group(2); 1291 1292 if (!isValidName(sourceName)) 1293 continue; 1294 1295 ModuleSymbol msym = syms.enterModule(names.fromString(sourceName)); 1296 if (!allModules.contains(msym)) { 1297 if (lintOptions) { 1298 log.warning(Warnings.ModuleForOptionNotFound(Option.ADD_READS, msym)); 1299 } 1300 continue; 1301 } 1302 1303 for (String targetName : targetNames.split("[ ,]+", -1)) { 1304 ModuleSymbol targetModule; 1305 if (targetName.equals("ALL-UNNAMED")) { 1306 targetModule = syms.unnamedModule; 1307 } else { 1308 if (!isValidName(targetName)) 1309 continue; 1310 targetModule = syms.enterModule(names.fromString(targetName)); 1311 if (!allModules.contains(targetModule)) { 1312 if (lintOptions) { 1313 log.warning(LintCategory.OPTIONS, Warnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule)); 1314 } 1315 continue; 1316 } 1317 } 1318 addReads.computeIfAbsent(msym, m -> new HashSet<>()) 1319 .add(new RequiresDirective(targetModule, EnumSet.of(RequiresFlag.EXTRA))); 1320 } 1321 } 1322 } 1323 1324 private void checkCyclicDependencies(JCModuleDecl mod) { 1325 for (JCDirective d : mod.directives) { 1326 JCRequires rd; 1327 if (!d.hasTag(Tag.REQUIRES) || (rd = (JCRequires) d).directive == null) 1328 continue; 1329 Set<ModuleSymbol> nonSyntheticDeps = new HashSet<>(); 1330 List<ModuleSymbol> queue = List.of(rd.directive.module); 1331 while (queue.nonEmpty()) { 1332 ModuleSymbol current = queue.head; 1333 queue = queue.tail; 1334 if (!nonSyntheticDeps.add(current)) 1335 continue; 1336 current.complete(); 1337 if ((current.flags() & Flags.ACYCLIC) != 0) 1338 continue; 1339 Assert.checkNonNull(current.requires, () -> current.toString()); 1340 for (RequiresDirective dep : current.requires) { 1341 if (!dep.flags.contains(RequiresFlag.EXTRA)) 1342 queue = queue.prepend(dep.module); 1343 } 1344 } 1345 if (nonSyntheticDeps.contains(mod.sym)) { 1346 log.error(rd.moduleName.pos(), Errors.CyclicRequires(rd.directive.module)); 1347 } 1348 mod.sym.flags_field |= Flags.ACYCLIC; 1349 } 1350 } 1351 1352 private boolean isValidName(CharSequence name) { 1353 return SourceVersion.isName(name, Source.toSourceVersion(source)); 1354 } 1355 1356 // DEBUG 1357 private String toString(ModuleSymbol msym) { 1358 return msym.name + "[" 1359 + "kind:" + msym.kind + ";" 1360 + "locn:" + toString(msym.sourceLocation) + "," + toString(msym.classLocation) + ";" 1361 + "info:" + toString(msym.module_info.sourcefile) + "," 1362 + toString(msym.module_info.classfile) + "," 1363 + msym.module_info.completer 1364 + "]"; 1365 } 1366 1367 // DEBUG 1368 String toString(Location locn) { 1369 return (locn == null) ? "--" : locn.getName(); 1370 } 1371 1372 // DEBUG 1373 String toString(JavaFileObject fo) { 1374 return (fo == null) ? "--" : fo.getName(); 1375 } 1376 1377 public void newRound() { 1378 rootModules = null; 1379 allModules = null; 1380 } 1381} 1382