Mergin jlahoda's fix of #8182450: javac aborts when generating ct.sym intermittently - Initialize the module system model even in presence of missing/broken module-infos; BadClassFiles should not immediatelly abort compilation anymore, but should be handled as if the classfile did not exist.
2 * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
27 package com.sun.tools.javac.comp;
29 import java.io.IOException;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.EnumSet;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.LinkedHashMap;
37 import java.util.LinkedHashSet;
40 import java.util.function.Consumer;
41 import java.util.function.Predicate;
42 import java.util.regex.Matcher;
43 import java.util.regex.Pattern;
44 import java.util.stream.Collectors;
45 import java.util.stream.Stream;
47 import javax.lang.model.SourceVersion;
48 import javax.tools.JavaFileManager;
49 import javax.tools.JavaFileManager.Location;
50 import javax.tools.JavaFileObject;
51 import javax.tools.JavaFileObject.Kind;
52 import javax.tools.StandardLocation;
54 import com.sun.source.tree.ModuleTree.ModuleKind;
55 import com.sun.tools.javac.code.ClassFinder;
56 import com.sun.tools.javac.code.DeferredLintHandler;
57 import com.sun.tools.javac.code.Directive;
58 import com.sun.tools.javac.code.Directive.ExportsDirective;
59 import com.sun.tools.javac.code.Directive.ExportsFlag;
60 import com.sun.tools.javac.code.Directive.OpensDirective;
61 import com.sun.tools.javac.code.Directive.OpensFlag;
62 import com.sun.tools.javac.code.Directive.RequiresDirective;
63 import com.sun.tools.javac.code.Directive.RequiresFlag;
64 import com.sun.tools.javac.code.Directive.UsesDirective;
65 import com.sun.tools.javac.code.Flags;
66 import com.sun.tools.javac.code.Lint.LintCategory;
67 import com.sun.tools.javac.code.ModuleFinder;
68 import com.sun.tools.javac.code.Source;
69 import com.sun.tools.javac.code.Symbol;
70 import com.sun.tools.javac.code.Symbol.ClassSymbol;
71 import com.sun.tools.javac.code.Symbol.Completer;
72 import com.sun.tools.javac.code.Symbol.CompletionFailure;
73 import com.sun.tools.javac.code.Symbol.MethodSymbol;
74 import com.sun.tools.javac.code.Symbol.ModuleFlags;
75 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
76 import com.sun.tools.javac.code.Symbol.PackageSymbol;
77 import com.sun.tools.javac.code.Symtab;
78 import com.sun.tools.javac.code.Type;
79 import com.sun.tools.javac.code.Types;
80 import com.sun.tools.javac.jvm.ClassWriter;
81 import com.sun.tools.javac.jvm.JNIWriter;
82 import com.sun.tools.javac.main.Option;
83 import com.sun.tools.javac.resources.CompilerProperties.Errors;
84 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
85 import com.sun.tools.javac.tree.JCTree;
86 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
87 import com.sun.tools.javac.tree.JCTree.JCDirective;
88 import com.sun.tools.javac.tree.JCTree.JCExports;
89 import com.sun.tools.javac.tree.JCTree.JCExpression;
90 import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
91 import com.sun.tools.javac.tree.JCTree.JCOpens;
92 import com.sun.tools.javac.tree.JCTree.JCProvides;
93 import com.sun.tools.javac.tree.JCTree.JCRequires;
94 import com.sun.tools.javac.tree.JCTree.JCUses;
95 import com.sun.tools.javac.tree.JCTree.Tag;
96 import com.sun.tools.javac.tree.TreeInfo;
97 import com.sun.tools.javac.util.Assert;
98 import com.sun.tools.javac.util.Context;
99 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
100 import com.sun.tools.javac.util.List;
101 import com.sun.tools.javac.util.ListBuffer;
102 import com.sun.tools.javac.util.Log;
103 import com.sun.tools.javac.util.Name;
104 import com.sun.tools.javac.util.Names;
105 import com.sun.tools.javac.util.Options;
107 import static com.sun.tools.javac.code.Flags.ABSTRACT;
108 import static com.sun.tools.javac.code.Flags.ENUM;
109 import static com.sun.tools.javac.code.Flags.PUBLIC;
110 import static com.sun.tools.javac.code.Flags.UNATTRIBUTED;
111 import com.sun.tools.javac.code.Kinds;
112 import static com.sun.tools.javac.code.Kinds.Kind.ERR;
113 import static com.sun.tools.javac.code.Kinds.Kind.MDL;
114 import static com.sun.tools.javac.code.Kinds.Kind.MTH;
115 import com.sun.tools.javac.code.Symbol.ModuleResolutionFlags;
116 import static com.sun.tools.javac.code.TypeTag.CLASS;
121 * <p><b>This is NOT part of any supported API.
122 * If you write code that depends on this, you do so at your own risk.
123 * This code and its internal interfaces are subject to change or
124 * deletion without notice.</b>
126 public class Modules extends JCTree.Visitor {
127 private static final String ALL_SYSTEM = "ALL-SYSTEM";
128 private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
130 private final Log log;
131 private final Names names;
132 private final Symtab syms;
133 private final Attr attr;
134 private final Check chk;
135 private final DeferredLintHandler deferredLintHandler;
136 private final TypeEnvs typeEnvs;
137 private final Types types;
138 private final JavaFileManager fileManager;
139 private final ModuleFinder moduleFinder;
140 private final Source source;
141 private final boolean allowModules;
143 public final boolean multiModuleMode;
145 private final String legacyModuleOverride;
147 private final Name java_se;
148 private final Name java_;
150 ModuleSymbol defaultModule;
152 private final String addExportsOpt;
153 private Map<ModuleSymbol, Set<ExportsDirective>> addExports;
154 private final String addReadsOpt;
155 private Map<ModuleSymbol, Set<RequiresDirective>> addReads;
156 private final String addModsOpt;
157 private final Set<String> extraAddMods = new HashSet<>();
158 private final String limitModsOpt;
159 private final Set<String> extraLimitMods = new HashSet<>();
160 private final String moduleVersionOpt;
162 private final boolean lintOptions;
163 private final boolean backgroundCompilation;
164 private final boolean ideMode;
165 private final JavaFileManager fm;
167 private Set<ModuleSymbol> rootModules = null;
168 private final Set<ModuleSymbol> warnedMissing = new HashSet<>();
170 public PackageNameFinder findPackageInFile;
172 public static Modules instance(Context context) {
173 Modules instance = context.get(Modules.class);
174 if (instance == null)
175 instance = new Modules(context);
179 protected Modules(Context context) {
180 context.put(Modules.class, this);
181 log = Log.instance(context);
182 names = Names.instance(context);
183 syms = Symtab.instance(context);
184 attr = Attr.instance(context);
185 chk = Check.instance(context);
186 deferredLintHandler = DeferredLintHandler.instance(context);
187 typeEnvs = TypeEnvs.instance(context);
188 moduleFinder = ModuleFinder.instance(context);
189 types = Types.instance(context);
190 fileManager = context.get(JavaFileManager.class);
191 source = Source.instance(context);
192 allowModules = source.allowModules();
193 Options options = Options.instance(context);
195 lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option);
197 Collection<String> xmodules = options.keySet()
199 .filter(opt -> opt.startsWith(XMODULES_PREFIX))
200 .map(opt -> opt.substring(XMODULES_PREFIX.length()))
201 .collect(Collectors.toList());
203 legacyModuleOverride = xmodules.size() == 1 ? xmodules.iterator().next() : null;
205 multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH);
206 ClassWriter classWriter = ClassWriter.instance(context);
207 classWriter.multiModuleMode = multiModuleMode;
208 JNIWriter jniWriter = JNIWriter.instance(context);
209 jniWriter.multiModuleMode = multiModuleMode;
211 java_se = names.fromString("java.se");
212 java_ = names.fromString("java.");
214 addExportsOpt = options.get(Option.ADD_EXPORTS);
215 addReadsOpt = options.get(Option.ADD_READS);
216 addModsOpt = options.get(Option.ADD_MODULES);
217 limitModsOpt = options.get(Option.LIMIT_MODULES);
218 moduleVersionOpt = options.get(Option.MODULE_VERSION);
220 fm = context.get(JavaFileManager.class);
221 backgroundCompilation = options.get("backgroundCompilation") != null;
222 ideMode = options.get("ide") != null;
225 private static final String XMODULES_PREFIX = "-Xmodule:";
228 private void dprintln(String msg) {
229 for (int i = 0; i < depth; i++)
230 System.err.print(" ");
231 System.err.println(msg);
234 public void addExtraAddModules(String... extras) {
235 extraAddMods.addAll(Arrays.asList(extras));
238 public void addExtraLimitModules(String... extras) {
239 extraLimitMods.addAll(Arrays.asList(extras));
242 boolean inInitModules;
243 public void initModules(List<JCCompilationUnit> trees) {
244 Assert.check(!inInitModules);
246 inInitModules = true;
247 if (rootModules == null) {
248 enter(trees, modules -> {
249 Assert.checkNull(rootModules);
250 Assert.checkNull(allModules);
251 this.rootModules = modules;
252 setupAllModules(); //initialize the module graph
253 Assert.checkNonNull(allModules);
254 inInitModules = false;
260 inInitModules = false;
264 public boolean enter(List<JCCompilationUnit> trees, ClassSymbol c) {
265 Assert.check(rootModules != null || inInitModules || !allowModules);
266 return enter(trees, modules -> {}, c);
269 private boolean enter(List<JCCompilationUnit> trees, Consumer<Set<ModuleSymbol>> init, ClassSymbol c) {
271 for (JCCompilationUnit tree: trees) {
272 tree.modle = syms.noModule;
274 defaultModule = syms.noModule;
278 int startErrors = log.nerrors;
282 // scan trees for module defs
283 Set<ModuleSymbol> roots = enterModules(trees, c);
285 setCompilationUnitModules(trees, roots, c);
289 for (ModuleSymbol msym: roots) {
292 } catch (CompletionFailure ex) {
293 chk.completionError(null, ex);
298 return (log.nerrors == startErrors);
301 public Completer getCompleter() {
302 return mainCompleter;
305 public ModuleSymbol getDefaultModule() {
306 return defaultModule;
309 public boolean modulesInitialized() {
310 return allModules != null;
313 private Set<ModuleSymbol> enterModules(List<JCCompilationUnit> trees, ClassSymbol c) {
314 Set<ModuleSymbol> modules = new LinkedHashSet<>();
315 for (JCCompilationUnit tree : trees) {
316 JavaFileObject prev = log.useSource(tree.sourcefile);
318 enterModule(tree, c, modules);
327 private void enterModule(JCCompilationUnit toplevel, ClassSymbol c, Set<ModuleSymbol> modules) {
328 boolean isModuleInfo = toplevel.sourcefile.isNameCompatible("module-info", Kind.SOURCE);
329 boolean isModuleDecl = toplevel.getModuleDecl() != null;
331 JCModuleDecl decl = toplevel.getModuleDecl();
333 log.error(decl.pos(), Errors.ModuleDeclSbInModuleInfoJava);
335 Name name = TreeInfo.fullName(decl.qualId);
338 sym = (ModuleSymbol) c.owner;
339 Assert.checkNonNull(sym.name);
340 Name treeName = TreeInfo.fullName(decl.qualId);
341 if (sym.name != treeName) {
342 log.error(decl.pos(), Errors.ModuleNameMismatch(name, sym.name));
345 sym = syms.enterModule(name);
346 if ((sym.flags_field & Flags.FROMCLASS) == 0 && sym.module_info.sourcefile != null && sym.module_info.sourcefile != toplevel.sourcefile) {
347 log.error(decl.pos(), Errors.DuplicateModule(sym));
351 sym.completer = getSourceCompleter(toplevel);
352 sym.module_info.sourcefile = toplevel.sourcefile;
355 if (multiModuleMode || modules.isEmpty()) {
358 log.error(toplevel.pos(), Errors.TooManyModules);
361 Env<AttrContext> provisionalEnv = new Env<>(decl, null);
363 provisionalEnv.toplevel = toplevel;
364 typeEnvs.put(sym, provisionalEnv);
365 } else if (isModuleInfo) {
366 if (multiModuleMode) {
367 JCTree tree = toplevel.defs.isEmpty() ? toplevel : toplevel.defs.head;
368 log.error(tree.pos(), Errors.ExpectedModule);
373 private void setCompilationUnitModules(List<JCCompilationUnit> trees, Set<ModuleSymbol> rootModules, ClassSymbol c) {
374 // update the module for each compilation unit
375 if (multiModuleMode) {
376 checkNoAllModulePath();
377 for (JCCompilationUnit tree: trees) {
378 if (tree.modle != null) {
381 if (tree.defs.isEmpty()) {
382 tree.modle = syms.unnamedModule;
386 JavaFileObject prev = log.useSource(tree.sourcefile);
388 Location msplocn = getModuleLocation(tree);
389 Location plocn = fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH) ?
390 fileManager.getLocationForModule(StandardLocation.PATCH_MODULE_PATH,
395 Name name = names.fromString(fileManager.inferModuleName(plocn));
396 ModuleSymbol msym = moduleFinder.findModule(name);
398 rootModules.add(msym);
400 if (msplocn != null) {
401 Name mspname = names.fromString(fileManager.inferModuleName(msplocn));
402 if (name != mspname) {
403 log.error(tree.pos(), Errors.FilePatchedAndMsp(name, mspname));
406 } else if (msplocn != null) {
407 if (tree.getModuleDecl() != null) {
408 JavaFileObject canonical =
409 fileManager.getJavaFileForInput(msplocn, "module-info", Kind.SOURCE);
410 if (canonical == null || !fileManager.isSameFile(canonical, tree.sourcefile)) {
411 log.error(tree.pos(), Errors.ModuleNotFoundOnModuleSourcePath);
414 Name name = names.fromString(fileManager.inferModuleName(msplocn));
416 JCModuleDecl decl = tree.getModuleDecl();
419 if (msym.name != name) {
420 log.error(decl.qualId, Errors.ModuleNameMismatch(msym.name, name));
423 if (tree.getPackage() == null) {
424 log.error(tree.pos(), Errors.UnnamedPkgNotAllowedNamedModules);
426 msym = syms.enterModule(name);
428 if (msym.sourceLocation == null) {
429 msym.sourceLocation = msplocn;
430 if (fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) {
431 msym.patchLocation = fileManager.getLocationForModule(
432 StandardLocation.PATCH_MODULE_PATH, msym.name.toString());
434 if (fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) {
435 Location outputLocn = fileManager.getLocationForModule(
436 StandardLocation.CLASS_OUTPUT, msym.name.toString());
437 if (msym.patchLocation == null) {
438 msym.classLocation = outputLocn;
440 msym.patchOutputLocation = outputLocn;
445 rootModules.add(msym);
446 } else if (c != null && c.packge().modle == syms.unnamedModule) {
447 tree.modle = syms.unnamedModule;
449 if (tree.getModuleDecl() != null) {
450 log.error(tree.pos(), Errors.ModuleNotFoundOnModuleSourcePath);
452 log.error(tree.pos(), Errors.NotInModuleOnModuleSourcePath);
454 tree.modle = syms.errModule;
455 tree.modle.completer = sym -> completeModule((ModuleSymbol)sym);
457 } catch (IOException e) {
458 throw new Error(e); // FIXME
463 if (syms.unnamedModule.sourceLocation == null) {
464 syms.unnamedModule.completer = getUnnamedModuleCompleter();
465 syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH;
466 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH;
468 defaultModule = syms.unnamedModule;
470 ModuleSymbol module = null;
471 if (defaultModule == null) {
472 String moduleOverride = singleModuleOverride(trees);
473 switch (rootModules.size()) {
475 defaultModule = moduleFinder.findSingleModule();
476 if (defaultModule == syms.unnamedModule) {
477 if (moduleOverride != null) {
478 checkNoAllModulePath();
479 defaultModule = moduleFinder.findModule(names.fromString(moduleOverride));
480 if (legacyModuleOverride != null) {
481 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH;
483 defaultModule.patchOutputLocation = StandardLocation.CLASS_OUTPUT;
485 // Question: why not do findAllModules and initVisiblePackages here?
486 // i.e. body of unnamedModuleCompleter
487 defaultModule.completer = getUnnamedModuleCompleter();
488 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH;
489 defaultModule.classLocation = StandardLocation.CLASS_PATH;
492 checkNoAllModulePath();
493 defaultModule.complete();
494 // Question: why not do completeModule here?
495 defaultModule.completer = sym -> completeModule((ModuleSymbol) sym);
496 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH;
498 rootModules.add(defaultModule);
501 checkNoAllModulePath();
502 defaultModule = rootModules.iterator().next();
503 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH;
504 if (fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) {
506 defaultModule.patchLocation = fileManager.getLocationForModule(
507 StandardLocation.PATCH_MODULE_PATH, defaultModule.name.toString());
508 } catch (IOException ex) {
512 if (defaultModule.patchLocation == null) {
513 Location loc = StandardLocation.CLASS_OUTPUT;
514 if (!backgroundCompilation && !fm.hasLocation(StandardLocation.CLASS_OUTPUT)) {
515 for (Location baseLoc : new Location[] {
516 StandardLocation.UPGRADE_MODULE_PATH,
517 StandardLocation.SYSTEM_MODULES,
518 StandardLocation.MODULE_PATH}) {
520 final Location tmp = fm.getLocationForModule(
522 defaultModule.name.toString());
527 } catch (IOException ioe) {
532 defaultModule.classLocation = loc;
534 defaultModule.patchOutputLocation = StandardLocation.CLASS_OUTPUT;
538 Assert.error("too many modules");
540 } else if (rootModules.size() == 1) {
541 module = rootModules.iterator().next();
543 module.completer = sym -> completeModule((ModuleSymbol) sym);
545 Assert.check(rootModules.isEmpty());
546 String moduleOverride = singleModuleOverride(trees);
547 if (moduleOverride != null) {
548 module = moduleFinder.findModule(names.fromString(moduleOverride));
550 module = defaultModule;
552 rootModules.add(module);
555 if (defaultModule != syms.unnamedModule) {
556 syms.unnamedModule.completer = getUnnamedModuleCompleter();
557 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH;
560 if (module == null) {
561 module = defaultModule;
564 for (JCCompilationUnit tree: trees) {
565 if (defaultModule != syms.unnamedModule
566 && defaultModule.sourceLocation == StandardLocation.SOURCE_PATH
567 && fileManager.hasLocation(StandardLocation.SOURCE_PATH)) {
568 checkSourceLocation(tree, module);
570 if (tree.modle == null) {
577 private void checkSourceLocation(JCCompilationUnit tree, ModuleSymbol msym) {
578 // skip check if legacy module override still in use
579 if (ideMode || legacyModuleOverride != null) {
584 JavaFileObject fo = tree.sourcefile;
585 if (fileManager.contains(msym.sourceLocation, fo)) {
588 if (msym.patchLocation != null && fileManager.contains(msym.patchLocation, fo)) {
591 if (fileManager.hasLocation(StandardLocation.SOURCE_OUTPUT)) {
592 if (fileManager.contains(StandardLocation.SOURCE_OUTPUT, fo)) {
596 if (fileManager.contains(StandardLocation.CLASS_OUTPUT, fo)) {
600 } catch (IOException e) {
604 JavaFileObject prev = log.useSource(tree.sourcefile);
606 log.error(tree.pos(), "file.sb.on.source.or.patch.path.for.module");
612 private String singleModuleOverride(List<JCCompilationUnit> trees) {
613 if (!fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) {
614 return legacyModuleOverride;
617 Set<String> override = new LinkedHashSet<>();
618 for (JCCompilationUnit tree : trees) {
619 JavaFileObject fo = tree.sourcefile;
623 fileManager.getLocationForModule(StandardLocation.PATCH_MODULE_PATH, fo);
626 override.add(fileManager.inferModuleName(loc));
628 } catch (IOException ex) {
633 switch (override.size()) {
634 case 0: return legacyModuleOverride;
635 case 1: return override.iterator().next();
637 log.error(Errors.TooManyPatchedModules(override));
643 * Determine the location for the module on the module source path
644 * or source output directory which contains a given CompilationUnit.
645 * If the source output directory is unset, the class output directory
646 * will be checked instead.
647 * {@code null} is returned if no such module can be found.
648 * @param tree the compilation unit tree
649 * @return the location for the enclosing module
650 * @throws IOException if there is a problem while searching for the module.
652 private Location getModuleLocation(JCCompilationUnit tree) throws IOException {
653 JavaFileObject fo = tree.sourcefile;
656 fileManager.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, fo);
658 Location sourceOutput = fileManager.hasLocation(StandardLocation.SOURCE_OUTPUT) ?
659 StandardLocation.SOURCE_OUTPUT : StandardLocation.CLASS_OUTPUT;
661 fileManager.getLocationForModule(sourceOutput, fo);
663 loc = fileManager.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, fileManager.inferModuleName(loc));
669 private void checkNoAllModulePath() {
670 if (addModsOpt != null && Arrays.asList(addModsOpt.split(",")).contains(ALL_MODULE_PATH)) {
671 log.error(Errors.AddmodsAllModulePathInvalid);
675 private final Completer mainCompleter = new Completer() {
677 public void complete(Symbol sym) throws CompletionFailure {
678 ModuleSymbol msym = moduleFinder.findModule((ModuleSymbol) sym);
680 if (msym.kind == ERR) {
681 //make sure the module is initialized:
682 msym.directives = List.nil();
683 msym.exports = List.nil();
684 msym.provides = List.nil();
685 msym.requires = List.nil();
686 msym.uses = List.nil();
687 } else if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) {
688 setupAutomaticModule(msym);
690 msym.module_info.complete();
693 // If module-info comes from a .java file, the underlying
694 // call of classFinder.fillIn will have called through the
695 // source completer, to Enter, and then to Modules.enter,
696 // which will call completeModule.
697 // But, if module-info comes from a .class file, the underlying
698 // call of classFinder.fillIn will just call ClassReader to read
699 // the .class file, and so we call completeModule here.
700 if (msym.module_info.classfile == null || msym.module_info.classfile.getKind() == Kind.CLASS) {
701 completeModule(msym);
706 public String toString() {
707 return "mainCompleter";
711 private void setupAutomaticModule(ModuleSymbol msym) throws CompletionFailure {
713 ListBuffer<Directive> directives = new ListBuffer<>();
714 ListBuffer<ExportsDirective> exports = new ListBuffer<>();
715 Set<String> seenPackages = new HashSet<>();
717 for (JavaFileObject clazz : fileManager.list(msym.classLocation, "", EnumSet.of(Kind.CLASS), true)) {
718 String binName = fileManager.inferBinaryName(msym.classLocation, clazz);
719 String pack = binName.lastIndexOf('.') != (-1) ? binName.substring(0, binName.lastIndexOf('.')) : ""; //unnamed package????
720 if (seenPackages.add(pack)) {
721 ExportsDirective d = new ExportsDirective(syms.enterPackage(msym, names.fromString(pack)), null);
728 msym.exports = exports.toList();
729 msym.provides = List.nil();
730 msym.requires = List.nil();
731 msym.uses = List.nil();
732 msym.directives = directives.toList();
733 msym.flags_field |= Flags.ACYCLIC;
734 } catch (IOException ex) {
735 throw new IllegalStateException(ex);
739 private void completeAutomaticModule(ModuleSymbol msym) throws CompletionFailure {
740 ListBuffer<Directive> directives = new ListBuffer<>();
742 directives.addAll(msym.directives);
744 ListBuffer<RequiresDirective> requires = new ListBuffer<>();
746 for (ModuleSymbol ms : allModules()) {
747 if (ms == syms.unnamedModule || ms == msym)
749 Set<RequiresFlag> flags = (ms.flags_field & Flags.AUTOMATIC_MODULE) != 0 ?
750 EnumSet.of(RequiresFlag.TRANSITIVE) : EnumSet.noneOf(RequiresFlag.class);
751 RequiresDirective d = new RequiresDirective(ms, flags);
756 RequiresDirective requiresUnnamed = new RequiresDirective(syms.unnamedModule);
757 directives.add(requiresUnnamed);
758 requires.add(requiresUnnamed);
760 msym.requires = requires.toList();
761 msym.directives = directives.toList();
764 private Completer getSourceCompleter(JCCompilationUnit tree) {
765 return new Completer() {
767 public void complete(Symbol sym) throws CompletionFailure {
768 ModuleSymbol msym = (ModuleSymbol) sym;
769 msym.flags_field |= UNATTRIBUTED;
770 ModuleVisitor v = new ModuleVisitor();
771 JavaFileObject prev = log.useSource(tree.sourcefile);
772 JCModuleDecl moduleDecl = tree.getModuleDecl();
773 DiagnosticPosition prevLintPos = deferredLintHandler.setPos(moduleDecl.pos());
776 moduleDecl.accept(v);
777 completeModule(msym);
778 checkCyclicDependencies(moduleDecl);
781 deferredLintHandler.setPos(prevLintPos);
782 msym.flags_field &= ~UNATTRIBUTED;
787 public String toString() {
788 return "SourceCompleter: " + tree.sourcefile.getName();
794 public boolean isRootModule(ModuleSymbol module) {
795 Assert.checkNonNull(rootModules);
796 return rootModules.contains(module);
799 public Set<ModuleSymbol> getRootModules() {
800 Assert.checkNonNull(rootModules);
804 class ModuleVisitor extends JCTree.Visitor {
805 private ModuleSymbol sym;
806 private final Set<ModuleSymbol> allRequires = new HashSet<>();
807 private final Map<PackageSymbol,List<ExportsDirective>> allExports = new HashMap<>();
808 private final Map<PackageSymbol,List<OpensDirective>> allOpens = new HashMap<>();
811 public void visitModuleDef(JCModuleDecl tree) {
812 sym = Assert.checkNonNull(tree.sym);
814 if (tree.getModuleType() == ModuleKind.OPEN) {
815 sym.flags.add(ModuleFlags.OPEN);
817 sym.flags_field |= (tree.mods.flags & Flags.DEPRECATED);
819 sym.requires = List.nil();
820 sym.exports = List.nil();
821 sym.opens = List.nil();
822 tree.directives.forEach(t -> t.accept(this));
823 sym.requires = sym.requires.reverse();
824 sym.exports = sym.exports.reverse();
825 sym.opens = sym.opens.reverse();
830 public void visitRequires(JCRequires tree) {
831 ModuleSymbol msym = lookupModule(tree.moduleName);
832 Set<RequiresFlag> flags = EnumSet.noneOf(RequiresFlag.class);
833 if (tree.isTransitive)
834 flags.add(RequiresFlag.TRANSITIVE);
835 if (tree.isStaticPhase)
836 flags.add(RequiresFlag.STATIC_PHASE);
837 RequiresDirective d = new RequiresDirective(msym, flags);
839 if (msym.kind != MDL) {
840 log.error(tree.moduleName.pos(), Errors.ModuleNotFound(msym));
841 warnedMissing.add(msym);
842 } else if (allRequires.contains(msym)) {
843 log.error(tree.moduleName.pos(), Errors.DuplicateRequires(msym));
845 allRequires.add(msym);
846 sym.requires = sym.requires.prepend(d);
851 public void visitExports(JCExports tree) {
852 Name name = TreeInfo.fullName(tree.qualid);
853 PackageSymbol packge = syms.enterPackage(sym, name);
854 attr.setPackageSymbols(tree.qualid, packge);
856 List<ExportsDirective> exportsForPackage = allExports.computeIfAbsent(packge, p -> List.nil());
857 for (ExportsDirective d : exportsForPackage) {
858 reportExportsConflict(tree, packge);
861 List<ModuleSymbol> toModules = null;
862 if (tree.moduleNames != null) {
863 Set<ModuleSymbol> to = new LinkedHashSet<>();
864 for (JCExpression n: tree.moduleNames) {
865 ModuleSymbol msym = lookupModule(n);
866 chk.checkModuleExists(n.pos(), msym);
867 for (ExportsDirective d : exportsForPackage) {
868 checkDuplicateExportsToModule(n, msym, d);
871 reportExportsConflictToModule(n, msym);
874 toModules = List.from(to);
877 if (toModules == null || !toModules.isEmpty()) {
878 Set<ExportsFlag> flags = EnumSet.noneOf(ExportsFlag.class);
879 ExportsDirective d = new ExportsDirective(packge, toModules, flags);
880 sym.exports = sym.exports.prepend(d);
883 allExports.put(packge, exportsForPackage.prepend(d));
887 private void reportExportsConflict(JCExports tree, PackageSymbol packge) {
888 log.error(tree.qualid.pos(), Errors.ConflictingExports(packge));
891 private void checkDuplicateExportsToModule(JCExpression name, ModuleSymbol msym,
892 ExportsDirective d) {
893 if (d.modules != null) {
894 for (ModuleSymbol other : d.modules) {
896 reportExportsConflictToModule(name, msym);
902 private void reportExportsConflictToModule(JCExpression name, ModuleSymbol msym) {
903 log.error(name.pos(), Errors.ConflictingExportsToModule(msym));
907 public void visitOpens(JCOpens tree) {
908 Name name = TreeInfo.fullName(tree.qualid);
909 PackageSymbol packge = syms.enterPackage(sym, name);
910 attr.setPackageSymbols(tree.qualid, packge);
912 if (sym.flags.contains(ModuleFlags.OPEN)) {
913 log.error(tree.pos(), Errors.NoOpensUnlessStrong);
915 List<OpensDirective> opensForPackage = allOpens.computeIfAbsent(packge, p -> List.nil());
916 for (OpensDirective d : opensForPackage) {
917 reportOpensConflict(tree, packge);
920 List<ModuleSymbol> toModules = null;
921 if (tree.moduleNames != null) {
922 Set<ModuleSymbol> to = new LinkedHashSet<>();
923 for (JCExpression n: tree.moduleNames) {
924 ModuleSymbol msym = lookupModule(n);
925 chk.checkModuleExists(n.pos(), msym);
926 for (OpensDirective d : opensForPackage) {
927 checkDuplicateOpensToModule(n, msym, d);
930 reportOpensConflictToModule(n, msym);
933 toModules = List.from(to);
936 if (toModules == null || !toModules.isEmpty()) {
937 Set<OpensFlag> flags = EnumSet.noneOf(OpensFlag.class);
938 OpensDirective d = new OpensDirective(packge, toModules, flags);
939 sym.opens = sym.opens.prepend(d);
942 allOpens.put(packge, opensForPackage.prepend(d));
946 private void reportOpensConflict(JCOpens tree, PackageSymbol packge) {
947 log.error(tree.qualid.pos(), Errors.ConflictingOpens(packge));
950 private void checkDuplicateOpensToModule(JCExpression name, ModuleSymbol msym,
952 if (d.modules != null) {
953 for (ModuleSymbol other : d.modules) {
955 reportOpensConflictToModule(name, msym);
961 private void reportOpensConflictToModule(JCExpression name, ModuleSymbol msym) {
962 log.error(name.pos(), Errors.ConflictingOpensToModule(msym));
966 public void visitProvides(JCProvides tree) { }
969 public void visitUses(JCUses tree) { }
971 private void ensureJavaBase() {
972 if (sym.name == names.java_base)
975 for (RequiresDirective d: sym.requires) {
976 if (d.module.name == names.java_base)
980 ModuleSymbol java_base = syms.enterModule(names.java_base);
981 Directive.RequiresDirective d =
982 new Directive.RequiresDirective(java_base,
983 EnumSet.of(Directive.RequiresFlag.MANDATED));
984 sym.requires = sym.requires.prepend(d);
987 private ModuleSymbol lookupModule(JCExpression moduleName) {
988 Name name = TreeInfo.fullName(moduleName);
989 ModuleSymbol msym = moduleFinder.findModule(name);
990 TreeInfo.setSymbol(moduleName, msym);
995 public Completer getUsesProvidesCompleter() {
997 ModuleSymbol msym = (ModuleSymbol) sym;
1001 Env<AttrContext> env = typeEnvs.get(msym);
1002 UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env);
1003 JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
1004 JCModuleDecl decl = env.toplevel.getModuleDecl();
1005 DiagnosticPosition prevLintPos = deferredLintHandler.setPos(decl.pos());
1010 log.useSource(prev);
1011 deferredLintHandler.setPos(prevLintPos);
1016 class UsesProvidesVisitor extends JCTree.Visitor {
1017 private final ModuleSymbol msym;
1018 private final Env<AttrContext> env;
1020 private final Set<ClassSymbol> allUses = new HashSet<>();
1021 private final Map<ClassSymbol, Set<ClassSymbol>> allProvides = new HashMap<>();
1023 public UsesProvidesVisitor(ModuleSymbol msym, Env<AttrContext> env) {
1028 @Override @SuppressWarnings("unchecked")
1029 public void visitModuleDef(JCModuleDecl tree) {
1030 msym.directives = List.nil();
1031 msym.provides = List.nil();
1032 msym.uses = List.nil();
1033 tree.directives.forEach(t -> t.accept(this));
1034 msym.directives = msym.directives.reverse();
1035 msym.provides = msym.provides.reverse();
1036 msym.uses = msym.uses.reverse();
1038 if (msym.requires.nonEmpty() && msym.requires.head.flags.contains(RequiresFlag.MANDATED))
1039 msym.directives = msym.directives.prepend(msym.requires.head);
1041 msym.directives = msym.directives.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet())));
1043 checkForCorrectness();
1047 public void visitExports(JCExports tree) {
1048 Iterable<Symbol> packageContent = tree.directive.packge.members().getSymbols();
1049 List<JavaFileObject> filesToCheck = List.nil();
1050 boolean packageNotEmpty = false;
1051 for (Symbol sym : packageContent) {
1052 if (sym.kind != Kinds.Kind.TYP)
1054 ClassSymbol csym = (ClassSymbol) sym;
1055 if (sym.completer.isTerminal() ||
1056 csym.classfile.getKind() == Kind.CLASS) {
1057 packageNotEmpty = true;
1058 filesToCheck = List.nil();
1061 if (csym.classfile.getKind() == Kind.SOURCE) {
1062 filesToCheck = filesToCheck.prepend(csym.classfile);
1065 for (JavaFileObject jfo : filesToCheck) {
1066 if (findPackageInFile.findPackageNameOf(jfo) == tree.directive.packge.fullname) {
1067 packageNotEmpty = true;
1071 if (!packageNotEmpty) {
1072 log.error(tree.qualid.pos(), Errors.PackageEmptyOrNotFound(tree.directive.packge));
1074 msym.directives = msym.directives.prepend(tree.directive);
1078 public void visitOpens(JCOpens tree) {
1079 chk.checkPackageExistsForOpens(tree.qualid, tree.directive.packge);
1080 msym.directives = msym.directives.prepend(tree.directive);
1083 MethodSymbol noArgsConstructor(ClassSymbol tsym) {
1084 for (Symbol sym : tsym.members().getSymbolsByName(names.init)) {
1085 MethodSymbol mSym = (MethodSymbol)sym;
1086 if (mSym.params().isEmpty()) {
1093 MethodSymbol factoryMethod(ClassSymbol tsym) {
1094 for (Symbol sym : tsym.members().getSymbolsByName(names.provider, sym -> sym.kind == MTH)) {
1095 MethodSymbol mSym = (MethodSymbol)sym;
1096 if (mSym.isStatic() && (mSym.flags() & Flags.PUBLIC) != 0 && mSym.params().isEmpty()) {
1103 Map<Directive.ProvidesDirective, JCProvides> directiveToTreeMap = new HashMap<>();
1106 public void visitProvides(JCProvides tree) {
1107 Type st = attr.attribType(tree.serviceName, env, syms.objectType);
1108 ClassSymbol service = (ClassSymbol) st.tsym;
1109 if (allProvides.containsKey(service)) {
1110 log.error(tree.serviceName.pos(), Errors.RepeatedProvidesForService(service));
1112 ListBuffer<ClassSymbol> impls = new ListBuffer<>();
1113 for (JCExpression implName : tree.implNames) {
1115 boolean prevVisitingServiceImplementation = env.info.visitingServiceImplementation;
1117 env.info.visitingServiceImplementation = true;
1118 it = attr.attribType(implName, env, syms.objectType);
1120 env.info.visitingServiceImplementation = prevVisitingServiceImplementation;
1122 ClassSymbol impl = (ClassSymbol) it.tsym;
1123 if ((impl.flags_field & PUBLIC) == 0) {
1124 log.error(implName.pos(), Errors.NotDefPublic(impl, impl.location()));
1126 //find provider factory:
1127 MethodSymbol factory = factoryMethod(impl);
1128 if (factory != null) {
1129 Type returnType = factory.type.getReturnType();
1130 if (!types.isSubtype(returnType, st)) {
1131 log.error(implName.pos(), Errors.ServiceImplementationProviderReturnMustBeSubtypeOfServiceInterface);
1134 if (!types.isSubtype(it, st)) {
1135 log.error(implName.pos(), Errors.ServiceImplementationMustBeSubtypeOfServiceInterface);
1136 } else if ((impl.flags() & ABSTRACT) != 0) {
1137 log.error(implName.pos(), Errors.ServiceImplementationIsAbstract(impl));
1138 } else if (impl.isInner()) {
1139 log.error(implName.pos(), Errors.ServiceImplementationIsInner(impl));
1141 MethodSymbol constr = noArgsConstructor(impl);
1142 if (constr == null) {
1143 log.error(implName.pos(), Errors.ServiceImplementationDoesntHaveANoArgsConstructor(impl));
1144 } else if ((constr.flags() & PUBLIC) == 0) {
1145 log.error(implName.pos(), Errors.ServiceImplementationNoArgsConstructorNotPublic(impl));
1149 if (it.hasTag(CLASS)) {
1150 if (allProvides.computeIfAbsent(service, s -> new HashSet<>()).add(impl)) {
1153 log.error(implName.pos(), Errors.DuplicateProvides(service, impl));
1157 if (st.hasTag(CLASS) && !impls.isEmpty()) {
1158 Directive.ProvidesDirective d = new Directive.ProvidesDirective(service, impls.toList());
1159 msym.provides = msym.provides.prepend(d);
1160 msym.directives = msym.directives.prepend(d);
1161 directiveToTreeMap.put(d, tree);
1166 public void visitRequires(JCRequires tree) {
1167 if (tree.directive != null && allModules().contains(tree.directive.module)) {
1168 chk.checkDeprecated(tree.moduleName.pos(), msym, tree.directive.module);
1169 chk.checkModuleRequires(tree.moduleName.pos(), tree.directive);
1170 msym.directives = msym.directives.prepend(tree.directive);
1175 public void visitUses(JCUses tree) {
1176 Type st = attr.attribType(tree.qualid, env, syms.objectType);
1177 Symbol sym = TreeInfo.symbol(tree.qualid);
1178 if ((sym.flags() & ENUM) != 0) {
1179 log.error(tree.qualid.pos(), Errors.ServiceDefinitionIsEnum(st.tsym));
1180 } else if (st.hasTag(CLASS)) {
1181 ClassSymbol service = (ClassSymbol) st.tsym;
1182 if (allUses.add(service)) {
1183 Directive.UsesDirective d = new Directive.UsesDirective(service);
1184 msym.uses = msym.uses.prepend(d);
1185 msym.directives = msym.directives.prepend(d);
1187 log.error(tree.pos(), Errors.DuplicateUses(service));
1192 private void checkForCorrectness() {
1193 for (Directive.ProvidesDirective provides : msym.provides) {
1194 JCProvides tree = directiveToTreeMap.get(provides);
1195 for (ClassSymbol impl : provides.impls) {
1196 /* The implementation must be defined in the same module as the provides directive
1199 PackageSymbol implementationDefiningPackage = impl.packge();
1200 if (implementationDefiningPackage.modle != msym) {
1201 // TODO: should use tree for the implentation name, not the entire provides tree
1202 // TODO: should improve error message to identify the implementation type
1203 log.error(tree.pos(), Errors.ServiceImplementationNotInRightModule(implementationDefiningPackage.modle));
1206 /* There is no inherent requirement that module that provides a service should actually
1207 * use it itself. However, it is a pointless declaration if the service package is not
1208 * exported and there is no uses for the service.
1210 PackageSymbol interfaceDeclaringPackage = provides.service.packge();
1211 boolean isInterfaceDeclaredInCurrentModule = interfaceDeclaringPackage.modle == msym;
1212 boolean isInterfaceExportedFromAReadableModule =
1213 msym.visiblePackages.get(interfaceDeclaringPackage.fullname) == interfaceDeclaringPackage;
1214 if (isInterfaceDeclaredInCurrentModule && !isInterfaceExportedFromAReadableModule) {
1215 // ok the interface is declared in this module. Let's check if it's exported
1216 boolean warn = true;
1217 for (ExportsDirective export : msym.exports) {
1218 if (interfaceDeclaringPackage == export.packge) {
1224 for (UsesDirective uses : msym.uses) {
1225 if (provides.service == uses.service) {
1232 log.warning(tree.pos(), Warnings.ServiceProvidedButNotExportedOrUsed(provides.service));
1240 private Set<ModuleSymbol> allModules;
1242 public Set<ModuleSymbol> allModules() {
1243 Assert.checkNonNull(allModules);
1247 private void setupAllModules() {
1248 Assert.checkNonNull(rootModules);
1249 Assert.checkNull(allModules);
1251 Set<ModuleSymbol> observable;
1253 if (limitModsOpt == null && extraLimitMods.isEmpty()) {
1256 Set<ModuleSymbol> limitMods = new HashSet<>();
1257 if (limitModsOpt != null) {
1258 for (String limit : limitModsOpt.split(",")) {
1259 if (!isValidName(limit))
1261 limitMods.add(syms.enterModule(names.fromString(limit)));
1264 for (String limit : extraLimitMods) {
1265 limitMods.add(syms.enterModule(names.fromString(limit)));
1267 observable = computeTransitiveClosure(limitMods, null);
1268 observable.addAll(rootModules);
1270 for (ModuleSymbol msym : limitMods) {
1271 if (!observable.contains(msym)) {
1272 log.warning(LintCategory.OPTIONS,
1273 Warnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym));
1279 Predicate<ModuleSymbol> observablePred = sym ->
1280 (observable == null) ? (moduleFinder.findModule(sym).kind != ERR) : observable.contains(sym);
1281 Predicate<ModuleSymbol> systemModulePred = sym -> (sym.flags() & Flags.SYSTEM_MODULE) != 0;
1282 Set<ModuleSymbol> enabledRoot = new LinkedHashSet<>();
1284 if (rootModules.contains(syms.unnamedModule)) {
1285 ModuleSymbol javaSE = syms.getModule(java_se);
1286 Predicate<ModuleSymbol> jdkModulePred;
1288 if (javaSE != null && (observable == null || observable.contains(javaSE))) {
1289 jdkModulePred = sym -> {
1291 return !sym.name.startsWith(java_)
1292 && sym.exports.stream().anyMatch(e -> e.modules == null);
1294 enabledRoot.add(javaSE);
1296 jdkModulePred = sym -> true;
1299 Predicate<ModuleSymbol> noIncubatorPred = sym -> {
1301 return !sym.resolutionFlags.contains(ModuleResolutionFlags.DO_NOT_RESOLVE_BY_DEFAULT);
1304 for (ModuleSymbol sym : new HashSet<>(syms.getAllModules())) {
1306 if (systemModulePred.test(sym) && observablePred.test(sym) && jdkModulePred.test(sym) && noIncubatorPred.test(sym)) {
1307 enabledRoot.add(sym);
1309 } catch (CompletionFailure ex) {
1310 chk.completionError(null, ex);
1315 enabledRoot.addAll(rootModules);
1317 if (addModsOpt != null || !extraAddMods.isEmpty()) {
1318 Set<String> fullAddMods = new HashSet<>();
1319 fullAddMods.addAll(extraAddMods);
1321 if (addModsOpt != null) {
1322 fullAddMods.addAll(Arrays.asList(addModsOpt.split(",")));
1325 for (String added : fullAddMods) {
1326 Stream<ModuleSymbol> modules;
1329 modules = new HashSet<>(syms.getAllModules())
1331 .filter(systemModulePred.and(observablePred));
1333 case ALL_MODULE_PATH:
1334 modules = new HashSet<>(syms.getAllModules())
1336 .filter(systemModulePred.negate().and(observablePred));
1339 if (!isValidName(added))
1341 modules = Stream.of(syms.enterModule(names.fromString(added)));
1344 modules.forEach(sym -> {
1345 enabledRoot.add(sym);
1346 if (observable != null)
1347 observable.add(sym);
1352 Set<ModuleSymbol> result = computeTransitiveClosure(enabledRoot, observable);
1354 result.add(syms.unnamedModule);
1356 boolean hasAutomatic = result.stream().anyMatch(IS_AUTOMATIC);
1359 syms.getAllModules()
1361 .filter(IS_AUTOMATIC)
1362 .forEach(result::add);
1365 String incubatingModules = result.stream()
1366 .filter(msym -> msym.resolutionFlags.contains(ModuleResolutionFlags.WARN_INCUBATING))
1367 .map(msym -> msym.name.toString())
1368 .collect(Collectors.joining(","));
1370 if (!incubatingModules.isEmpty()) {
1371 log.warning(Warnings.IncubatingModules(incubatingModules));
1374 allModules = result;
1376 //add module versions from options, if any:
1377 if (moduleVersionOpt != null) {
1378 Name version = names.fromString(moduleVersionOpt);
1379 rootModules.forEach(m -> m.version = version);
1383 private static final Predicate<ModuleSymbol> IS_AUTOMATIC =
1384 m -> (m.flags_field & Flags.AUTOMATIC_MODULE) != 0;
1386 public boolean isInModuleGraph(ModuleSymbol msym) {
1387 return allModules == null || allModules.contains(msym);
1390 private Set<ModuleSymbol> computeTransitiveClosure(Set<? extends ModuleSymbol> base, Set<ModuleSymbol> observable) {
1391 List<ModuleSymbol> primaryTodo = List.nil();
1392 List<ModuleSymbol> secondaryTodo = List.nil();
1394 for (ModuleSymbol ms : base) {
1395 primaryTodo = primaryTodo.prepend(ms);
1398 Set<ModuleSymbol> result = new LinkedHashSet<>();
1399 result.add(syms.java_base);
1401 while (primaryTodo.nonEmpty() || secondaryTodo.nonEmpty()) {
1403 ModuleSymbol current;
1404 boolean isPrimaryTodo;
1405 if (primaryTodo.nonEmpty()) {
1406 current = primaryTodo.head;
1407 primaryTodo = primaryTodo.tail;
1408 isPrimaryTodo = true;
1410 current = secondaryTodo.head;
1411 secondaryTodo = secondaryTodo.tail;
1412 isPrimaryTodo = false;
1414 if (observable != null && !observable.contains(current))
1416 if (!result.add(current) || current == syms.unnamedModule || ((current.flags_field & Flags.AUTOMATIC_MODULE) != 0))
1419 if (current.kind == ERR && isPrimaryTodo && warnedMissing.add(current)) {
1420 log.error(Errors.ModuleNotFound(current));
1422 for (RequiresDirective rd : current.requires) {
1423 if (rd.module == syms.java_base) continue;
1424 if ((rd.isTransitive() && isPrimaryTodo) || base.contains(current)) {
1425 primaryTodo = primaryTodo.prepend(rd.module);
1427 secondaryTodo = secondaryTodo.prepend(rd.module);
1430 } catch (CompletionFailure ex) {
1431 chk.completionError(null, ex);
1438 public ModuleSymbol getObservableModule(Name name) {
1439 ModuleSymbol mod = syms.getModule(name);
1441 if (allModules().contains(mod)) {
1448 private Completer getUnnamedModuleCompleter() {
1449 moduleFinder.findAllModules();
1450 return new Symbol.Completer() {
1452 public void complete(Symbol sym) throws CompletionFailure {
1453 if (inInitModules) {
1454 sym.completer = this;
1457 ModuleSymbol msym = (ModuleSymbol) sym;
1458 Set<ModuleSymbol> allModules = new HashSet<>(allModules());
1459 allModules.remove(syms.unnamedModule);
1460 for (ModuleSymbol m : allModules) {
1463 initVisiblePackages(msym, allModules);
1467 public String toString() {
1468 return "unnamedModule Completer";
1473 private final Map<ModuleSymbol, Set<ModuleSymbol>> requiresTransitiveCache = new HashMap<>();
1475 private void completeModule(ModuleSymbol msym) {
1476 if (inInitModules) {
1477 msym.completer = sym -> completeModule(msym);
1481 if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) {
1482 completeAutomaticModule(msym);
1485 Assert.checkNonNull(msym.requires);
1489 msym.requires = msym.requires.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet())));
1491 List<RequiresDirective> requires = msym.requires;
1493 while (requires.nonEmpty()) {
1494 if (!allModules().contains(requires.head.module)) {
1495 Env<AttrContext> env = typeEnvs.get(msym);
1497 JavaFileObject origSource = log.useSource(env.toplevel.sourcefile);
1499 log.error(/*XXX*/env.tree, Errors.ModuleNotFound(requires.head.module));
1501 log.useSource(origSource);
1504 Assert.check((msym.flags() & Flags.AUTOMATIC_MODULE) == 0);
1506 msym.requires = List.filter(msym.requires, requires.head);
1508 requires = requires.tail;
1511 Set<ModuleSymbol> readable = new LinkedHashSet<>();
1512 Set<ModuleSymbol> requiresTransitive = new HashSet<>();
1514 for (RequiresDirective d : msym.requires) {
1515 d.module.complete();
1516 readable.add(d.module);
1517 Set<ModuleSymbol> s = retrieveRequiresTransitive(d.module);
1518 Assert.checkNonNull(s, () -> "no entry in cache for " + d.module);
1520 if (d.flags.contains(RequiresFlag.TRANSITIVE)) {
1521 requiresTransitive.add(d.module);
1522 requiresTransitive.addAll(s);
1526 requiresTransitiveCache.put(msym, requiresTransitive);
1527 initVisiblePackages(msym, readable);
1528 for (ExportsDirective d: msym.exports) {
1529 if (d.packge != null) {
1530 d.packge.modle = msym;
1536 private Set<ModuleSymbol> retrieveRequiresTransitive(ModuleSymbol msym) {
1537 Set<ModuleSymbol> requiresTransitive = requiresTransitiveCache.get(msym);
1539 if (requiresTransitive == null) {
1540 //the module graph may contain cycles involving automatic modules or --add-reads edges
1541 requiresTransitive = new HashSet<>();
1543 Set<ModuleSymbol> seen = new HashSet<>();
1544 List<ModuleSymbol> todo = List.of(msym);
1546 while (todo.nonEmpty()) {
1547 ModuleSymbol current = todo.head;
1549 if (!seen.add(current))
1551 requiresTransitive.add(current);
1553 Iterable<? extends RequiresDirective> requires;
1554 if (current != syms.unnamedModule) {
1555 Assert.checkNonNull(current.requires, () -> current + ".requires == null; " + msym);
1556 requires = current.requires;
1557 for (RequiresDirective rd : requires) {
1558 if (rd.isTransitive())
1559 todo = todo.prepend(rd.module);
1562 for (ModuleSymbol mod : allModules()) {
1563 todo = todo.prepend(mod);
1568 requiresTransitive.remove(msym);
1571 return requiresTransitive;
1574 private void initVisiblePackages(ModuleSymbol msym, Collection<ModuleSymbol> readable) {
1577 msym.visiblePackages = new LinkedHashMap<>();
1578 msym.readModules = new HashSet<>(readable);
1580 Map<Name, ModuleSymbol> seen = new HashMap<>();
1582 for (ModuleSymbol rm : readable) {
1583 if (rm == syms.unnamedModule)
1585 addVisiblePackages(msym, seen, rm, rm.exports);
1588 addExports.forEach((exportsFrom, exports) -> {
1589 addVisiblePackages(msym, seen, exportsFrom, exports);
1593 private void addVisiblePackages(ModuleSymbol msym,
1594 Map<Name, ModuleSymbol> seenPackages,
1595 ModuleSymbol exportsFrom,
1596 Collection<ExportsDirective> exports) {
1597 for (ExportsDirective d : exports) {
1598 if (d.modules == null || d.modules.contains(msym)) {
1599 Name packageName = d.packge.fullname;
1600 ModuleSymbol previousModule = seenPackages.get(packageName);
1602 if (previousModule != null && previousModule != exportsFrom) {
1603 Env<AttrContext> env = typeEnvs.get(msym);
1604 JavaFileObject origSource = env != null ? log.useSource(env.toplevel.sourcefile)
1606 DiagnosticPosition pos = env != null ? env.tree.pos() : null;
1608 log.error(pos, Errors.PackageClashFromRequires(msym, packageName,
1609 previousModule, exportsFrom));
1612 log.useSource(origSource);
1617 seenPackages.put(packageName, exportsFrom);
1618 msym.visiblePackages.put(d.packge.fullname, d.packge);
1623 private void initAddExports() {
1624 if (addExports != null)
1627 addExports = new LinkedHashMap<>();
1628 Set<ModuleSymbol> unknownModules = new HashSet<>();
1630 if (addExportsOpt == null)
1633 Pattern ep = Pattern.compile("([^/]+)/([^=]+)=(.*)");
1634 for (String s: addExportsOpt.split("\0+")) {
1637 Matcher em = ep.matcher(s);
1638 if (!em.matches()) {
1642 // Terminology comes from
1643 // --add-exports module/package=target,...
1645 // module module { exports package to target, ... }
1646 String moduleName = em.group(1);
1647 String packageName = em.group(2);
1648 String targetNames = em.group(3);
1650 if (!isValidName(moduleName))
1653 ModuleSymbol msym = syms.enterModule(names.fromString(moduleName));
1654 if (!isKnownModule(msym, unknownModules))
1657 if (!isValidName(packageName))
1659 PackageSymbol p = syms.enterPackage(msym, names.fromString(packageName));
1660 p.modle = msym; // TODO: do we need this?
1662 List<ModuleSymbol> targetModules = List.nil();
1663 for (String toModule : targetNames.split("[ ,]+")) {
1665 if (toModule.equals("ALL-UNNAMED")) {
1666 m = syms.unnamedModule;
1668 if (!isValidName(toModule))
1670 m = syms.enterModule(names.fromString(toModule));
1671 if (!isKnownModule(m, unknownModules))
1674 targetModules = targetModules.prepend(m);
1677 Set<ExportsDirective> extra = addExports.computeIfAbsent(msym, _x -> new LinkedHashSet<>());
1678 ExportsDirective d = new ExportsDirective(p, targetModules);
1683 private boolean isKnownModule(ModuleSymbol msym, Set<ModuleSymbol> unknownModules) {
1684 if (allModules.contains(msym)) {
1688 if (!unknownModules.contains(msym)) {
1690 log.warning(LintCategory.OPTIONS,
1691 Warnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym));
1693 unknownModules.add(msym);
1698 private void initAddReads() {
1699 if (addReads != null)
1702 addReads = new LinkedHashMap<>();
1704 if (addReadsOpt == null)
1707 Pattern rp = Pattern.compile("([^=]+)=(.*)");
1708 for (String s : addReadsOpt.split("\0+")) {
1711 Matcher rm = rp.matcher(s);
1712 if (!rm.matches()) {
1716 // Terminology comes from
1717 // --add-reads source-module=target-module,...
1719 // module source-module { requires target-module; ... }
1720 String sourceName = rm.group(1);
1721 String targetNames = rm.group(2);
1723 if (!isValidName(sourceName))
1726 ModuleSymbol msym = syms.enterModule(names.fromString(sourceName));
1727 if (!allModules.contains(msym)) {
1729 log.warning(Warnings.ModuleForOptionNotFound(Option.ADD_READS, msym));
1734 for (String targetName : targetNames.split("[ ,]+", -1)) {
1735 ModuleSymbol targetModule;
1736 if (targetName.equals("ALL-UNNAMED")) {
1737 targetModule = syms.unnamedModule;
1739 if (!isValidName(targetName))
1741 targetModule = syms.enterModule(names.fromString(targetName));
1742 if (!allModules.contains(targetModule)) {
1744 log.warning(LintCategory.OPTIONS, Warnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule));
1749 addReads.computeIfAbsent(msym, m -> new HashSet<>())
1750 .add(new RequiresDirective(targetModule, EnumSet.of(RequiresFlag.EXTRA)));
1755 private void checkCyclicDependencies(JCModuleDecl mod) {
1756 for (JCDirective d : mod.directives) {
1758 if (!d.hasTag(Tag.REQUIRES) || (rd = (JCRequires) d).directive == null)
1760 Set<ModuleSymbol> nonSyntheticDeps = new HashSet<>();
1761 List<ModuleSymbol> queue = List.of(rd.directive.module);
1762 while (queue.nonEmpty()) {
1763 ModuleSymbol current = queue.head;
1765 if (!nonSyntheticDeps.add(current))
1768 if ((current.flags() & Flags.ACYCLIC) != 0)
1770 if (current.kind != MDL)
1772 Assert.checkNonNull(current.requires, current::toString);
1773 for (RequiresDirective dep : current.requires) {
1774 if (!dep.flags.contains(RequiresFlag.EXTRA))
1775 queue = queue.prepend(dep.module);
1778 if (nonSyntheticDeps.contains(mod.sym)) {
1779 log.error(rd.moduleName.pos(), Errors.CyclicRequires(rd.directive.module));
1781 mod.sym.flags_field |= Flags.ACYCLIC;
1785 private boolean isValidName(CharSequence name) {
1786 return SourceVersion.isName(name, Source.toSourceVersion(source));
1790 private String toString(ModuleSymbol msym) {
1791 return msym.name + "["
1792 + "kind:" + msym.kind + ";"
1793 + "locn:" + toString(msym.sourceLocation) + "," + toString(msym.classLocation) + ";"
1794 + "info:" + toString(msym.module_info.sourcefile) + ","
1795 + toString(msym.module_info.classfile) + ","
1796 + msym.module_info.completer
1801 String toString(Location locn) {
1802 return (locn == null) ? "--" : locn.getName();
1806 String toString(JavaFileObject fo) {
1807 return (fo == null) ? "--" : fo.getName();
1810 public void newRound() {
1813 warnedMissing.clear();
1816 public interface PackageNameFinder {
1817 public Name findPackageNameOf(JavaFileObject jfo);