Modules.java revision 3770:d813bfb238a9
11541Srgrimes/* 21541Srgrimes * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. 31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41541Srgrimes * 51541Srgrimes * This code is free software; you can redistribute it and/or modify it 61541Srgrimes * under the terms of the GNU General Public License version 2 only, as 71541Srgrimes * published by the Free Software Foundation. Oracle designates this 81541Srgrimes * particular file as subject to the "Classpath" exception as provided 91541Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101541Srgrimes * 111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151541Srgrimes * accompanied this code). 161541Srgrimes * 171541Srgrimes * You should have received a copy of the GNU General Public License version 181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201541Srgrimes * 211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221541Srgrimes * or visit www.oracle.com if you need additional information or have any 231541Srgrimes * questions. 241541Srgrimes */ 251541Srgrimes 261541Srgrimes 271541Srgrimespackage com.sun.tools.javac.comp; 281541Srgrimes 291541Srgrimesimport java.io.IOException; 301541Srgrimesimport java.util.Arrays; 311541Srgrimesimport java.util.Collection; 321541Srgrimesimport java.util.Collections; 331541Srgrimesimport java.util.EnumSet; 3417663Sjulianimport java.util.HashMap; 351541Srgrimesimport java.util.HashSet; 361541Srgrimesimport java.util.LinkedHashMap; 371541Srgrimesimport java.util.LinkedHashSet; 381541Srgrimesimport java.util.Map; 391541Srgrimesimport java.util.Set; 401541Srgrimesimport java.util.function.Consumer; 411541Srgrimesimport java.util.function.Predicate; 421541Srgrimesimport java.util.regex.Matcher; 431541Srgrimesimport java.util.regex.Pattern; 441541Srgrimesimport java.util.stream.Stream; 451541Srgrimes 461541Srgrimesimport javax.lang.model.SourceVersion; 471541Srgrimesimport javax.tools.JavaFileManager; 481541Srgrimesimport javax.tools.JavaFileManager.Location; 4912662Sdgimport javax.tools.JavaFileObject; 509759Sbdeimport javax.tools.JavaFileObject.Kind; 5112662Sdgimport javax.tools.StandardLocation; 521541Srgrimes 5310653Sdgimport com.sun.tools.javac.code.ClassFinder; 5410358Sjulianimport com.sun.tools.javac.code.Directive; 5510358Sjulianimport com.sun.tools.javac.code.Directive.ExportsDirective; 569759Sbdeimport com.sun.tools.javac.code.Directive.RequiresDirective; 571541Srgrimesimport com.sun.tools.javac.code.Directive.RequiresFlag; 589759Sbdeimport com.sun.tools.javac.code.Directive.UsesDirective; 5915689Swollmanimport com.sun.tools.javac.code.Flags; 609759Sbdeimport com.sun.tools.javac.code.Kinds; 619759Sbdeimport com.sun.tools.javac.code.Lint.LintCategory; 629759Sbdeimport com.sun.tools.javac.code.ModuleFinder; 639759Sbdeimport com.sun.tools.javac.code.Source; 649759Sbdeimport com.sun.tools.javac.code.Symbol; 651541Srgrimesimport com.sun.tools.javac.code.Symbol.ClassSymbol; 6612819Sphkimport com.sun.tools.javac.code.Symbol.Completer; 6712819Sphkimport com.sun.tools.javac.code.Symbol.CompletionFailure; 6815736Sphkimport com.sun.tools.javac.code.Symbol.MethodSymbol; 6915736Sphkimport com.sun.tools.javac.code.Symbol.ModuleSymbol; 7015736Sphkimport com.sun.tools.javac.code.Symbol.PackageSymbol; 7115744Sphkimport com.sun.tools.javac.code.Symtab; 7215744Sphkimport com.sun.tools.javac.code.Type; 7310358Sjulianimport com.sun.tools.javac.code.Types; 7410358Sjulianimport com.sun.tools.javac.jvm.ClassWriter; 7512569Sbdeimport com.sun.tools.javac.jvm.JNIWriter; 7612569Sbdeimport com.sun.tools.javac.main.Option; 771541Srgrimesimport com.sun.tools.javac.resources.CompilerProperties.Errors; 781541Srgrimesimport com.sun.tools.javac.resources.CompilerProperties.Warnings; 791541Srgrimesimport com.sun.tools.javac.tree.JCTree; 8015689Swollmanimport com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 811541Srgrimesimport com.sun.tools.javac.tree.JCTree.JCExports; 8215689Swollmanimport com.sun.tools.javac.tree.JCTree.JCExpression; 8315689Swollmanimport com.sun.tools.javac.tree.JCTree.JCModuleDecl; 841541Srgrimesimport com.sun.tools.javac.tree.JCTree.JCPackageDecl; 851541Srgrimesimport com.sun.tools.javac.tree.JCTree.JCProvides; 861541Srgrimesimport com.sun.tools.javac.tree.JCTree.JCRequires; 871541Srgrimesimport com.sun.tools.javac.tree.JCTree.JCUses; 881541Srgrimesimport com.sun.tools.javac.tree.TreeInfo; 891541Srgrimesimport com.sun.tools.javac.util.Assert; 901541Srgrimesimport com.sun.tools.javac.util.Context; 911541Srgrimesimport com.sun.tools.javac.util.JCDiagnostic; 921541Srgrimesimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 9315689Swollmanimport com.sun.tools.javac.util.List; 9415689Swollmanimport com.sun.tools.javac.util.ListBuffer; 9515689Swollmanimport com.sun.tools.javac.util.Log; 9615689Swollmanimport com.sun.tools.javac.util.Name; 9715689Swollmanimport com.sun.tools.javac.util.Names; 9815689Swollmanimport com.sun.tools.javac.util.Options; 9915689Swollman 10015689Swollmanimport static com.sun.tools.javac.code.Flags.UNATTRIBUTED; 10115689Swollmanimport static com.sun.tools.javac.code.Kinds.Kind.MDL; 10215689Swollmanimport static com.sun.tools.javac.code.TypeTag.CLASS; 10315689Swollman 10415689Swollmanimport com.sun.tools.javac.tree.JCTree.JCDirective; 10515689Swollmanimport com.sun.tools.javac.tree.JCTree.Tag; 10615689Swollmanimport com.sun.tools.javac.util.Abort; 10715689Swollmanimport com.sun.tools.javac.util.Position; 10815689Swollman 10915689Swollmanimport static com.sun.tools.javac.code.Flags.ABSTRACT; 11015689Swollmanimport static com.sun.tools.javac.code.Flags.ENUM; 11115689Swollmanimport static com.sun.tools.javac.code.Flags.PUBLIC; 11215689Swollmanimport static com.sun.tools.javac.tree.JCTree.Tag.MODULEDEF; 11315689Swollman 11415689Swollman/** 11515689Swollman * TODO: fill in 11615689Swollman * 11715689Swollman * <p><b>This is NOT part of any supported API. 11815689Swollman * If you write code that depends on this, you do so at your own risk. 11915689Swollman * This code and its internal interfaces are subject to change or 12015689Swollman * deletion without notice.</b> 12115689Swollman */ 12215689Swollmanpublic class Modules extends JCTree.Visitor { 12315689Swollman private static final String ALL_SYSTEM = "ALL-SYSTEM"; 12415689Swollman private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; 12515689Swollman 12615689Swollman private final Log log; 12715689Swollman private final Names names; 12815689Swollman private final Symtab syms; 12915689Swollman private final Attr attr; 13015689Swollman private final TypeEnvs typeEnvs; 13115689Swollman private final Types types; 13215689Swollman private final JavaFileManager fileManager; 13315689Swollman private final ModuleFinder moduleFinder; 1341541Srgrimes private final Source source; 1351541Srgrimes private final boolean allowModules; 1361541Srgrimes 1371541Srgrimes public final boolean multiModuleMode; 1381541Srgrimes 1391549Srgrimes private final String moduleOverride; 1401541Srgrimes 1411541Srgrimes private final Name java_se; 1421541Srgrimes private final Name java_; 1431541Srgrimes 1441541Srgrimes ModuleSymbol defaultModule; 1451541Srgrimes 1461541Srgrimes private final String addExportsOpt; 1471541Srgrimes private Map<ModuleSymbol, Set<ExportsDirective>> addExports; 1487066Sdg private final String addReadsOpt; 1497066Sdg private Map<ModuleSymbol, Set<RequiresDirective>> addReads; 1507066Sdg private final String addModsOpt; 1517066Sdg private final Set<String> extraAddMods = new HashSet<>(); 1527066Sdg private final String limitModsOpt; 15315722Swollman private final Set<String> extraLimitMods = new HashSet<>(); 1547066Sdg 1557066Sdg private final boolean lintOptions; 15615543Sphk 15715722Swollman private Set<ModuleSymbol> rootModules = null; 1586191Sbde 1597066Sdg public static Modules instance(Context context) { 1607066Sdg Modules instance = context.get(Modules.class); 1617066Sdg if (instance == null) 1627066Sdg instance = new Modules(context); 1637066Sdg return instance; 1641541Srgrimes } 1657066Sdg 16615543Sphk protected Modules(Context context) { 1671541Srgrimes context.put(Modules.class, this); 1681541Srgrimes log = Log.instance(context); 1691541Srgrimes names = Names.instance(context); 1701541Srgrimes syms = Symtab.instance(context); 1711541Srgrimes attr = Attr.instance(context); 1721541Srgrimes typeEnvs = TypeEnvs.instance(context); 1731541Srgrimes moduleFinder = ModuleFinder.instance(context); 1741541Srgrimes types = Types.instance(context); 1751541Srgrimes fileManager = context.get(JavaFileManager.class); 1761541Srgrimes source = Source.instance(context); 1771541Srgrimes allowModules = source.allowModules(); 1781541Srgrimes Options options = Options.instance(context); 1791541Srgrimes 1801541Srgrimes lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option); 1811541Srgrimes 1821541Srgrimes moduleOverride = options.get(Option.XMODULE); 1831541Srgrimes 1841541Srgrimes multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH); 1851541Srgrimes ClassWriter classWriter = ClassWriter.instance(context); 1861541Srgrimes classWriter.multiModuleMode = multiModuleMode; 1871541Srgrimes JNIWriter jniWriter = JNIWriter.instance(context); 1881541Srgrimes jniWriter.multiModuleMode = multiModuleMode; 1891541Srgrimes 1901541Srgrimes java_se = names.fromString("java.se"); 1916669Sdg java_ = names.fromString("java."); 1926669Sdg 1936669Sdg addExportsOpt = options.get(Option.ADD_EXPORTS); 1946669Sdg addReadsOpt = options.get(Option.ADD_READS); 1951541Srgrimes addModsOpt = options.get(Option.ADD_MODULES); 1961541Srgrimes limitModsOpt = options.get(Option.LIMIT_MODULES); 1971541Srgrimes } 1981541Srgrimes 1991541Srgrimes int depth = -1; 2001541Srgrimes private void dprintln(String msg) { 2011541Srgrimes for (int i = 0; i < depth; i++) 2021541Srgrimes System.err.print(" "); 2031541Srgrimes System.err.println(msg); 2041541Srgrimes } 2051541Srgrimes 2061541Srgrimes public void addExtraAddModules(String... extras) { 2071541Srgrimes extraAddMods.addAll(Arrays.asList(extras)); 2081541Srgrimes } 2091541Srgrimes 2101541Srgrimes public void addExtraLimitModules(String... extras) { 2116669Sdg extraLimitMods.addAll(Arrays.asList(extras)); 2126669Sdg } 2136669Sdg 2146669Sdg boolean inInitModules; 2151541Srgrimes public void initModules(List<JCCompilationUnit> trees) { 2161541Srgrimes Assert.check(!inInitModules); 2171541Srgrimes try { 21812819Sphk inInitModules = true; 2191541Srgrimes Assert.checkNull(rootModules); 2201541Srgrimes enter(trees, modules -> { 2211541Srgrimes Assert.checkNull(rootModules); 2221541Srgrimes Assert.checkNull(allModules); 2231541Srgrimes this.rootModules = modules; 2241541Srgrimes setupAllModules(); //initialize the module graph 2251541Srgrimes Assert.checkNonNull(allModules); 2261541Srgrimes inInitModules = false; 2271541Srgrimes }, null); 2281541Srgrimes } finally { 2291541Srgrimes inInitModules = false; 2301541Srgrimes } 2311541Srgrimes } 2321541Srgrimes 2331541Srgrimes public boolean enter(List<JCCompilationUnit> trees, ClassSymbol c) { 2341541Srgrimes Assert.check(rootModules != null || inInitModules || !allowModules); 2351541Srgrimes return enter(trees, modules -> {}, c); 2361541Srgrimes } 2371541Srgrimes 2381541Srgrimes private boolean enter(List<JCCompilationUnit> trees, Consumer<Set<ModuleSymbol>> init, ClassSymbol c) { 2391541Srgrimes if (!allowModules) { 2401541Srgrimes for (JCCompilationUnit tree: trees) { 2411541Srgrimes tree.modle = syms.noModule; 2421541Srgrimes } 2431541Srgrimes defaultModule = syms.noModule; 2441541Srgrimes return true; 2451541Srgrimes } 2461541Srgrimes 2471541Srgrimes int startErrors = log.nerrors; 2481541Srgrimes 2491541Srgrimes depth++; 2501541Srgrimes try { 2511541Srgrimes // scan trees for module defs 2521541Srgrimes Set<ModuleSymbol> roots = enterModules(trees, c); 2531541Srgrimes 2541541Srgrimes setCompilationUnitModules(trees, roots); 2551541Srgrimes 2561541Srgrimes init.accept(roots); 2571541Srgrimes 2581541Srgrimes for (ModuleSymbol msym: roots) { 2591541Srgrimes msym.complete(); 2601541Srgrimes } 2611541Srgrimes } catch (CompletionFailure ex) { 2621541Srgrimes log.error(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE, Position.NOPOS, "cant.access", ex.sym, ex.getDetailValue()); 2631541Srgrimes if (ex instanceof ClassFinder.BadClassFile) throw new Abort(); 2641541Srgrimes } finally { 2651541Srgrimes depth--; 2661541Srgrimes } 2671541Srgrimes 2681541Srgrimes return (log.nerrors == startErrors); 2691541Srgrimes } 2701541Srgrimes 2711541Srgrimes public Completer getCompleter() { 2721541Srgrimes return mainCompleter; 2731541Srgrimes } 2741541Srgrimes 2751541Srgrimes public ModuleSymbol getDefaultModule() { 2761541Srgrimes return defaultModule; 2771541Srgrimes } 2781541Srgrimes 2791541Srgrimes private Set<ModuleSymbol> enterModules(List<JCCompilationUnit> trees, ClassSymbol c) { 2801541Srgrimes Set<ModuleSymbol> modules = new LinkedHashSet<>(); 2811541Srgrimes for (JCCompilationUnit tree : trees) { 2821541Srgrimes JavaFileObject prev = log.useSource(tree.sourcefile); 2831541Srgrimes try { 2841541Srgrimes enterModule(tree, c, modules); 2851541Srgrimes } finally { 2861541Srgrimes log.useSource(prev); 2871541Srgrimes } 2881541Srgrimes } 2891541Srgrimes return modules; 2901541Srgrimes } 2913308Sphk 2923308Sphk 2931541Srgrimes private void enterModule(JCCompilationUnit toplevel, ClassSymbol c, Set<ModuleSymbol> modules) { 2941541Srgrimes boolean isModuleInfo = toplevel.sourcefile.isNameCompatible("module-info", Kind.SOURCE); 2951541Srgrimes boolean isModuleDecl = toplevel.defs.nonEmpty() && toplevel.defs.head.hasTag(MODULEDEF); 2961541Srgrimes if (isModuleDecl) { 2971541Srgrimes JCModuleDecl decl = (JCModuleDecl) toplevel.defs.head; 2981541Srgrimes if (!isModuleInfo) { 2991541Srgrimes log.error(decl.pos(), Errors.ModuleDeclSbInModuleInfoJava); 3001541Srgrimes } 3011541Srgrimes Name name = TreeInfo.fullName(decl.qualId); 3021541Srgrimes ModuleSymbol sym; 3031541Srgrimes if (c != null) { 3041541Srgrimes sym = (ModuleSymbol) c.owner; 3051541Srgrimes Assert.checkNonNull(sym.name); 3061541Srgrimes Name treeName = TreeInfo.fullName(decl.qualId); 3071541Srgrimes if (sym.name != treeName) { 3081541Srgrimes log.error(decl.pos(), Errors.ModuleNameMismatch(name, sym.name)); 3091541Srgrimes } 3101541Srgrimes } else { 3111541Srgrimes sym = syms.enterModule(name); 3121541Srgrimes if (sym.module_info.sourcefile != null && sym.module_info.sourcefile != toplevel.sourcefile) { 3131541Srgrimes log.error(decl.pos(), Errors.DuplicateModule(sym)); 3141541Srgrimes return; 3151541Srgrimes } 3161541Srgrimes } 3171541Srgrimes sym.completer = getSourceCompleter(toplevel); 3181541Srgrimes sym.module_info.sourcefile = toplevel.sourcefile; 3191541Srgrimes decl.sym = sym; 3201541Srgrimes 3211541Srgrimes if (multiModuleMode || modules.isEmpty()) { 3221541Srgrimes modules.add(sym); 3231541Srgrimes } else { 3241541Srgrimes log.error(toplevel.pos(), Errors.TooManyModules); 3251541Srgrimes } 3261541Srgrimes 3271541Srgrimes Env<AttrContext> provisionalEnv = new Env<>(decl, null); 3281541Srgrimes 3291541Srgrimes provisionalEnv.toplevel = toplevel; 3301541Srgrimes typeEnvs.put(sym, provisionalEnv); 3311541Srgrimes } else if (isModuleInfo) { 3321541Srgrimes if (multiModuleMode) { 33312819Sphk JCTree tree = toplevel.defs.isEmpty() ? toplevel : toplevel.defs.head; 3341541Srgrimes log.error(tree.pos(), Errors.ExpectedModule); 3351541Srgrimes } 3361541Srgrimes } 3371541Srgrimes } 3381541Srgrimes 3391541Srgrimes private void setCompilationUnitModules(List<JCCompilationUnit> trees, Set<ModuleSymbol> rootModules) { 3401541Srgrimes // update the module for each compilation unit 3411541Srgrimes if (multiModuleMode) { 3421541Srgrimes checkNoAllModulePath(); 3431541Srgrimes for (JCCompilationUnit tree: trees) { 3441541Srgrimes if (tree.defs.isEmpty()) { 3451541Srgrimes tree.modle = syms.unnamedModule; 3461541Srgrimes continue; 3471541Srgrimes } 3481541Srgrimes 3491541Srgrimes JavaFileObject prev = log.useSource(tree.sourcefile); 3501541Srgrimes try { 3511541Srgrimes Location locn = getModuleLocation(tree); 3521541Srgrimes if (locn != null) { 3531541Srgrimes Name name = names.fromString(fileManager.inferModuleName(locn)); 3541541Srgrimes ModuleSymbol msym; 3551541Srgrimes if (tree.defs.head.hasTag(MODULEDEF)) { 3561541Srgrimes JCModuleDecl decl = (JCModuleDecl) tree.defs.head; 3571541Srgrimes msym = decl.sym; 3581541Srgrimes if (msym.name != name) { 3591541Srgrimes log.error(decl.qualId, Errors.ModuleNameMismatch(msym.name, name)); 3601541Srgrimes } 3611541Srgrimes } else { 3621541Srgrimes msym = syms.enterModule(name); 3631541Srgrimes } 3641541Srgrimes if (msym.sourceLocation == null) { 3651541Srgrimes msym.sourceLocation = locn; 3661541Srgrimes if (fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) { 3671541Srgrimes msym.classLocation = fileManager.getLocationForModule( 3681541Srgrimes StandardLocation.CLASS_OUTPUT, msym.name.toString()); 3691541Srgrimes } 3701541Srgrimes } 3711541Srgrimes tree.modle = msym; 3721541Srgrimes rootModules.add(msym); 3731541Srgrimes } else { 3741541Srgrimes log.error(tree.pos(), Errors.UnnamedPkgNotAllowedNamedModules); 3751541Srgrimes tree.modle = syms.errModule; 3761541Srgrimes } 3771541Srgrimes } catch (IOException e) { 3781541Srgrimes throw new Error(e); // FIXME 3791541Srgrimes } finally { 3801541Srgrimes log.useSource(prev); 38117663Sjulian } 38217663Sjulian } 38317663Sjulian if (syms.unnamedModule.sourceLocation == null) { 38417663Sjulian syms.unnamedModule.completer = getUnnamedModuleCompleter(); 38517663Sjulian syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH; 3861541Srgrimes syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH; 3871541Srgrimes } 3881541Srgrimes defaultModule = syms.unnamedModule; 3891541Srgrimes } else { 3901541Srgrimes if (defaultModule == null) { 3911541Srgrimes switch (rootModules.size()) { 3921541Srgrimes case 0: 3931541Srgrimes defaultModule = moduleFinder.findSingleModule(); 3941541Srgrimes if (defaultModule == syms.unnamedModule) { 3951541Srgrimes if (moduleOverride != null) { 3961541Srgrimes checkNoAllModulePath(); 3971541Srgrimes defaultModule = moduleFinder.findModule(names.fromString(moduleOverride)); 3981541Srgrimes defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 3991541Srgrimes } else { 4001541Srgrimes // Question: why not do findAllModules and initVisiblePackages here? 4011541Srgrimes // i.e. body of unnamedModuleCompleter 4021541Srgrimes defaultModule.completer = getUnnamedModuleCompleter(); 4031541Srgrimes defaultModule.classLocation = StandardLocation.CLASS_PATH; 4041541Srgrimes } 4051541Srgrimes } else { 4061541Srgrimes checkSpecifiedModule(trees, Errors.ModuleInfoWithXmoduleClasspath); 40715689Swollman checkNoAllModulePath(); 40815689Swollman defaultModule.complete(); 40915689Swollman // Question: why not do completeModule here? 41015689Swollman defaultModule.completer = new Completer() { 41115689Swollman @Override 41215689Swollman public void complete(Symbol sym) throws CompletionFailure { 41315689Swollman completeModule((ModuleSymbol) sym); 41415689Swollman } 41515689Swollman }; 41615689Swollman } 41715689Swollman rootModules.add(defaultModule); 41815689Swollman break; 41915689Swollman case 1: 42015689Swollman checkSpecifiedModule(trees, Errors.ModuleInfoWithXmoduleSourcepath); 42115689Swollman checkNoAllModulePath(); 42215689Swollman defaultModule = rootModules.iterator().next(); 42315689Swollman defaultModule.classLocation = StandardLocation.CLASS_OUTPUT; 42415689Swollman break; 42515689Swollman default: 42615689Swollman Assert.error("too many modules"); 42715689Swollman } 42815689Swollman defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 42915689Swollman } else if (rootModules.size() == 1 && defaultModule == rootModules.iterator().next()) { 43015689Swollman defaultModule.complete(); 43115689Swollman defaultModule.completer = sym -> completeModule((ModuleSymbol) sym); 43215689Swollman } else { 43315689Swollman Assert.check(rootModules.isEmpty()); 43415689Swollman rootModules.add(defaultModule); 43515689Swollman } 43615689Swollman 43715689Swollman if (defaultModule != syms.unnamedModule) { 43815689Swollman syms.unnamedModule.completer = getUnnamedModuleCompleter(); 43915689Swollman if (moduleOverride == null) { 44015689Swollman syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH; 44115689Swollman } 44215689Swollman syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH; 44315689Swollman } 44415689Swollman 44515689Swollman for (JCCompilationUnit tree: trees) { 44615689Swollman tree.modle = defaultModule; 44715689Swollman } 44815689Swollman } 44915689Swollman } 45015689Swollman 45115689Swollman private Location getModuleLocation(JCCompilationUnit tree) throws IOException { 45215689Swollman switch (tree.defs.head.getTag()) { 45315689Swollman case MODULEDEF: 45415689Swollman return getModuleLocation(tree.sourcefile, null); 45515689Swollman 45615689Swollman case PACKAGEDEF: 45715689Swollman JCPackageDecl pkg = (JCPackageDecl) tree.defs.head; 45815689Swollman return getModuleLocation(tree.sourcefile, TreeInfo.fullName(pkg.pid)); 45915689Swollman 46015689Swollman default: 46115689Swollman // code in unnamed module 4621541Srgrimes return null; 4631541Srgrimes } 4641541Srgrimes } 4651549Srgrimes 4661541Srgrimes private Location getModuleLocation(JavaFileObject fo, Name pkgName) throws IOException { 4671541Srgrimes // For now, just check module source path. 4681541Srgrimes // We may want to check source path as well. 4691541Srgrimes return fileManager.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, 4701541Srgrimes fo, (pkgName == null) ? null : pkgName.toString()); 4711541Srgrimes } 4721541Srgrimes 4731541Srgrimes private void checkSpecifiedModule(List<JCCompilationUnit> trees, JCDiagnostic.Error error) { 4741541Srgrimes if (moduleOverride != null) { 4751541Srgrimes JavaFileObject prev = log.useSource(trees.head.sourcefile); 4761541Srgrimes try { 4771541Srgrimes log.error(trees.head.pos(), error); 4781541Srgrimes } finally { 4791541Srgrimes log.useSource(prev); 4801541Srgrimes } 4811541Srgrimes } 4821541Srgrimes } 4831541Srgrimes 4841541Srgrimes private void checkNoAllModulePath() { 4851541Srgrimes if (addModsOpt != null && Arrays.asList(addModsOpt.split(",")).contains(ALL_MODULE_PATH)) { 4861541Srgrimes log.error(Errors.AddmodsAllModulePathInvalid); 4871541Srgrimes } 4881541Srgrimes } 4891541Srgrimes 4901541Srgrimes private final Completer mainCompleter = new Completer() { 4911541Srgrimes @Override 4921541Srgrimes public void complete(Symbol sym) throws CompletionFailure { 4931541Srgrimes ModuleSymbol msym = moduleFinder.findModule((ModuleSymbol) sym); 4941541Srgrimes 4951541Srgrimes if (msym.kind == Kinds.Kind.ERR) { 4961541Srgrimes log.error(Errors.ModuleNotFound(msym)); 4971541Srgrimes //make sure the module is initialized: 4981541Srgrimes msym.directives = List.nil(); 4991541Srgrimes msym.exports = List.nil(); 5001541Srgrimes msym.provides = List.nil(); 5011549Srgrimes msym.requires = List.nil(); 5021541Srgrimes msym.uses = List.nil(); 5031541Srgrimes } else if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 5041541Srgrimes setupAutomaticModule(msym); 5051541Srgrimes } else { 5061541Srgrimes msym.module_info.complete(); 5071541Srgrimes } 5081541Srgrimes 5091541Srgrimes // If module-info comes from a .java file, the underlying 5101541Srgrimes // call of classFinder.fillIn will have called through the 5111541Srgrimes // source completer, to Enter, and then to Modules.enter, 5121541Srgrimes // which will call completeModule. 5131541Srgrimes // But, if module-info comes from a .class file, the underlying 5141541Srgrimes // call of classFinder.fillIn will just call ClassReader to read 5151541Srgrimes // the .class file, and so we call completeModule here. 5161541Srgrimes if (msym.module_info.classfile == null || msym.module_info.classfile.getKind() == Kind.CLASS) { 5171541Srgrimes completeModule(msym); 5181541Srgrimes } 5191541Srgrimes } 5201541Srgrimes 5211541Srgrimes @Override 5221549Srgrimes public String toString() { 5231541Srgrimes return "mainCompleter"; 5241541Srgrimes } 5251541Srgrimes }; 5261541Srgrimes 5271541Srgrimes private void setupAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 5281541Srgrimes try { 5291541Srgrimes ListBuffer<Directive> directives = new ListBuffer<>(); 5301541Srgrimes ListBuffer<ExportsDirective> exports = new ListBuffer<>(); 5311541Srgrimes Set<String> seenPackages = new HashSet<>(); 5321541Srgrimes 5331541Srgrimes for (JavaFileObject clazz : fileManager.list(msym.classLocation, "", EnumSet.of(Kind.CLASS), true)) { 5341541Srgrimes String binName = fileManager.inferBinaryName(msym.classLocation, clazz); 5351541Srgrimes String pack = binName.lastIndexOf('.') != (-1) ? binName.substring(0, binName.lastIndexOf('.')) : ""; //unnamed package???? 5361541Srgrimes if (seenPackages.add(pack)) { 5371541Srgrimes ExportsDirective d = new ExportsDirective(syms.enterPackage(msym, names.fromString(pack)), null); 5381541Srgrimes directives.add(d); 5391541Srgrimes exports.add(d); 5401541Srgrimes } 5411541Srgrimes } 5421541Srgrimes 5431541Srgrimes msym.exports = exports.toList(); 5441541Srgrimes msym.provides = List.nil(); 5451541Srgrimes msym.requires = List.nil(); 5461541Srgrimes msym.uses = List.nil(); 5471541Srgrimes msym.directives = directives.toList(); 5481541Srgrimes msym.flags_field |= Flags.ACYCLIC; 5491541Srgrimes } catch (IOException ex) { 5501541Srgrimes throw new IllegalStateException(ex); 5511541Srgrimes } 5521541Srgrimes } 5531541Srgrimes 5541541Srgrimes private void completeAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 5551541Srgrimes ListBuffer<Directive> directives = new ListBuffer<>(); 5561541Srgrimes 5571541Srgrimes directives.addAll(msym.directives); 5581541Srgrimes 5591541Srgrimes ListBuffer<RequiresDirective> requires = new ListBuffer<>(); 5601541Srgrimes 5611541Srgrimes for (ModuleSymbol ms : allModules()) { 5621541Srgrimes if (ms == syms.unnamedModule || ms == msym) 5631541Srgrimes continue; 5641541Srgrimes Set<RequiresFlag> flags = (ms.flags_field & Flags.AUTOMATIC_MODULE) != 0 ? 5651541Srgrimes EnumSet.of(RequiresFlag.PUBLIC) : EnumSet.noneOf(RequiresFlag.class); 5661541Srgrimes RequiresDirective d = new RequiresDirective(ms, flags); 5671541Srgrimes directives.add(d); 5681541Srgrimes requires.add(d); 5691541Srgrimes } 5701541Srgrimes 5711541Srgrimes RequiresDirective requiresUnnamed = new RequiresDirective(syms.unnamedModule); 5721541Srgrimes directives.add(requiresUnnamed); 5731541Srgrimes requires.add(requiresUnnamed); 5741541Srgrimes 5751541Srgrimes msym.requires = requires.toList(); 5761541Srgrimes msym.directives = directives.toList(); 5771541Srgrimes } 5781541Srgrimes 5791541Srgrimes private Completer getSourceCompleter(JCCompilationUnit tree) { 5801541Srgrimes return new Completer() { 5811541Srgrimes @Override 5821541Srgrimes public void complete(Symbol sym) throws CompletionFailure { 5831541Srgrimes ModuleSymbol msym = (ModuleSymbol) sym; 5841541Srgrimes msym.flags_field |= UNATTRIBUTED; 5851541Srgrimes ModuleVisitor v = new ModuleVisitor(); 5861541Srgrimes JavaFileObject prev = log.useSource(tree.sourcefile); 5871541Srgrimes try { 5881541Srgrimes tree.defs.head.accept(v); 5891541Srgrimes checkCyclicDependencies((JCModuleDecl) tree.defs.head); 5901541Srgrimes completeModule(msym); 5913308Sphk } finally { 5923308Sphk log.useSource(prev); 5931541Srgrimes msym.flags_field &= ~UNATTRIBUTED; 5941541Srgrimes } 5951541Srgrimes } 5961541Srgrimes 5971541Srgrimes @Override 5981541Srgrimes public String toString() { 5991541Srgrimes return "SourceCompleter: " + tree.sourcefile.getName(); 6001541Srgrimes } 6011541Srgrimes 6021541Srgrimes }; 6031541Srgrimes } 60412819Sphk 6051541Srgrimes class ModuleVisitor extends JCTree.Visitor { 6061541Srgrimes private ModuleSymbol sym; 6071541Srgrimes private final Set<ModuleSymbol> allRequires = new HashSet<>(); 6081541Srgrimes private final Set<PackageSymbol> allExports = new HashSet<>(); 6091541Srgrimes 6101541Srgrimes @Override 6111541Srgrimes public void visitModuleDef(JCModuleDecl tree) { 6121541Srgrimes sym = Assert.checkNonNull(tree.sym); 6131541Srgrimes 6141541Srgrimes sym.requires = List.nil(); 6151541Srgrimes sym.exports = List.nil(); 6161541Srgrimes tree.directives.forEach(t -> t.accept(this)); 6171541Srgrimes sym.requires = sym.requires.reverse(); 6181541Srgrimes sym.exports = sym.exports.reverse(); 6191541Srgrimes ensureJavaBase(); 6201541Srgrimes } 6211541Srgrimes 6221541Srgrimes @Override 6231541Srgrimes public void visitRequires(JCRequires tree) { 6241541Srgrimes ModuleSymbol msym = lookupModule(tree.moduleName); 6251541Srgrimes if (msym.kind != MDL) { 6261541Srgrimes log.error(tree.moduleName.pos(), Errors.ModuleNotFound(msym)); 6271541Srgrimes } else if (allRequires.contains(msym)) { 6281541Srgrimes log.error(tree.moduleName.pos(), Errors.DuplicateRequires(msym)); 6291541Srgrimes } else { 6301541Srgrimes allRequires.add(msym); 6311541Srgrimes Set<RequiresFlag> flags = EnumSet.noneOf(RequiresFlag.class); 6321541Srgrimes if (tree.isPublic) 6331541Srgrimes flags.add(RequiresFlag.PUBLIC); 6341541Srgrimes RequiresDirective d = new RequiresDirective(msym, flags); 6351541Srgrimes tree.directive = d; 6361541Srgrimes sym.requires = sym.requires.prepend(d); 6371541Srgrimes } 6381541Srgrimes } 6391541Srgrimes 6401541Srgrimes @Override 6411541Srgrimes public void visitExports(JCExports tree) { 6421541Srgrimes Name name = TreeInfo.fullName(tree.qualid); 6431541Srgrimes PackageSymbol packge = syms.enterPackage(sym, name); 6441541Srgrimes attr.setPackageSymbols(tree.qualid, packge); 6451541Srgrimes if (!allExports.add(packge)) { 6461541Srgrimes log.error(tree.qualid.pos(), Errors.DuplicateExports(packge)); 6471541Srgrimes } 6481541Srgrimes 6491541Srgrimes List<ModuleSymbol> toModules = null; 6501541Srgrimes if (tree.moduleNames != null) { 6511541Srgrimes Set<ModuleSymbol> to = new HashSet<>(); 6521541Srgrimes for (JCExpression n: tree.moduleNames) { 6531541Srgrimes ModuleSymbol msym = lookupModule(n); 6541541Srgrimes if (msym.kind != MDL) { 6551541Srgrimes log.error(n.pos(), Errors.ModuleNotFound(msym)); 6561541Srgrimes } else if (!to.add(msym)) { 6571541Srgrimes log.error(n.pos(), Errors.DuplicateExports(msym)); 6581541Srgrimes } 6591541Srgrimes } 6601541Srgrimes toModules = List.from(to); 6611541Srgrimes } 6621541Srgrimes 6631541Srgrimes if (toModules == null || !toModules.isEmpty()) { 6641541Srgrimes ExportsDirective d = new ExportsDirective(packge, toModules); 6651541Srgrimes tree.directive = d; 6661541Srgrimes sym.exports = sym.exports.prepend(d); 6671541Srgrimes } 6681541Srgrimes } 6691541Srgrimes 6701541Srgrimes @Override 6711541Srgrimes public void visitProvides(JCProvides tree) { } 6721541Srgrimes 6731541Srgrimes @Override 6741541Srgrimes public void visitUses(JCUses tree) { } 6751541Srgrimes 6761541Srgrimes private void ensureJavaBase() { 6771541Srgrimes if (sym.name == names.java_base) 6781541Srgrimes return; 6791541Srgrimes 6801541Srgrimes for (RequiresDirective d: sym.requires) { 6811541Srgrimes if (d.module.name == names.java_base) 6821541Srgrimes return; 6831541Srgrimes } 6841541Srgrimes 6851541Srgrimes ModuleSymbol java_base = syms.enterModule(names.java_base); 6861541Srgrimes Directive.RequiresDirective d = 6871541Srgrimes new Directive.RequiresDirective(java_base, 6881541Srgrimes EnumSet.of(Directive.RequiresFlag.MANDATED)); 6891541Srgrimes sym.requires = sym.requires.prepend(d); 6901541Srgrimes } 6911541Srgrimes 6921541Srgrimes private ModuleSymbol lookupModule(JCExpression moduleName) { 6931541Srgrimes Name name = TreeInfo.fullName(moduleName); 6941541Srgrimes ModuleSymbol msym = moduleFinder.findModule(name); 6951541Srgrimes TreeInfo.setSymbol(moduleName, msym); 6961541Srgrimes return msym; 6971541Srgrimes } 6981541Srgrimes } 6991541Srgrimes 7001541Srgrimes public Completer getUsesProvidesCompleter() { 7011541Srgrimes return sym -> { 7021541Srgrimes ModuleSymbol msym = (ModuleSymbol) sym; 7031541Srgrimes 7041541Srgrimes msym.complete(); 7051541Srgrimes 7061541Srgrimes Env<AttrContext> env = typeEnvs.get(msym); 7071541Srgrimes UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env); 7081541Srgrimes JavaFileObject prev = log.useSource(env.toplevel.sourcefile); 7091541Srgrimes try { 7101541Srgrimes env.toplevel.defs.head.accept(v); 7111541Srgrimes } finally { 7121541Srgrimes log.useSource(prev); 7131541Srgrimes } 7141541Srgrimes }; 7151541Srgrimes } 7161541Srgrimes 71717663Sjulian class UsesProvidesVisitor extends JCTree.Visitor { 71817663Sjulian private final ModuleSymbol msym; 71917663Sjulian private final Env<AttrContext> env; 72017663Sjulian 72117663Sjulian private final Set<Directive.UsesDirective> allUses = new HashSet<>(); 7221541Srgrimes private final Set<Directive.ProvidesDirective> allProvides = new HashSet<>(); 7231541Srgrimes 7241541Srgrimes public UsesProvidesVisitor(ModuleSymbol msym, Env<AttrContext> env) { 7251541Srgrimes this.msym = msym; 7261541Srgrimes this.env = env; 7271541Srgrimes } 7281541Srgrimes 7291541Srgrimes @Override @SuppressWarnings("unchecked") 7301541Srgrimes public void visitModuleDef(JCModuleDecl tree) { 7311541Srgrimes msym.directives = List.nil(); 7321541Srgrimes msym.provides = List.nil(); 7331541Srgrimes msym.uses = List.nil(); 7341541Srgrimes tree.directives.forEach(t -> t.accept(this)); 7351541Srgrimes msym.directives = msym.directives.reverse(); 7361541Srgrimes msym.provides = msym.provides.reverse(); 7371541Srgrimes msym.uses = msym.uses.reverse(); 7381541Srgrimes 7391541Srgrimes if (msym.requires.nonEmpty() && msym.requires.head.flags.contains(RequiresFlag.MANDATED)) 7401541Srgrimes msym.directives = msym.directives.prepend(msym.requires.head); 74112577Sbde 7421541Srgrimes msym.directives = msym.directives.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 7431541Srgrimes 7441541Srgrimes checkForCorrectness(); 7451541Srgrimes } 7461541Srgrimes 7471541Srgrimes @Override 7481541Srgrimes public void visitExports(JCExports tree) { 7491541Srgrimes if (tree.directive.packge.members().isEmpty()) { 7501541Srgrimes log.error(tree.qualid.pos(), Errors.PackageEmptyOrNotFound(tree.directive.packge)); 7511541Srgrimes } 7521541Srgrimes msym.directives = msym.directives.prepend(tree.directive); 7531541Srgrimes } 7541541Srgrimes 7551541Srgrimes MethodSymbol noArgsConstructor(ClassSymbol tsym) { 7561541Srgrimes for (Symbol sym : tsym.members().getSymbolsByName(names.init)) { 7571541Srgrimes MethodSymbol mSym = (MethodSymbol)sym; 7581541Srgrimes if (mSym.params().isEmpty()) { 7591541Srgrimes return mSym; 7601541Srgrimes } 7611541Srgrimes } 7621541Srgrimes return null; 7631541Srgrimes } 7641541Srgrimes 7651541Srgrimes Map<Directive.ProvidesDirective, JCProvides> directiveToTreeMap = new HashMap<>(); 7661541Srgrimes 7671541Srgrimes @Override 7681541Srgrimes public void visitProvides(JCProvides tree) { 7691541Srgrimes Type st = attr.attribType(tree.serviceName, env, syms.objectType); 7701541Srgrimes Type it = attr.attribType(tree.implName, env, syms.objectType); 7711541Srgrimes ClassSymbol service = (ClassSymbol) st.tsym; 7721541Srgrimes ClassSymbol impl = (ClassSymbol) it.tsym; 7731541Srgrimes if (!types.isSubtype(it, st)) { 7741541Srgrimes log.error(tree.implName.pos(), Errors.ServiceImplementationMustBeSubtypeOfServiceInterface); 7751541Srgrimes } 7761541Srgrimes if ((impl.flags() & ABSTRACT) != 0) { 7771541Srgrimes log.error(tree.implName.pos(), Errors.ServiceImplementationIsAbstract(impl)); 7781541Srgrimes } else if (impl.isInner()) { 7791541Srgrimes log.error(tree.implName.pos(), Errors.ServiceImplementationIsInner(impl)); 7801541Srgrimes } else { 7811541Srgrimes MethodSymbol constr = noArgsConstructor(impl); 7821541Srgrimes if (constr == null) { 7831541Srgrimes log.error(tree.implName.pos(), Errors.ServiceImplementationDoesntHaveANoArgsConstructor(impl)); 7841541Srgrimes } else if ((constr.flags() & PUBLIC) == 0) { 7851541Srgrimes log.error(tree.implName.pos(), Errors.ServiceImplementationNoArgsConstructorNotPublic(impl)); 7861541Srgrimes } 7871541Srgrimes } 7881541Srgrimes if (st.hasTag(CLASS) && it.hasTag(CLASS)) { 7891541Srgrimes Directive.ProvidesDirective d = new Directive.ProvidesDirective(service, impl); 7901541Srgrimes if (!allProvides.add(d)) { 7911541Srgrimes log.error(tree.pos(), Errors.DuplicateProvides(service, impl)); 7921541Srgrimes } 7931541Srgrimes msym.provides = msym.provides.prepend(d); 7941541Srgrimes msym.directives = msym.directives.prepend(d); 7951541Srgrimes directiveToTreeMap.put(d, tree); 7961541Srgrimes } 7971541Srgrimes } 7981541Srgrimes 7991541Srgrimes @Override 8001541Srgrimes public void visitRequires(JCRequires tree) { 8011541Srgrimes if (tree.directive != null) { 8023352Sphk msym.directives = msym.directives.prepend(tree.directive); 8033352Sphk } 8043352Sphk } 8053352Sphk 8063352Sphk @Override 8073352Sphk public void visitUses(JCUses tree) { 8083352Sphk Type st = attr.attribType(tree.qualid, env, syms.objectType); 8093352Sphk Symbol sym = TreeInfo.symbol(tree.qualid); 8103352Sphk if ((sym.flags() & ENUM) != 0) { 8113352Sphk log.error(tree.qualid.pos(), Errors.ServiceDefinitionIsEnum(st.tsym)); 8123352Sphk } else if (st.hasTag(CLASS)) { 8133352Sphk ClassSymbol service = (ClassSymbol) st.tsym; 8143352Sphk Directive.UsesDirective d = new Directive.UsesDirective(service); 8153352Sphk if (!allUses.add(d)) { 8163352Sphk log.error(tree.pos(), Errors.DuplicateUses(service)); 8173352Sphk } 8183352Sphk msym.uses = msym.uses.prepend(d); 8193352Sphk msym.directives = msym.directives.prepend(d); 8203352Sphk } 8213352Sphk } 8223352Sphk 8233352Sphk private void checkForCorrectness() { 8243352Sphk for (Directive.ProvidesDirective provides : allProvides) { 8253352Sphk JCProvides tree = directiveToTreeMap.get(provides); 8263352Sphk /* The implementation must be defined in the same module as the provides directive 8273352Sphk * (else, error) 8283352Sphk */ 8293352Sphk PackageSymbol implementationDefiningPackage = provides.impl.packge(); 8303352Sphk if (implementationDefiningPackage.modle != msym) { 8313352Sphk log.error(tree.pos(), Errors.ServiceImplementationNotInRightModule(implementationDefiningPackage.modle)); 8323352Sphk } 8333352Sphk 8343352Sphk /* There is no inherent requirement that module that provides a service should actually 8353352Sphk * use it itself. However, it is a pointless declaration if the service package is not 8363352Sphk * exported and there is no uses for the service. 8373352Sphk */ 8383352Sphk PackageSymbol interfaceDeclaringPackage = provides.service.packge(); 8393352Sphk boolean isInterfaceDeclaredInCurrentModule = interfaceDeclaringPackage.modle == msym; 8403352Sphk boolean isInterfaceExportedFromAReadableModule = 8413352Sphk msym.visiblePackages.get(interfaceDeclaringPackage.fullname) == interfaceDeclaringPackage; 8423352Sphk if (isInterfaceDeclaredInCurrentModule && !isInterfaceExportedFromAReadableModule) { 8433352Sphk // ok the interface is declared in this module. Let's check if it's exported 8443352Sphk boolean warn = true; 8453352Sphk for (ExportsDirective export : msym.exports) { 8463352Sphk if (interfaceDeclaringPackage == export.packge) { 8473352Sphk warn = false; 8483352Sphk break; 8493352Sphk } 8503352Sphk } 8513352Sphk if (warn) { 8523352Sphk for (UsesDirective uses : msym.uses) { 8533352Sphk if (provides.service == uses.service) { 8543352Sphk warn = false; 855 break; 856 } 857 } 858 } 859 if (warn) { 860 log.warning(tree.pos(), Warnings.ServiceProvidedButNotExportedOrUsed(provides.service)); 861 } 862 } 863 } 864 } 865 } 866 867 private Set<ModuleSymbol> allModules; 868 869 public Set<ModuleSymbol> allModules() { 870 Assert.checkNonNull(allModules); 871 return allModules; 872 } 873 874 private void setupAllModules() { 875 Assert.checkNonNull(rootModules); 876 Assert.checkNull(allModules); 877 878 Set<ModuleSymbol> observable; 879 880 if (limitModsOpt == null && extraLimitMods.isEmpty()) { 881 observable = null; 882 } else { 883 Set<ModuleSymbol> limitMods = new HashSet<>(); 884 if (limitModsOpt != null) { 885 for (String limit : limitModsOpt.split(",")) { 886 if (!isValidName(limit)) 887 continue; 888 limitMods.add(syms.enterModule(names.fromString(limit))); 889 } 890 } 891 for (String limit : extraLimitMods) { 892 limitMods.add(syms.enterModule(names.fromString(limit))); 893 } 894 observable = computeTransitiveClosure(limitMods, null); 895 observable.addAll(rootModules); 896 if (lintOptions) { 897 for (ModuleSymbol msym : limitMods) { 898 if (!observable.contains(msym)) { 899 log.warning(LintCategory.OPTIONS, 900 Warnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym)); 901 } 902 } 903 } 904 } 905 906 Predicate<ModuleSymbol> observablePred = sym -> observable == null || observable.contains(sym); 907 Predicate<ModuleSymbol> systemModulePred = sym -> (sym.flags() & Flags.SYSTEM_MODULE) != 0; 908 Set<ModuleSymbol> enabledRoot = new LinkedHashSet<>(); 909 910 if (rootModules.contains(syms.unnamedModule)) { 911 ModuleSymbol javaSE = syms.getModule(java_se); 912 Predicate<ModuleSymbol> jdkModulePred; 913 914 if (javaSE != null && (observable == null || observable.contains(javaSE))) { 915 jdkModulePred = sym -> { 916 sym.complete(); 917 return !sym.name.startsWith(java_) 918 && sym.exports.stream().anyMatch(e -> e.modules == null); 919 }; 920 enabledRoot.add(javaSE); 921 } else { 922 jdkModulePred = sym -> true; 923 } 924 925 for (ModuleSymbol sym : new HashSet<>(syms.getAllModules())) { 926 if (systemModulePred.test(sym) && observablePred.test(sym) && jdkModulePred.test(sym)) { 927 enabledRoot.add(sym); 928 } 929 } 930 } 931 932 enabledRoot.addAll(rootModules); 933 934 if (addModsOpt != null || !extraAddMods.isEmpty()) { 935 Set<String> fullAddMods = new HashSet<>(); 936 fullAddMods.addAll(extraAddMods); 937 938 if (addModsOpt != null) { 939 fullAddMods.addAll(Arrays.asList(addModsOpt.split(","))); 940 } 941 942 for (String added : fullAddMods) { 943 Stream<ModuleSymbol> modules; 944 switch (added) { 945 case ALL_SYSTEM: 946 modules = syms.getAllModules() 947 .stream() 948 .filter(systemModulePred.and(observablePred)); 949 break; 950 case ALL_MODULE_PATH: 951 modules = syms.getAllModules() 952 .stream() 953 .filter(systemModulePred.negate().and(observablePred)); 954 break; 955 default: 956 if (!isValidName(added)) 957 continue; 958 modules = Stream.of(syms.enterModule(names.fromString(added))); 959 break; 960 } 961 modules.forEach(sym -> { 962 enabledRoot.add(sym); 963 if (observable != null) 964 observable.add(sym); 965 }); 966 } 967 } 968 969 Set<ModuleSymbol> result = computeTransitiveClosure(enabledRoot, observable); 970 971 result.add(syms.unnamedModule); 972 973 allModules = result; 974 } 975 976 private Set<ModuleSymbol> computeTransitiveClosure(Iterable<? extends ModuleSymbol> base, Set<ModuleSymbol> observable) { 977 List<ModuleSymbol> todo = List.nil(); 978 979 for (ModuleSymbol ms : base) { 980 todo = todo.prepend(ms); 981 } 982 983 Set<ModuleSymbol> result = new LinkedHashSet<>(); 984 result.add(syms.java_base); 985 986 while (todo.nonEmpty()) { 987 ModuleSymbol current = todo.head; 988 todo = todo.tail; 989 if (observable != null && !observable.contains(current)) 990 continue; 991 if (!result.add(current) || current == syms.unnamedModule || ((current.flags_field & Flags.AUTOMATIC_MODULE) != 0)) 992 continue; 993 current.complete(); 994 for (RequiresDirective rd : current.requires) { 995 todo = todo.prepend(rd.module); 996 } 997 } 998 999 return result; 1000 } 1001 1002 public ModuleSymbol getObservableModule(Name name) { 1003 ModuleSymbol mod = syms.getModule(name); 1004 1005 if (allModules().contains(mod)) { 1006 return mod; 1007 } 1008 1009 return null; 1010 } 1011 1012 private Completer getUnnamedModuleCompleter() { 1013 moduleFinder.findAllModules(); 1014 return new Symbol.Completer() { 1015 @Override 1016 public void complete(Symbol sym) throws CompletionFailure { 1017 if (inInitModules) { 1018 sym.completer = this; 1019 return ; 1020 } 1021 ModuleSymbol msym = (ModuleSymbol) sym; 1022 Set<ModuleSymbol> allModules = allModules(); 1023 for (ModuleSymbol m : allModules) { 1024 m.complete(); 1025 } 1026 initVisiblePackages(msym, allModules); 1027 } 1028 1029 @Override 1030 public String toString() { 1031 return "unnamedModule Completer"; 1032 } 1033 }; 1034 } 1035 1036 private final Map<ModuleSymbol, Set<ModuleSymbol>> requiresPublicCache = new HashMap<>(); 1037 1038 private void completeModule(ModuleSymbol msym) { 1039 if (inInitModules) { 1040 msym.completer = sym -> completeModule(msym); 1041 return ; 1042 } 1043 1044 if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 1045 completeAutomaticModule(msym); 1046 } 1047 1048 Assert.checkNonNull(msym.requires); 1049 1050 initAddReads(); 1051 1052 msym.requires = msym.requires.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 1053 1054 List<RequiresDirective> requires = msym.requires; 1055 List<RequiresDirective> previous = null; 1056 1057 while (requires.nonEmpty()) { 1058 if (!allModules().contains(requires.head.module)) { 1059 Env<AttrContext> env = typeEnvs.get(msym); 1060 if (env != null) { 1061 JavaFileObject origSource = log.useSource(env.toplevel.sourcefile); 1062 try { 1063 log.error(/*XXX*/env.tree, Errors.ModuleNotFound(requires.head.module)); 1064 } finally { 1065 log.useSource(origSource); 1066 } 1067 } else { 1068 Assert.check((msym.flags() & Flags.AUTOMATIC_MODULE) == 0); 1069 } 1070 if (previous != null) { 1071 previous.tail = requires.tail; 1072 } else { 1073 msym.requires.tail = requires.tail; 1074 } 1075 } else { 1076 previous = requires; 1077 } 1078 requires = requires.tail; 1079 } 1080 1081 Set<ModuleSymbol> readable = new LinkedHashSet<>(); 1082 Set<ModuleSymbol> requiresPublic = new HashSet<>(); 1083 1084 for (RequiresDirective d : msym.requires) { 1085 d.module.complete(); 1086 readable.add(d.module); 1087 Set<ModuleSymbol> s = retrieveRequiresPublic(d.module); 1088 Assert.checkNonNull(s, () -> "no entry in cache for " + d.module); 1089 readable.addAll(s); 1090 if (d.flags.contains(RequiresFlag.PUBLIC)) { 1091 requiresPublic.add(d.module); 1092 requiresPublic.addAll(s); 1093 } 1094 } 1095 1096 requiresPublicCache.put(msym, requiresPublic); 1097 initVisiblePackages(msym, readable); 1098 for (ExportsDirective d: msym.exports) { 1099 d.packge.modle = msym; 1100 } 1101 1102 } 1103 1104 private Set<ModuleSymbol> retrieveRequiresPublic(ModuleSymbol msym) { 1105 Set<ModuleSymbol> requiresPublic = requiresPublicCache.get(msym); 1106 1107 if (requiresPublic == null) { 1108 //the module graph may contain cycles involving automatic modules or --add-reads edges 1109 requiresPublic = new HashSet<>(); 1110 1111 Set<ModuleSymbol> seen = new HashSet<>(); 1112 List<ModuleSymbol> todo = List.of(msym); 1113 1114 while (todo.nonEmpty()) { 1115 ModuleSymbol current = todo.head; 1116 todo = todo.tail; 1117 if (!seen.add(current)) 1118 continue; 1119 requiresPublic.add(current); 1120 current.complete(); 1121 Iterable<? extends RequiresDirective> requires; 1122 if (current != syms.unnamedModule) { 1123 Assert.checkNonNull(current.requires, () -> current + ".requires == null; " + msym); 1124 requires = current.requires; 1125 for (RequiresDirective rd : requires) { 1126 if (rd.isPublic()) 1127 todo = todo.prepend(rd.module); 1128 } 1129 } else { 1130 for (ModuleSymbol mod : allModules()) { 1131 todo = todo.prepend(mod); 1132 } 1133 } 1134 } 1135 1136 requiresPublic.remove(msym); 1137 } 1138 1139 return requiresPublic; 1140 } 1141 1142 private void initVisiblePackages(ModuleSymbol msym, Collection<ModuleSymbol> readable) { 1143 initAddExports(); 1144 1145 msym.visiblePackages = new LinkedHashMap<>(); 1146 1147 Map<Name, ModuleSymbol> seen = new HashMap<>(); 1148 1149 for (ModuleSymbol rm : readable) { 1150 if (rm == syms.unnamedModule) 1151 continue; 1152 addVisiblePackages(msym, seen, rm, rm.exports); 1153 } 1154 1155 addExports.forEach((exportsFrom, exports) -> { 1156 addVisiblePackages(msym, seen, exportsFrom, exports); 1157 }); 1158 } 1159 1160 private void addVisiblePackages(ModuleSymbol msym, 1161 Map<Name, ModuleSymbol> seenPackages, 1162 ModuleSymbol exportsFrom, 1163 Collection<ExportsDirective> exports) { 1164 for (ExportsDirective d : exports) { 1165 if (d.modules == null || d.modules.contains(msym)) { 1166 Name packageName = d.packge.fullname; 1167 ModuleSymbol previousModule = seenPackages.get(packageName); 1168 1169 if (previousModule != null && previousModule != exportsFrom) { 1170 Env<AttrContext> env = typeEnvs.get(msym); 1171 JavaFileObject origSource = env != null ? log.useSource(env.toplevel.sourcefile) 1172 : null; 1173 DiagnosticPosition pos = env != null ? env.tree.pos() : null; 1174 try { 1175 log.error(pos, Errors.PackageClashFromRequires(msym, packageName, 1176 previousModule, exportsFrom)); 1177 } finally { 1178 if (env != null) 1179 log.useSource(origSource); 1180 } 1181 continue; 1182 } 1183 1184 seenPackages.put(packageName, exportsFrom); 1185 msym.visiblePackages.put(d.packge.fullname, d.packge); 1186 } 1187 } 1188 } 1189 1190 private void initAddExports() { 1191 if (addExports != null) 1192 return; 1193 1194 addExports = new LinkedHashMap<>(); 1195 Set<ModuleSymbol> unknownModules = new HashSet<>(); 1196 1197 if (addExportsOpt == null) 1198 return; 1199 1200 Pattern ep = Pattern.compile("([^/]+)/([^=]+)=(.*)"); 1201 for (String s: addExportsOpt.split("\0+")) { 1202 if (s.isEmpty()) 1203 continue; 1204 Matcher em = ep.matcher(s); 1205 if (!em.matches()) { 1206 continue; 1207 } 1208 1209 // Terminology comes from 1210 // --add-exports module/package=target,... 1211 // Compare to 1212 // module module { exports package to target, ... } 1213 String moduleName = em.group(1); 1214 String packageName = em.group(2); 1215 String targetNames = em.group(3); 1216 1217 if (!isValidName(moduleName)) 1218 continue; 1219 1220 ModuleSymbol msym = syms.enterModule(names.fromString(moduleName)); 1221 if (!isKnownModule(msym, unknownModules)) 1222 continue; 1223 1224 if (!isValidName(packageName)) 1225 continue; 1226 PackageSymbol p = syms.enterPackage(msym, names.fromString(packageName)); 1227 p.modle = msym; // TODO: do we need this? 1228 1229 List<ModuleSymbol> targetModules = List.nil(); 1230 for (String toModule : targetNames.split("[ ,]+")) { 1231 ModuleSymbol m; 1232 if (toModule.equals("ALL-UNNAMED")) { 1233 m = syms.unnamedModule; 1234 } else { 1235 if (!isValidName(toModule)) 1236 continue; 1237 m = syms.enterModule(names.fromString(toModule)); 1238 if (!isKnownModule(m, unknownModules)) 1239 continue; 1240 } 1241 targetModules = targetModules.prepend(m); 1242 } 1243 1244 Set<ExportsDirective> extra = addExports.computeIfAbsent(msym, _x -> new LinkedHashSet<>()); 1245 ExportsDirective d = new ExportsDirective(p, targetModules); 1246 extra.add(d); 1247 } 1248 } 1249 1250 private boolean isKnownModule(ModuleSymbol msym, Set<ModuleSymbol> unknownModules) { 1251 if (allModules.contains(msym)) { 1252 return true; 1253 } 1254 1255 if (!unknownModules.contains(msym)) { 1256 if (lintOptions) { 1257 log.warning(LintCategory.OPTIONS, 1258 Warnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym)); 1259 } 1260 unknownModules.add(msym); 1261 } 1262 return false; 1263 } 1264 1265 private void initAddReads() { 1266 if (addReads != null) 1267 return; 1268 1269 addReads = new LinkedHashMap<>(); 1270 1271 if (addReadsOpt == null) 1272 return; 1273 1274 Pattern rp = Pattern.compile("([^=]+)=(.*)"); 1275 for (String s : addReadsOpt.split("\0+")) { 1276 if (s.isEmpty()) 1277 continue; 1278 Matcher rm = rp.matcher(s); 1279 if (!rm.matches()) { 1280 continue; 1281 } 1282 1283 // Terminology comes from 1284 // --add-reads source-module=target-module,... 1285 // Compare to 1286 // module source-module { requires target-module; ... } 1287 String sourceName = rm.group(1); 1288 String targetNames = rm.group(2); 1289 1290 if (!isValidName(sourceName)) 1291 continue; 1292 1293 ModuleSymbol msym = syms.enterModule(names.fromString(sourceName)); 1294 if (!allModules.contains(msym)) { 1295 if (lintOptions) { 1296 log.warning(Warnings.ModuleForOptionNotFound(Option.ADD_READS, msym)); 1297 } 1298 continue; 1299 } 1300 1301 for (String targetName : targetNames.split("[ ,]+", -1)) { 1302 ModuleSymbol targetModule; 1303 if (targetName.equals("ALL-UNNAMED")) { 1304 targetModule = syms.unnamedModule; 1305 } else { 1306 if (!isValidName(targetName)) 1307 continue; 1308 targetModule = syms.enterModule(names.fromString(targetName)); 1309 if (!allModules.contains(targetModule)) { 1310 if (lintOptions) { 1311 log.warning(LintCategory.OPTIONS, Warnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule)); 1312 } 1313 continue; 1314 } 1315 } 1316 addReads.computeIfAbsent(msym, m -> new HashSet<>()) 1317 .add(new RequiresDirective(targetModule, EnumSet.of(RequiresFlag.EXTRA))); 1318 } 1319 } 1320 } 1321 1322 private void checkCyclicDependencies(JCModuleDecl mod) { 1323 for (JCDirective d : mod.directives) { 1324 JCRequires rd; 1325 if (!d.hasTag(Tag.REQUIRES) || (rd = (JCRequires) d).directive == null) 1326 continue; 1327 Set<ModuleSymbol> nonSyntheticDeps = new HashSet<>(); 1328 List<ModuleSymbol> queue = List.of(rd.directive.module); 1329 while (queue.nonEmpty()) { 1330 ModuleSymbol current = queue.head; 1331 queue = queue.tail; 1332 if (!nonSyntheticDeps.add(current)) 1333 continue; 1334 current.complete(); 1335 if ((current.flags() & Flags.ACYCLIC) != 0) 1336 continue; 1337 Assert.checkNonNull(current.requires, () -> current.toString()); 1338 for (RequiresDirective dep : current.requires) { 1339 if (!dep.flags.contains(RequiresFlag.EXTRA)) 1340 queue = queue.prepend(dep.module); 1341 } 1342 } 1343 if (nonSyntheticDeps.contains(mod.sym)) { 1344 log.error(rd.moduleName.pos(), Errors.CyclicRequires(rd.directive.module)); 1345 } 1346 mod.sym.flags_field |= Flags.ACYCLIC; 1347 } 1348 } 1349 1350 private boolean isValidName(CharSequence name) { 1351 return SourceVersion.isName(name, Source.toSourceVersion(source)); 1352 } 1353 1354 // DEBUG 1355 private String toString(ModuleSymbol msym) { 1356 return msym.name + "[" 1357 + "kind:" + msym.kind + ";" 1358 + "locn:" + toString(msym.sourceLocation) + "," + toString(msym.classLocation) + ";" 1359 + "info:" + toString(msym.module_info.sourcefile) + "," 1360 + toString(msym.module_info.classfile) + "," 1361 + msym.module_info.completer 1362 + "]"; 1363 } 1364 1365 // DEBUG 1366 String toString(Location locn) { 1367 return (locn == null) ? "--" : locn.getName(); 1368 } 1369 1370 // DEBUG 1371 String toString(JavaFileObject fo) { 1372 return (fo == null) ? "--" : fo.getName(); 1373 } 1374 1375 public void newRound() { 1376 rootModules = null; 1377 allModules = null; 1378 } 1379} 1380