1 /* 2 * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27 package com.sun.tools.javac.comp; 28 29 import java.io.IOException; 30 import java.util.Arrays; 31 import java.util.Collection; 32 import java.util.Collections; 33 import java.util.EnumSet; 34 import java.util.HashMap; 35 import java.util.HashSet; 36 import java.util.LinkedHashMap; 37 import java.util.LinkedHashSet; 38 import java.util.Map; 39 import java.util.Map.Entry; 40 import java.util.Set; 41 import java.util.function.Consumer; 42 import java.util.function.Predicate; 43 import java.util.regex.Matcher; 44 import java.util.regex.Pattern; 45 import java.util.stream.Stream; 46 47 import javax.lang.model.SourceVersion; 48 import javax.tools.JavaFileManager; 49 import javax.tools.JavaFileManager.Location; 50 import javax.tools.JavaFileObject; 51 import javax.tools.JavaFileObject.Kind; 52 import javax.tools.StandardLocation; 53 54 import com.sun.tools.javac.code.ClassFinder; 55 import com.sun.tools.javac.code.Directive; 56 import com.sun.tools.javac.code.Directive.ExportsDirective; 57 import com.sun.tools.javac.code.Directive.RequiresDirective; 58 import com.sun.tools.javac.code.Directive.RequiresFlag; 59 import com.sun.tools.javac.code.Directive.UsesDirective; 60 import com.sun.tools.javac.code.Flags; 61 import com.sun.tools.javac.code.Kinds; 62 import com.sun.tools.javac.code.ModuleFinder; 63 import com.sun.tools.javac.code.Source; 64 import com.sun.tools.javac.code.Symbol; 65 import com.sun.tools.javac.code.Symbol.ClassSymbol; 66 import com.sun.tools.javac.code.Symbol.Completer; 67 import com.sun.tools.javac.code.Symbol.CompletionFailure; 68 import com.sun.tools.javac.code.Symbol.MethodSymbol; 69 import com.sun.tools.javac.code.Symbol.ModuleSymbol; 70 import com.sun.tools.javac.code.Symbol.PackageSymbol; 71 import com.sun.tools.javac.code.Symtab; 72 import com.sun.tools.javac.code.Type; 73 import com.sun.tools.javac.code.Types; 74 import com.sun.tools.javac.jvm.ClassWriter; 75 import com.sun.tools.javac.jvm.JNIWriter; 76 import com.sun.tools.javac.main.Option; 77 import com.sun.tools.javac.resources.CompilerProperties.Errors; 78 import com.sun.tools.javac.resources.CompilerProperties.Warnings; 79 import com.sun.tools.javac.tree.JCTree; 80 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 81 import com.sun.tools.javac.tree.JCTree.JCExports; 82 import com.sun.tools.javac.tree.JCTree.JCExpression; 83 import com.sun.tools.javac.tree.JCTree.JCModuleDecl; 84 import com.sun.tools.javac.tree.JCTree.JCPackageDecl; 85 import com.sun.tools.javac.tree.JCTree.JCProvides; 86 import com.sun.tools.javac.tree.JCTree.JCRequires; 87 import com.sun.tools.javac.tree.JCTree.JCUses; 88 import com.sun.tools.javac.tree.TreeInfo; 89 import com.sun.tools.javac.util.Assert; 90 import com.sun.tools.javac.util.Context; 91 import com.sun.tools.javac.util.JCDiagnostic; 92 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 93 import com.sun.tools.javac.util.List; 94 import com.sun.tools.javac.util.ListBuffer; 95 import com.sun.tools.javac.util.Log; 96 import com.sun.tools.javac.util.Name; 97 import com.sun.tools.javac.util.Names; 98 import com.sun.tools.javac.util.Options; 99 100 import static com.sun.tools.javac.code.Flags.UNATTRIBUTED; 101 import static com.sun.tools.javac.code.Kinds.Kind.MDL; 102 import static com.sun.tools.javac.code.TypeTag.CLASS; 103 104 import com.sun.tools.javac.tree.JCTree.JCDirective; 105 import com.sun.tools.javac.tree.JCTree.Tag; 106 import com.sun.tools.javac.util.Abort; 107 import com.sun.tools.javac.util.Position; 108 109 import static com.sun.tools.javac.code.Flags.ABSTRACT; 110 import static com.sun.tools.javac.code.Flags.ENUM; 111 import static com.sun.tools.javac.code.Flags.PUBLIC; 112 import static com.sun.tools.javac.tree.JCTree.Tag.MODULEDEF; 113 114 /** 115 * TODO: fill in 116 * 117 * <p><b>This is NOT part of any supported API. 118 * If you write code that depends on this, you do so at your own risk. 119 * This code and its internal interfaces are subject to change or 120 * deletion without notice.</b> 121 */ 122 public class Modules extends JCTree.Visitor { 123 private static final String ALL_SYSTEM = "ALL-SYSTEM"; 124 private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; 125 126 private final Log log; 127 private final Names names; 128 private final Symtab syms; 129 private final Attr attr; 130 private final TypeEnvs typeEnvs; 131 private final Types types; 132 private final JavaFileManager fileManager; 133 private final ModuleFinder moduleFinder; 134 private final boolean allowModules; 135 136 public final boolean multiModuleMode; 137 138 private final String moduleOverride; 139 140 private final Name java_se; 141 private final Name java_; 142 143 ModuleSymbol defaultModule; 144 145 private final String addExportsOpt; 146 private Map<ModuleSymbol, Set<ExportsDirective>> addExports; 147 private final String addReadsOpt; 148 private Map<ModuleSymbol, Set<RequiresDirective>> addReads; 149 private final String addModsOpt; 150 private final Set<String> extraAddMods = new HashSet<>(); 151 private final String limitModsOpt; 152 private final Set<String> extraLimitMods = new HashSet<>(); 153 154 private Set<ModuleSymbol> rootModules = null; 155 156 public static Modules instance(Context context) { 157 Modules instance = context.get(Modules.class); 158 if (instance == null) 159 instance = new Modules(context); 160 return instance; 161 } 162 163 protected Modules(Context context) { 164 context.put(Modules.class, this); 165 log = Log.instance(context); 166 names = Names.instance(context); 167 syms = Symtab.instance(context); 168 attr = Attr.instance(context); 169 typeEnvs = TypeEnvs.instance(context); 170 moduleFinder = ModuleFinder.instance(context); 171 types = Types.instance(context); 172 fileManager = context.get(JavaFileManager.class); 173 allowModules = Source.instance(context).allowModules(); 174 Options options = Options.instance(context); 175 176 moduleOverride = options.get(Option.XMODULE); 177 178 multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH); 179 ClassWriter classWriter = ClassWriter.instance(context); 180 classWriter.multiModuleMode = multiModuleMode; 181 JNIWriter jniWriter = JNIWriter.instance(context); 182 jniWriter.multiModuleMode = multiModuleMode; 183 184 java_se = names.fromString("java.se"); 185 java_ = names.fromString("java."); 186 187 addExportsOpt = options.get(Option.ADD_EXPORTS); 188 addReadsOpt = options.get(Option.ADD_READS); 189 addModsOpt = options.get(Option.ADD_MODULES); 190 limitModsOpt = options.get(Option.LIMIT_MODULES); 191 } 192 193 int depth = -1; 194 private void dprintln(String msg) { 195 for (int i = 0; i < depth; i++) 196 System.err.print(" "); 197 System.err.println(msg); 198 } 199 200 public void addExtraAddModules(String... extras) { 201 extraAddMods.addAll(Arrays.asList(extras)); 202 } 203 204 public void addExtraLimitModules(String... extras) { 205 extraLimitMods.addAll(Arrays.asList(extras)); 206 } 207 208 boolean inInitModules; 209 public void initModules(List<JCCompilationUnit> trees) { 210 Assert.check(!inInitModules); 211 try { 212 inInitModules = true; 213 Assert.checkNull(rootModules); 214 enter(trees, modules -> { 215 Assert.checkNull(rootModules); 216 Assert.checkNull(allModules); 217 this.rootModules = modules; 218 setupAllModules(); //initialize the module graph 219 Assert.checkNonNull(allModules); 220 inInitModules = false; 221 }, null); 222 } finally { 223 inInitModules = false; 224 } 225 } 226 227 public boolean enter(List<JCCompilationUnit> trees, ClassSymbol c) { 228 Assert.check(rootModules != null || inInitModules || !allowModules); 229 return enter(trees, modules -> {}, c); 230 } 231 232 private boolean enter(List<JCCompilationUnit> trees, Consumer<Set<ModuleSymbol>> init, ClassSymbol c) { 233 if (!allowModules) { 234 for (JCCompilationUnit tree: trees) { 235 tree.modle = syms.noModule; 236 } 237 defaultModule = syms.noModule; 238 return true; 239 } 240 241 int startErrors = log.nerrors; 242 243 depth++; 244 try { 245 // scan trees for module defs 246 Set<ModuleSymbol> roots = enterModules(trees, c); 247 248 setCompilationUnitModules(trees, roots); 249 250 init.accept(roots); 251 252 for (ModuleSymbol msym: roots) { 253 msym.complete(); 254 } 255 } catch (CompletionFailure ex) { 256 log.error(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE, Position.NOPOS, "cant.access", ex.sym, ex.getDetailValue()); 257 if (ex instanceof ClassFinder.BadClassFile) throw new Abort(); 258 } finally { 259 depth--; 260 } 261 262 return (log.nerrors == startErrors); 263 } 264 265 public Completer getCompleter() { 266 return mainCompleter; 267 } 268 269 public ModuleSymbol getDefaultModule() { 270 return defaultModule; 271 } 272 273 private Set<ModuleSymbol> enterModules(List<JCCompilationUnit> trees, ClassSymbol c) { 274 Set<ModuleSymbol> modules = new LinkedHashSet<>(); 275 for (JCCompilationUnit tree : trees) { 276 JavaFileObject prev = log.useSource(tree.sourcefile); 277 try { 278 enterModule(tree, c, modules); 279 } finally { 280 log.useSource(prev); 281 } 282 } 283 return modules; 284 } 285 286 287 private void enterModule(JCCompilationUnit toplevel, ClassSymbol c, Set<ModuleSymbol> modules) { 288 boolean isModuleInfo = toplevel.sourcefile.isNameCompatible("module-info", Kind.SOURCE); 289 boolean isModuleDecl = toplevel.defs.nonEmpty() && toplevel.defs.head.hasTag(MODULEDEF); 290 if (isModuleInfo && isModuleDecl) { 291 JCModuleDecl decl = (JCModuleDecl) toplevel.defs.head; 292 Name name = TreeInfo.fullName(decl.qualId); 293 ModuleSymbol sym; 294 if (c != null) { 295 sym = (ModuleSymbol) c.owner; 296 if (sym.name == null) { 297 //ModuleFinder.findSingleModule creates a stub of a ModuleSymbol without a name, 298 //fill the name here after the module-info.java has been parsed 299 //also enter the ModuleSymbol among modules: 300 syms.enterModule(sym, name); 301 } else { 302 // TODO: validate name 303 } 304 } else { 305 sym = syms.enterModule(name); 306 if (sym.module_info.sourcefile != null && sym.module_info.sourcefile != toplevel.sourcefile) { 307 log.error(decl.pos(), Errors.DuplicateModule(sym)); 308 return; 309 } 310 } 311 sym.completer = getSourceCompleter(toplevel); 312 sym.module_info.sourcefile = toplevel.sourcefile; 313 decl.sym = sym; 314 315 if (multiModuleMode || modules.isEmpty()) { 316 modules.add(sym); 317 } else { 318 log.error(toplevel.pos(), Errors.TooManyModules); 319 } 320 321 Env<AttrContext> provisionalEnv = new Env<>(decl, null); 322 323 provisionalEnv.toplevel = toplevel; 324 typeEnvs.put(sym, provisionalEnv); 325 } else if (isModuleInfo) { 326 if (multiModuleMode) { 327 JCTree tree = toplevel.defs.isEmpty() ? toplevel : toplevel.defs.head; 328 log.error(tree.pos(), Errors.ExpectedModule); 329 } 330 } else if (isModuleDecl) { 331 JCTree tree = toplevel.defs.head; 332 log.error(tree.pos(), Errors.ModuleDeclSbInModuleInfoJava); 333 } 334 } 335 336 private void setCompilationUnitModules(List<JCCompilationUnit> trees, Set<ModuleSymbol> rootModules) { 337 // update the module for each compilation unit 338 if (multiModuleMode) { 339 checkNoAllModulePath(); 340 for (JCCompilationUnit tree: trees) { 341 if (tree.defs.isEmpty()) { 342 tree.modle = syms.unnamedModule; 343 continue; 344 } 345 346 JavaFileObject prev = log.useSource(tree.sourcefile); 347 try { 348 Location locn = getModuleLocation(tree); 349 if (locn != null) { 350 Name name = names.fromString(fileManager.inferModuleName(locn)); 351 ModuleSymbol msym; 352 if (tree.defs.head.hasTag(MODULEDEF)) { 353 JCModuleDecl decl = (JCModuleDecl) tree.defs.head; 354 msym = decl.sym; 355 if (msym.name != name) { 356 log.error(decl.qualId, Errors.ModuleNameMismatch(msym.name, name)); 357 } 358 } else { 359 msym = syms.enterModule(name); 360 } 361 if (msym.sourceLocation == null) { 362 msym.sourceLocation = locn; 363 if (fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) { 364 msym.classLocation = fileManager.getModuleLocation( 365 StandardLocation.CLASS_OUTPUT, msym.name.toString()); 366 } 367 } 368 tree.modle = msym; 369 rootModules.add(msym); 370 } else { 371 log.error(tree.pos(), Errors.UnnamedPkgNotAllowedNamedModules); 372 tree.modle = syms.errModule; 373 } 374 } catch (IOException e) { 375 throw new Error(e); // FIXME 376 } finally { 377 log.useSource(prev); 378 } 379 } 380 if (syms.unnamedModule.sourceLocation == null) { 381 syms.unnamedModule.completer = getUnnamedModuleCompleter(); 382 syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH; 383 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH; 384 } 385 defaultModule = syms.unnamedModule; 386 } else { 387 if (defaultModule == null) { 388 switch (rootModules.size()) { 389 case 0: 390 defaultModule = moduleFinder.findSingleModule(); 391 if (defaultModule == syms.unnamedModule) { 392 if (moduleOverride != null) { 393 checkNoAllModulePath(); 394 defaultModule = moduleFinder.findModule(names.fromString(moduleOverride)); 395 } else { 396 // Question: why not do findAllModules and initVisiblePackages here? 397 // i.e. body of unnamedModuleCompleter 398 defaultModule.completer = getUnnamedModuleCompleter(); 399 defaultModule.classLocation = StandardLocation.CLASS_PATH; 400 } 401 } else { 402 checkSpecifiedModule(trees, Errors.ModuleInfoWithXmoduleClasspath); 403 checkNoAllModulePath(); 404 defaultModule.complete(); 405 // Question: why not do completeModule here? 406 defaultModule.completer = new Completer() { 407 @Override 408 public void complete(Symbol sym) throws CompletionFailure { 409 completeModule((ModuleSymbol) sym); 410 } 411 }; 412 } 413 rootModules.add(defaultModule); 414 break; 415 case 1: 416 checkSpecifiedModule(trees, Errors.ModuleInfoWithXmoduleSourcepath); 417 checkNoAllModulePath(); 418 defaultModule = rootModules.iterator().next(); 419 defaultModule.classLocation = StandardLocation.CLASS_OUTPUT; 420 break; 421 default: 422 Assert.error("too many modules"); 423 } 424 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 425 } else if (rootModules.size() == 1 && defaultModule == rootModules.iterator().next()) { 426 defaultModule.complete(); 427 defaultModule.completer = sym -> completeModule((ModuleSymbol) sym); 428 } else { 429 Assert.check(rootModules.isEmpty()); 430 rootModules.add(defaultModule); 431 } 432 433 if (defaultModule != syms.unnamedModule) { 434 syms.unnamedModule.completer = getUnnamedModuleCompleter(); 435 syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH; 436 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH; 437 } 438 439 for (JCCompilationUnit tree: trees) { 440 tree.modle = defaultModule; 441 } 442 } 443 } 444 445 private Location getModuleLocation(JCCompilationUnit tree) throws IOException { 446 switch (tree.defs.head.getTag()) { 447 case MODULEDEF: 448 return getModuleLocation(tree.sourcefile, null); 449 450 case PACKAGEDEF: 451 JCPackageDecl pkg = (JCPackageDecl) tree.defs.head; 452 return getModuleLocation(tree.sourcefile, TreeInfo.fullName(pkg.pid)); 453 454 default: 455 // code in unnamed module 456 return null; 457 } 458 } 459 460 private Location getModuleLocation(JavaFileObject fo, Name pkgName) throws IOException { 461 // For now, just check module source path. 462 // We may want to check source path as well. 463 return fileManager.getModuleLocation(StandardLocation.MODULE_SOURCE_PATH, 464 fo, (pkgName == null) ? null : pkgName.toString()); 465 } 466 467 private void checkSpecifiedModule(List<JCCompilationUnit> trees, JCDiagnostic.Error error) { 468 if (moduleOverride != null) { 469 JavaFileObject prev = log.useSource(trees.head.sourcefile); 470 try { 471 log.error(trees.head.pos(), error); 472 } finally { 473 log.useSource(prev); 474 } 475 } 476 } 477 478 private void checkNoAllModulePath() { 479 if (addModsOpt != null && Arrays.asList(addModsOpt.split(",")).contains(ALL_MODULE_PATH)) { 480 log.error(Errors.AddmodsAllModulePathInvalid); 481 } 482 } 483 484 private final Completer mainCompleter = new Completer() { 485 @Override 486 public void complete(Symbol sym) throws CompletionFailure { 487 ModuleSymbol msym = moduleFinder.findModule((ModuleSymbol) sym); 488 489 if (msym.kind == Kinds.Kind.ERR) { 490 log.error(Errors.CantFindModule(msym)); 491 //make sure the module is initialized: 492 msym.directives = List.nil(); 493 msym.exports = List.nil(); 494 msym.provides = List.nil(); 495 msym.requires = List.nil(); 496 msym.uses = List.nil(); 497 } else if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 498 setupAutomaticModule(msym); 499 } else { 500 msym.module_info.complete(); 501 } 502 503 // If module-info comes from a .java file, the underlying 504 // call of classFinder.fillIn will have called through the 505 // source completer, to Enter, and then to Modules.enter, 506 // which will call completeModule. 507 // But, if module-info comes from a .class file, the underlying 508 // call of classFinder.fillIn will just call ClassReader to read 509 // the .class file, and so we call completeModule here. 510 if (msym.module_info.classfile == null || msym.module_info.classfile.getKind() == Kind.CLASS) { 511 completeModule(msym); 512 } 513 } 514 515 @Override 516 public String toString() { 517 return "mainCompleter"; 518 } 519 }; 520 521 private void setupAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 522 try { 523 ListBuffer<Directive> directives = new ListBuffer<>(); 524 ListBuffer<ExportsDirective> exports = new ListBuffer<>(); 525 Set<String> seenPackages = new HashSet<>(); 526 527 for (JavaFileObject clazz : fileManager.list(msym.classLocation, "", EnumSet.of(Kind.CLASS), true)) { 528 String binName = fileManager.inferBinaryName(msym.classLocation, clazz); 529 String pack = binName.lastIndexOf('.') != (-1) ? binName.substring(0, binName.lastIndexOf('.')) : ""; //unnamed package???? 530 if (seenPackages.add(pack)) { 531 ExportsDirective d = new ExportsDirective(syms.enterPackage(msym, names.fromString(pack)), null); 532 directives.add(d); 533 exports.add(d); 534 } 535 } 536 537 msym.exports = exports.toList(); 538 msym.provides = List.nil(); 539 msym.requires = List.nil(); 540 msym.uses = List.nil(); 541 msym.directives = directives.toList(); 542 msym.flags_field |= Flags.ACYCLIC; 543 } catch (IOException ex) { 544 throw new IllegalStateException(ex); 545 } 546 } 547 548 private void completeAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 549 ListBuffer<Directive> directives = new ListBuffer<>(); 550 551 directives.addAll(msym.directives); 552 553 ListBuffer<RequiresDirective> requires = new ListBuffer<>(); 554 555 for (ModuleSymbol ms : allModules()) { 556 if (ms == syms.unnamedModule || ms == msym) 557 continue; 558 Set<RequiresFlag> flags = (ms.flags_field & Flags.AUTOMATIC_MODULE) != 0 ? 559 EnumSet.of(RequiresFlag.PUBLIC) : EnumSet.noneOf(RequiresFlag.class); 560 RequiresDirective d = new RequiresDirective(ms, flags); 561 directives.add(d); 562 requires.add(d); 563 } 564 565 RequiresDirective requiresUnnamed = new RequiresDirective(syms.unnamedModule); 566 directives.add(requiresUnnamed); 567 requires.add(requiresUnnamed); 568 569 msym.requires = requires.toList(); 570 msym.directives = directives.toList(); 571 } 572 573 private Completer getSourceCompleter(JCCompilationUnit tree) { 574 return new Completer() { 575 @Override 576 public void complete(Symbol sym) throws CompletionFailure { 577 ModuleSymbol msym = (ModuleSymbol) sym; 578 msym.flags_field |= UNATTRIBUTED; 579 ModuleVisitor v = new ModuleVisitor(); 580 JavaFileObject prev = log.useSource(tree.sourcefile); 581 try { 582 tree.defs.head.accept(v); 583 checkCyclicDependencies((JCModuleDecl) tree.defs.head); 584 completeModule(msym); 585 } finally { 586 log.useSource(prev); 587 msym.flags_field &= ~UNATTRIBUTED; 588 } 589 } 590 591 @Override 592 public String toString() { 593 return "SourceCompleter: " + tree.sourcefile.getName(); 594 } 595 596 }; 597 } 598 599 class ModuleVisitor extends JCTree.Visitor { 600 private ModuleSymbol sym; 601 private final Set<ModuleSymbol> allRequires = new HashSet<>(); 602 private final Set<PackageSymbol> allExports = new HashSet<>(); 603 604 @Override 605 public void visitModuleDef(JCModuleDecl tree) { 606 sym = Assert.checkNonNull(tree.sym); 607 608 sym.requires = List.nil(); 609 sym.exports = List.nil(); 610 tree.directives.forEach(t -> t.accept(this)); 611 sym.requires = sym.requires.reverse(); 612 sym.exports = sym.exports.reverse(); 613 ensureJavaBase(); 614 } 615 616 @Override 617 public void visitRequires(JCRequires tree) { 618 ModuleSymbol msym = lookupModule(tree.moduleName); 619 if (msym.kind != MDL) { 620 log.error(tree.moduleName.pos(), Errors.ModuleNotFound(msym)); 621 } else if (allRequires.contains(msym)) { 622 log.error(tree.moduleName.pos(), Errors.DuplicateRequires(msym)); 623 } else { 624 allRequires.add(msym); 625 Set<RequiresFlag> flags = EnumSet.noneOf(RequiresFlag.class); 626 if (tree.isPublic) 627 flags.add(RequiresFlag.PUBLIC); 628 RequiresDirective d = new RequiresDirective(msym, flags); 629 tree.directive = d; 630 sym.requires = sym.requires.prepend(d); 631 } 632 } 633 634 @Override 635 public void visitExports(JCExports tree) { 636 Name name = TreeInfo.fullName(tree.qualid); 637 PackageSymbol packge = syms.enterPackage(sym, name); 638 attr.setPackageSymbols(tree.qualid, packge); 639 if (!allExports.add(packge)) { 640 log.error(tree.qualid.pos(), Errors.DuplicateExports(packge)); 641 } 642 643 List<ModuleSymbol> toModules = null; 644 if (tree.moduleNames != null) { 645 Set<ModuleSymbol> to = new HashSet<>(); 646 for (JCExpression n: tree.moduleNames) { 647 ModuleSymbol msym = lookupModule(n); 648 if (msym.kind != MDL) { 649 log.error(n.pos(), Errors.ModuleNotFound(msym)); 650 } else if (!to.add(msym)) { 651 log.error(n.pos(), Errors.DuplicateExports(msym)); 652 } 653 } 654 toModules = List.from(to); 655 } 656 657 if (toModules == null || !toModules.isEmpty()) { 658 ExportsDirective d = new ExportsDirective(packge, toModules); 659 tree.directive = d; 660 sym.exports = sym.exports.prepend(d); 661 } 662 } 663 664 @Override 665 public void visitProvides(JCProvides tree) { } 666 667 @Override 668 public void visitUses(JCUses tree) { } 669 670 private void ensureJavaBase() { 671 if (sym.name == names.java_base) 672 return; 673 674 for (RequiresDirective d: sym.requires) { 675 if (d.module.name == names.java_base) 676 return; 677 } 678 679 ModuleSymbol java_base = syms.enterModule(names.java_base); 680 Directive.RequiresDirective d = 681 new Directive.RequiresDirective(java_base, 682 EnumSet.of(Directive.RequiresFlag.MANDATED)); 683 sym.requires = sym.requires.prepend(d); 684 } 685 686 private ModuleSymbol lookupModule(JCExpression moduleName) { 687 try { 688 Name name = TreeInfo.fullName(moduleName); 689 ModuleSymbol msym = moduleFinder.findModule(name); 690 TreeInfo.setSymbol(moduleName, msym); 691 return msym; 692 } catch (Throwable t) { 693 System.err.println("Module " + sym + "; lookup export " + moduleName); 694 throw t; 695 } 696 } 697 } 698 699 public Completer getUsesProvidesCompleter() { 700 return sym -> { 701 ModuleSymbol msym = (ModuleSymbol) sym; 702 703 msym.complete(); 704 705 Env<AttrContext> env = typeEnvs.get(msym); 706 UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env); 707 JavaFileObject prev = log.useSource(env.toplevel.sourcefile); 708 try { 709 env.toplevel.defs.head.accept(v); 710 } finally { 711 log.useSource(prev); 712 } 713 }; 714 } 715 716 class UsesProvidesVisitor extends JCTree.Visitor { 717 private final ModuleSymbol msym; 718 private final Env<AttrContext> env; 719 720 private final Set<Directive.UsesDirective> allUses = new HashSet<>(); 721 private final Set<Directive.ProvidesDirective> allProvides = new HashSet<>(); 722 723 public UsesProvidesVisitor(ModuleSymbol msym, Env<AttrContext> env) { 724 this.msym = msym; 725 this.env = env; 726 } 727 728 @Override @SuppressWarnings("unchecked") 729 public void visitModuleDef(JCModuleDecl tree) { 730 msym.directives = List.nil(); 731 msym.provides = List.nil(); 732 msym.uses = List.nil(); 733 tree.directives.forEach(t -> t.accept(this)); 734 msym.directives = msym.directives.reverse(); 735 msym.provides = msym.provides.reverse(); 736 msym.uses = msym.uses.reverse(); 737 738 if (msym.requires.nonEmpty() && msym.requires.head.flags.contains(RequiresFlag.MANDATED)) 739 msym.directives = msym.directives.prepend(msym.requires.head); 740 741 msym.directives = msym.directives.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 742 743 checkForCorrectness(); 744 } 745 746 @Override 747 public void visitExports(JCExports tree) { 748 if (tree.directive.packge.members().isEmpty()) { 749 log.error(tree.qualid.pos(), Errors.PackageEmptyOrNotFound(tree.directive.packge)); 750 } 751 msym.directives = msym.directives.prepend(tree.directive); 752 } 753 754 MethodSymbol noArgsConstructor(ClassSymbol tsym) { 755 for (Symbol sym : tsym.members().getSymbolsByName(names.init)) { 756 MethodSymbol mSym = (MethodSymbol)sym; 757 if (mSym.params().isEmpty()) { 758 return mSym; 759 } 760 } 761 return null; 762 } 763 764 Map<Directive.ProvidesDirective, JCProvides> directiveToTreeMap = new HashMap<>(); 765 766 @Override 767 public void visitProvides(JCProvides tree) { 768 Type st = attr.attribType(tree.serviceName, env, syms.objectType); 769 Type it = attr.attribType(tree.implName, env, syms.objectType); 770 ClassSymbol service = (ClassSymbol) st.tsym; 771 ClassSymbol impl = (ClassSymbol) it.tsym; 772 if (!types.isSubtype(it, st)) { 773 log.error(tree.implName.pos(), Errors.ServiceImplementationMustBeSubtypeOfServiceInterface); 774 } 775 if ((impl.flags() & ABSTRACT) != 0) { 776 log.error(tree.implName.pos(), Errors.ServiceImplementationIsAbstract(impl)); 777 } else if (impl.isInner()) { 778 log.error(tree.implName.pos(), Errors.ServiceImplementationIsInner(impl)); 779 } else if (service.isInner()) { 780 log.error(tree.serviceName.pos(), Errors.ServiceDefinitionIsInner(service)); 781 } else { 782 MethodSymbol constr = noArgsConstructor(impl); 783 if (constr == null) { 784 log.error(tree.implName.pos(), Errors.ServiceImplementationDoesntHaveANoArgsConstructor(impl)); 785 } else if ((constr.flags() & PUBLIC) == 0) { 786 log.error(tree.implName.pos(), Errors.ServiceImplementationNoArgsConstructorNotPublic(impl)); 787 } 788 } 789 if (st.hasTag(CLASS) && it.hasTag(CLASS)) { 790 Directive.ProvidesDirective d = new Directive.ProvidesDirective(service, impl); 791 if (!allProvides.add(d)) { 792 log.error(tree.pos(), Errors.DuplicateProvides(service, impl)); 793 } 794 msym.provides = msym.provides.prepend(d); 795 msym.directives = msym.directives.prepend(d); 796 directiveToTreeMap.put(d, tree); 797 } 798 } 799 800 @Override 801 public void visitRequires(JCRequires tree) { 802 if (tree.directive != null) { 803 msym.directives = msym.directives.prepend(tree.directive); 804 } 805 } 806 807 @Override 808 public void visitUses(JCUses tree) { 809 Type st = attr.attribType(tree.qualid, env, syms.objectType); 810 Symbol sym = TreeInfo.symbol(tree.qualid); 811 if ((sym.flags() & ENUM) != 0) { 812 log.error(tree.qualid.pos(), Errors.ServiceDefinitionIsEnum(st.tsym)); 813 } else if (st.hasTag(CLASS)) { 814 ClassSymbol service = (ClassSymbol) st.tsym; 815 Directive.UsesDirective d = new Directive.UsesDirective(service); 816 if (!allUses.add(d)) { 817 log.error(tree.pos(), Errors.DuplicateUses(service)); 818 } 819 msym.uses = msym.uses.prepend(d); 820 msym.directives = msym.directives.prepend(d); 821 } 822 } 823 824 private void checkForCorrectness() { 825 for (Directive.ProvidesDirective provides : allProvides) { 826 JCProvides tree = directiveToTreeMap.get(provides); 827 /* The implementation must be defined in the same module as the provides directive 828 * (else, error) 829 */ 830 PackageSymbol implementationDefiningPackage = provides.impl.packge(); 831 if (implementationDefiningPackage.modle != msym) { 832 log.error(tree.pos(), Errors.ServiceImplementationNotInRightModule(implementationDefiningPackage.modle)); 833 } 834 835 /* There is no inherent requirement that module that provides a service should actually 836 * use it itself. However, it is a pointless declaration if the service package is not 837 * exported and there is no uses for the service. 838 */ 839 PackageSymbol interfaceDeclaringPackage = provides.service.packge(); 840 boolean isInterfaceDeclaredInCurrentModule = interfaceDeclaringPackage.modle == msym; 841 boolean isInterfaceExportedFromAReadableModule = 842 msym.visiblePackages.get(interfaceDeclaringPackage.fullname) == interfaceDeclaringPackage; 843 if (isInterfaceDeclaredInCurrentModule && !isInterfaceExportedFromAReadableModule) { 844 // ok the interface is declared in this module. Let's check if it's exported 845 boolean warn = true; 846 for (ExportsDirective export : msym.exports) { 847 if (interfaceDeclaringPackage == export.packge) { 848 warn = false; 849 break; 850 } 851 } 852 if (warn) { 853 for (UsesDirective uses : msym.uses) { 854 if (provides.service == uses.service) { 855 warn = false; 856 break; 857 } 858 } 859 } 860 if (warn) { 861 log.warning(tree.pos(), Warnings.ServiceProvidedButNotExportedOrUsed(provides.service)); 862 } 863 } 864 } 865 } 866 } 867 868 private Set<ModuleSymbol> allModules; 869 870 public Set<ModuleSymbol> allModules() { 871 Assert.checkNonNull(allModules); 872 return allModules; 873 } 874 875 private void setupAllModules() { 876 Assert.checkNonNull(rootModules); 877 Assert.checkNull(allModules); 878 879 Set<ModuleSymbol> observable; 880 881 if (limitModsOpt == null && extraLimitMods.isEmpty()) { 882 observable = null; 883 } else { 884 Set<ModuleSymbol> limitMods = new HashSet<>(); 885 if (limitModsOpt != null) { 886 for (String limit : limitModsOpt.split(",")) { 887 limitMods.add(syms.enterModule(names.fromString(limit))); 888 } 889 } 890 for (String limit : extraLimitMods) { 891 limitMods.add(syms.enterModule(names.fromString(limit))); 892 } 893 observable = computeTransitiveClosure(limitMods, null); 894 observable.addAll(rootModules); 895 } 896 897 Predicate<ModuleSymbol> observablePred = sym -> observable == null || observable.contains(sym); 898 Predicate<ModuleSymbol> systemModulePred = sym -> (sym.flags() & Flags.SYSTEM_MODULE) != 0; 899 Set<ModuleSymbol> enabledRoot = new LinkedHashSet<>(); 900 901 if (rootModules.contains(syms.unnamedModule)) { 902 ModuleSymbol javaSE = syms.getModule(java_se); 903 Predicate<ModuleSymbol> jdkModulePred; 904 905 if (javaSE != null && (observable == null || observable.contains(javaSE))) { 906 jdkModulePred = sym -> { 907 sym.complete(); 908 return !sym.name.startsWith(java_) 909 && sym.exports.stream().anyMatch(e -> e.modules == null); 910 }; 911 enabledRoot.add(javaSE); 912 } else { 913 jdkModulePred = sym -> true; 914 } 915 916 for (ModuleSymbol sym : new HashSet<>(syms.getAllModules())) { 917 if (systemModulePred.test(sym) && observablePred.test(sym) && jdkModulePred.test(sym)) { 918 enabledRoot.add(sym); 919 } 920 } 921 } 922 923 enabledRoot.addAll(rootModules); 924 925 if (addModsOpt != null || !extraAddMods.isEmpty()) { 926 Set<String> fullAddMods = new HashSet<>(); 927 fullAddMods.addAll(extraAddMods); 928 929 if (addModsOpt != null) { 930 fullAddMods.addAll(Arrays.asList(addModsOpt.split(","))); 931 } 932 933 for (String added : fullAddMods) { 934 Stream<ModuleSymbol> modules; 935 switch (added) { 936 case ALL_SYSTEM: 937 modules = syms.getAllModules() 938 .stream() 939 .filter(systemModulePred.and(observablePred)); 940 break; 941 case ALL_MODULE_PATH: 942 modules = syms.getAllModules() 943 .stream() 944 .filter(systemModulePred.negate().and(observablePred)); 945 break; 946 default: 947 modules = Stream.of(syms.enterModule(names.fromString(added))); 948 break; 949 } 950 modules.forEach(sym -> { 951 enabledRoot.add(sym); 952 if (observable != null) 953 observable.add(sym); 954 }); 955 } 956 } 957 958 Set<ModuleSymbol> result = computeTransitiveClosure(enabledRoot, observable); 959 960 result.add(syms.unnamedModule); 961 962 allModules = result; 963 } 964 965 private Set<ModuleSymbol> computeTransitiveClosure(Iterable<? extends ModuleSymbol> base, Set<ModuleSymbol> observable) { 966 List<ModuleSymbol> todo = List.nil(); 967 968 for (ModuleSymbol ms : base) { 969 todo = todo.prepend(ms); 970 } 971 972 Set<ModuleSymbol> result = new LinkedHashSet<>(); 973 result.add(syms.java_base); 974 975 while (todo.nonEmpty()) { 976 ModuleSymbol current = todo.head; 977 todo = todo.tail; 978 if (observable != null && !observable.contains(current)) 979 continue; 980 if (!result.add(current) || current == syms.unnamedModule || ((current.flags_field & Flags.AUTOMATIC_MODULE) != 0)) 981 continue; 982 current.complete(); 983 for (RequiresDirective rd : current.requires) { 984 todo = todo.prepend(rd.module); 985 } 986 } 987 988 return result; 989 } 990 991 public ModuleSymbol getObservableModule(Name name) { 992 ModuleSymbol mod = syms.getModule(name); 993 994 if (allModules().contains(mod)) { 995 return mod; 996 } 997 998 return null; 999 } 1000 1001 private Completer getUnnamedModuleCompleter() { 1002 moduleFinder.findAllModules(); 1003 return new Symbol.Completer() { 1004 @Override 1005 public void complete(Symbol sym) throws CompletionFailure { 1006 ModuleSymbol msym = (ModuleSymbol) sym; 1007 Set<ModuleSymbol> allModules = allModules(); 1008 for (ModuleSymbol m : allModules) { 1009 m.complete(); 1010 } 1011 initVisiblePackages(msym, allModules); 1012 } 1013 1014 @Override 1015 public String toString() { 1016 return "unnamedModule Completer"; 1017 } 1018 }; 1019 } 1020 1021 private final Map<ModuleSymbol, Set<ModuleSymbol>> requiresPublicCache = new HashMap<>(); 1022 1023 private void completeModule(ModuleSymbol msym) { 1024 if (inInitModules) { 1025 msym.completer = sym -> completeModule(msym); 1026 return ; 1027 } 1028 1029 if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 1030 completeAutomaticModule(msym); 1031 } 1032 1033 Assert.checkNonNull(msym.requires); 1034 1035 initAddReads(); 1036 1037 msym.requires = msym.requires.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 1038 1039 List<RequiresDirective> requires = msym.requires; 1040 List<RequiresDirective> previous = null; 1041 1042 while (requires.nonEmpty()) { 1043 if (!allModules().contains(requires.head.module)) { 1044 Env<AttrContext> env = typeEnvs.get(msym); 1045 if (env != null) { 1046 JavaFileObject origSource = log.useSource(env.toplevel.sourcefile); 1047 try { 1048 log.error(/*XXX*/env.tree, Errors.ModuleNotFound(requires.head.module)); 1049 } finally { 1050 log.useSource(origSource); 1051 } 1052 } else { 1053 Assert.check((msym.flags() & Flags.AUTOMATIC_MODULE) == 0); 1054 } 1055 if (previous != null) { 1056 previous.tail = requires.tail; 1057 } else { 1058 msym.requires.tail = requires.tail; 1059 } 1060 } else { 1061 previous = requires; 1062 } 1063 requires = requires.tail; 1064 } 1065 1066 Set<ModuleSymbol> readable = new LinkedHashSet<>(); 1067 Set<ModuleSymbol> requiresPublic = new HashSet<>(); 1068 1069 for (RequiresDirective d : msym.requires) { 1070 d.module.complete(); 1071 readable.add(d.module); 1072 Set<ModuleSymbol> s = retrieveRequiresPublic(d.module); 1073 Assert.checkNonNull(s, () -> "no entry in cache for " + d.module); 1074 readable.addAll(s); 1075 if (d.flags.contains(RequiresFlag.PUBLIC)) { 1076 requiresPublic.add(d.module); 1077 requiresPublic.addAll(s); 1078 } 1079 } 1080 1081 requiresPublicCache.put(msym, requiresPublic); 1082 initVisiblePackages(msym, readable); 1083 for (ExportsDirective d: msym.exports) { 1084 d.packge.modle = msym; 1085 } 1086 1087 } 1088 1089 private Set<ModuleSymbol> retrieveRequiresPublic(ModuleSymbol msym) { 1090 Set<ModuleSymbol> requiresPublic = requiresPublicCache.get(msym); 1091 1092 if (requiresPublic == null) { 1093 //the module graph may contain cycles involving automatic modules or --add-reads edges 1094 requiresPublic = new HashSet<>(); 1095 1096 Set<ModuleSymbol> seen = new HashSet<>(); 1097 List<ModuleSymbol> todo = List.of(msym); 1098 1099 while (todo.nonEmpty()) { 1100 ModuleSymbol current = todo.head; 1101 todo = todo.tail; 1102 if (!seen.add(current)) 1103 continue; 1104 requiresPublic.add(current); 1105 current.complete(); 1106 Iterable<? extends RequiresDirective> requires; 1107 if (current != syms.unnamedModule) { 1108 Assert.checkNonNull(current.requires, () -> current + ".requires == null; " + msym); 1109 requires = current.requires; 1110 for (RequiresDirective rd : requires) { 1111 if (rd.isPublic()) 1112 todo = todo.prepend(rd.module); 1113 } 1114 } else { 1115 for (ModuleSymbol mod : allModules()) { 1116 todo = todo.prepend(mod); 1117 } 1118 } 1119 } 1120 1121 requiresPublic.remove(msym); 1122 } 1123 1124 return requiresPublic; 1125 } 1126 1127 private void initVisiblePackages(ModuleSymbol msym, Collection<ModuleSymbol> readable) { 1128 initAddExports(); 1129 1130 msym.visiblePackages = new LinkedHashMap<>(); 1131 1132 Map<Name, ModuleSymbol> seen = new HashMap<>(); 1133 1134 for (ModuleSymbol rm : readable) { 1135 if (rm == syms.unnamedModule) 1136 continue; 1137 addVisiblePackages(msym, seen, rm, rm.exports); 1138 } 1139 1140 for (Entry<ModuleSymbol, Set<ExportsDirective>> addExportsEntry : addExports.entrySet()) 1141 addVisiblePackages(msym, seen, addExportsEntry.getKey(), addExportsEntry.getValue()); 1142 } 1143 1144 private void addVisiblePackages(ModuleSymbol msym, 1145 Map<Name, ModuleSymbol> seenPackages, 1146 ModuleSymbol exportsFrom, 1147 Collection<ExportsDirective> exports) { 1148 for (ExportsDirective d : exports) { 1149 if (d.modules == null || d.modules.contains(msym)) { 1150 Name packageName = d.packge.fullname; 1151 ModuleSymbol previousModule = seenPackages.get(packageName); 1152 1153 if (previousModule != null && previousModule != exportsFrom) { 1154 Env<AttrContext> env = typeEnvs.get(msym); 1155 JavaFileObject origSource = env != null ? log.useSource(env.toplevel.sourcefile) 1156 : null; 1157 DiagnosticPosition pos = env != null ? env.tree.pos() : null; 1158 try { 1159 log.error(pos, Errors.PackageClashFromRequires(msym, packageName, 1160 previousModule, exportsFrom)); 1161 } finally { 1162 if (env != null) 1163 log.useSource(origSource); 1164 } 1165 continue; 1166 } 1167 1168 seenPackages.put(packageName, exportsFrom); 1169 msym.visiblePackages.put(d.packge.fullname, d.packge); 1170 } 1171 } 1172 } 1173 1174 private void initAddExports() { 1175 if (addExports != null) 1176 return; 1177 1178 addExports = new LinkedHashMap<>(); 1179 1180 if (addExportsOpt == null) 1181 return; 1182 1183 // System.err.println("Modules.addExports:\n " + addExportsOpt.replace("\0", "\n ")); 1184 1185 Pattern ep = Pattern.compile("([^/]+)/([^=]+)=(.*)"); 1186 for (String s: addExportsOpt.split("\0+")) { 1187 if (s.isEmpty()) 1188 continue; 1189 Matcher em = ep.matcher(s); 1190 if (!em.matches()) { 1191 continue; 1192 } 1193 1194 // Terminology comes from 1195 // --add-exports module/package=target,... 1196 // Compare to 1197 // module module { exports package to target, ... } 1198 String moduleName = em.group(1); 1199 String packageName = em.group(2); 1200 String targetNames = em.group(3); 1201 1202 ModuleSymbol msym = syms.enterModule(names.fromString(moduleName)); 1203 PackageSymbol p = syms.enterPackage(msym, names.fromString(packageName)); 1204 p.modle = msym; // TODO: do we need this? 1205 1206 List<ModuleSymbol> targetModules = List.nil(); 1207 for (String toModule : targetNames.split("[ ,]+")) { 1208 ModuleSymbol m; 1209 if (toModule.equals("ALL-UNNAMED")) { 1210 m = syms.unnamedModule; 1211 } else { 1212 if (!SourceVersion.isName(toModule)) { 1213 // TODO: error: invalid module name 1214 continue; 1215 } 1216 m = syms.enterModule(names.fromString(toModule)); 1217 } 1218 targetModules = targetModules.prepend(m); 1219 } 1220 1221 Set<ExportsDirective> extra = addExports.computeIfAbsent(msym, _x -> new LinkedHashSet<>()); 1222 ExportsDirective d = new ExportsDirective(p, targetModules); 1223 extra.add(d); 1224 } 1225 } 1226 1227 private void initAddReads() { 1228 if (addReads != null) 1229 return; 1230 1231 addReads = new LinkedHashMap<>(); 1232 1233 if (addReadsOpt == null) 1234 return; 1235 1236 // System.err.println("Modules.addReads:\n " + addReadsOpt.replace("\0", "\n ")); 1237 1238 Pattern rp = Pattern.compile("([^=]+)=(.*)"); 1239 for (String s : addReadsOpt.split("\0+")) { 1240 if (s.isEmpty()) 1241 continue; 1242 Matcher rm = rp.matcher(s); 1243 if (!rm.matches()) { 1244 continue; 1245 } 1246 1247 // Terminology comes from 1248 // --add-reads target-module=source-module,... 1249 // Compare to 1250 // module target-module { requires source-module; ... } 1251 String targetName = rm.group(1); 1252 String sources = rm.group(2); 1253 1254 ModuleSymbol msym = syms.enterModule(names.fromString(targetName)); 1255 for (String source : sources.split("[ ,]+")) { 1256 ModuleSymbol sourceModule; 1257 if (source.equals("ALL-UNNAMED")) { 1258 sourceModule = syms.unnamedModule; 1259 } else { 1260 if (!SourceVersion.isName(source)) { 1261 // TODO: error: invalid module name 1262 continue; 1263 } 1264 sourceModule = syms.enterModule(names.fromString(source)); 1265 } 1266 addReads.computeIfAbsent(msym, m -> new HashSet<>()) 1267 .add(new RequiresDirective(sourceModule, EnumSet.of(RequiresFlag.EXTRA))); 1268 } 1269 } 1270 } 1271 1272 private void checkCyclicDependencies(JCModuleDecl mod) { 1273 for (JCDirective d : mod.directives) { 1274 JCRequires rd; 1275 if (!d.hasTag(Tag.REQUIRES) || (rd = (JCRequires) d).directive == null) 1276 continue; 1277 Set<ModuleSymbol> nonSyntheticDeps = new HashSet<>(); 1278 List<ModuleSymbol> queue = List.of(rd.directive.module); 1279 while (queue.nonEmpty()) { 1280 ModuleSymbol current = queue.head; 1281 queue = queue.tail; 1282 if (!nonSyntheticDeps.add(current)) 1283 continue; 1284 current.complete(); 1285 if ((current.flags() & Flags.ACYCLIC) != 0) 1286 continue; 1287 Assert.checkNonNull(current.requires, () -> current.toString()); 1288 for (RequiresDirective dep : current.requires) { 1289 if (!dep.flags.contains(RequiresFlag.EXTRA)) 1290 queue = queue.prepend(dep.module); 1291 } 1292 } 1293 if (nonSyntheticDeps.contains(mod.sym)) { 1294 log.error(rd.moduleName.pos(), Errors.CyclicRequires(rd.directive.module)); 1295 } 1296 mod.sym.flags_field |= Flags.ACYCLIC; 1297 } 1298 } 1299 1300 // DEBUG 1301 private String toString(ModuleSymbol msym) { 1302 return msym.name + "[" 1303 + "kind:" + msym.kind + ";" 1304 + "locn:" + toString(msym.sourceLocation) + "," + toString(msym.classLocation) + ";" 1305 + "info:" + toString(msym.module_info.sourcefile) + "," 1306 + toString(msym.module_info.classfile) + "," 1307 + msym.module_info.completer 1308 + "]"; 1309 } 1310 1311 // DEBUG 1312 String toString(Location locn) { 1313 return (locn == null) ? "--" : locn.getName(); 1314 } 1315 1316 // DEBUG 1317 String toString(JavaFileObject fo) { 1318 return (fo == null) ? "--" : fo.getName(); 1319 } 1320 1321 public void newRound() { 1322 rootModules = null; 1323 allModules = null; 1324 } 1325 }