Modules.java revision 3634:5a2d38a840cc
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 27package com.sun.tools.javac.comp; 28 29import java.io.IOException; 30import java.util.Arrays; 31import java.util.Collection; 32import java.util.Collections; 33import java.util.EnumSet; 34import java.util.HashMap; 35import java.util.HashSet; 36import java.util.LinkedHashMap; 37import java.util.LinkedHashSet; 38import java.util.Map; 39import java.util.Map.Entry; 40import java.util.Set; 41import java.util.function.Consumer; 42import java.util.function.Predicate; 43import java.util.regex.Matcher; 44import java.util.regex.Pattern; 45import java.util.stream.Stream; 46 47import javax.lang.model.SourceVersion; 48import javax.tools.JavaFileManager; 49import javax.tools.JavaFileManager.Location; 50import javax.tools.JavaFileObject; 51import javax.tools.JavaFileObject.Kind; 52import javax.tools.StandardLocation; 53 54import com.sun.tools.javac.code.ClassFinder; 55import com.sun.tools.javac.code.Directive; 56import com.sun.tools.javac.code.Directive.ExportsDirective; 57import com.sun.tools.javac.code.Directive.RequiresDirective; 58import com.sun.tools.javac.code.Directive.RequiresFlag; 59import com.sun.tools.javac.code.Directive.UsesDirective; 60import com.sun.tools.javac.code.Flags; 61import com.sun.tools.javac.code.Kinds; 62import com.sun.tools.javac.code.ModuleFinder; 63import com.sun.tools.javac.code.Source; 64import com.sun.tools.javac.code.Symbol; 65import com.sun.tools.javac.code.Symbol.ClassSymbol; 66import com.sun.tools.javac.code.Symbol.Completer; 67import com.sun.tools.javac.code.Symbol.CompletionFailure; 68import com.sun.tools.javac.code.Symbol.MethodSymbol; 69import com.sun.tools.javac.code.Symbol.ModuleSymbol; 70import com.sun.tools.javac.code.Symbol.PackageSymbol; 71import com.sun.tools.javac.code.Symtab; 72import com.sun.tools.javac.code.Type; 73import com.sun.tools.javac.code.Types; 74import com.sun.tools.javac.jvm.ClassWriter; 75import com.sun.tools.javac.jvm.JNIWriter; 76import com.sun.tools.javac.main.Option; 77import com.sun.tools.javac.resources.CompilerProperties.Errors; 78import com.sun.tools.javac.resources.CompilerProperties.Warnings; 79import com.sun.tools.javac.tree.JCTree; 80import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 81import com.sun.tools.javac.tree.JCTree.JCExports; 82import com.sun.tools.javac.tree.JCTree.JCExpression; 83import com.sun.tools.javac.tree.JCTree.JCModuleDecl; 84import com.sun.tools.javac.tree.JCTree.JCPackageDecl; 85import com.sun.tools.javac.tree.JCTree.JCProvides; 86import com.sun.tools.javac.tree.JCTree.JCRequires; 87import com.sun.tools.javac.tree.JCTree.JCUses; 88import com.sun.tools.javac.tree.TreeInfo; 89import com.sun.tools.javac.util.Assert; 90import com.sun.tools.javac.util.Context; 91import com.sun.tools.javac.util.JCDiagnostic; 92import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 93import com.sun.tools.javac.util.List; 94import com.sun.tools.javac.util.ListBuffer; 95import com.sun.tools.javac.util.Log; 96import com.sun.tools.javac.util.Name; 97import com.sun.tools.javac.util.Names; 98import com.sun.tools.javac.util.Options; 99 100import static com.sun.tools.javac.code.Flags.UNATTRIBUTED; 101import static com.sun.tools.javac.code.Kinds.Kind.MDL; 102import static com.sun.tools.javac.code.TypeTag.CLASS; 103 104import com.sun.tools.javac.tree.JCTree.JCDirective; 105import com.sun.tools.javac.tree.JCTree.Tag; 106import com.sun.tools.javac.util.Abort; 107import com.sun.tools.javac.util.Position; 108 109import static com.sun.tools.javac.code.Flags.ABSTRACT; 110import static com.sun.tools.javac.code.Flags.ENUM; 111import static com.sun.tools.javac.code.Flags.PUBLIC; 112import 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 */ 122public 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 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 396 } else { 397 // Question: why not do findAllModules and initVisiblePackages here? 398 // i.e. body of unnamedModuleCompleter 399 defaultModule.completer = getUnnamedModuleCompleter(); 400 defaultModule.classLocation = StandardLocation.CLASS_PATH; 401 } 402 } else { 403 checkSpecifiedModule(trees, Errors.ModuleInfoWithXmoduleClasspath); 404 checkNoAllModulePath(); 405 defaultModule.complete(); 406 // Question: why not do completeModule here? 407 defaultModule.completer = new Completer() { 408 @Override 409 public void complete(Symbol sym) throws CompletionFailure { 410 completeModule((ModuleSymbol) sym); 411 } 412 }; 413 } 414 rootModules.add(defaultModule); 415 break; 416 case 1: 417 checkSpecifiedModule(trees, Errors.ModuleInfoWithXmoduleSourcepath); 418 checkNoAllModulePath(); 419 defaultModule = rootModules.iterator().next(); 420 defaultModule.classLocation = StandardLocation.CLASS_OUTPUT; 421 break; 422 default: 423 Assert.error("too many modules"); 424 } 425 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 426 } else if (rootModules.size() == 1 && defaultModule == rootModules.iterator().next()) { 427 defaultModule.complete(); 428 defaultModule.completer = sym -> completeModule((ModuleSymbol) sym); 429 } else { 430 Assert.check(rootModules.isEmpty()); 431 rootModules.add(defaultModule); 432 } 433 434 if (defaultModule != syms.unnamedModule) { 435 syms.unnamedModule.completer = getUnnamedModuleCompleter(); 436 if (moduleOverride == null) { 437 syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH; 438 } 439 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH; 440 } 441 442 for (JCCompilationUnit tree: trees) { 443 tree.modle = defaultModule; 444 } 445 } 446 } 447 448 private Location getModuleLocation(JCCompilationUnit tree) throws IOException { 449 switch (tree.defs.head.getTag()) { 450 case MODULEDEF: 451 return getModuleLocation(tree.sourcefile, null); 452 453 case PACKAGEDEF: 454 JCPackageDecl pkg = (JCPackageDecl) tree.defs.head; 455 return getModuleLocation(tree.sourcefile, TreeInfo.fullName(pkg.pid)); 456 457 default: 458 // code in unnamed module 459 return null; 460 } 461 } 462 463 private Location getModuleLocation(JavaFileObject fo, Name pkgName) throws IOException { 464 // For now, just check module source path. 465 // We may want to check source path as well. 466 return fileManager.getModuleLocation(StandardLocation.MODULE_SOURCE_PATH, 467 fo, (pkgName == null) ? null : pkgName.toString()); 468 } 469 470 private void checkSpecifiedModule(List<JCCompilationUnit> trees, JCDiagnostic.Error error) { 471 if (moduleOverride != null) { 472 JavaFileObject prev = log.useSource(trees.head.sourcefile); 473 try { 474 log.error(trees.head.pos(), error); 475 } finally { 476 log.useSource(prev); 477 } 478 } 479 } 480 481 private void checkNoAllModulePath() { 482 if (addModsOpt != null && Arrays.asList(addModsOpt.split(",")).contains(ALL_MODULE_PATH)) { 483 log.error(Errors.AddmodsAllModulePathInvalid); 484 } 485 } 486 487 private final Completer mainCompleter = new Completer() { 488 @Override 489 public void complete(Symbol sym) throws CompletionFailure { 490 ModuleSymbol msym = moduleFinder.findModule((ModuleSymbol) sym); 491 492 if (msym.kind == Kinds.Kind.ERR) { 493 log.error(Errors.CantFindModule(msym)); 494 //make sure the module is initialized: 495 msym.directives = List.nil(); 496 msym.exports = List.nil(); 497 msym.provides = List.nil(); 498 msym.requires = List.nil(); 499 msym.uses = List.nil(); 500 } else if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 501 setupAutomaticModule(msym); 502 } else { 503 msym.module_info.complete(); 504 } 505 506 // If module-info comes from a .java file, the underlying 507 // call of classFinder.fillIn will have called through the 508 // source completer, to Enter, and then to Modules.enter, 509 // which will call completeModule. 510 // But, if module-info comes from a .class file, the underlying 511 // call of classFinder.fillIn will just call ClassReader to read 512 // the .class file, and so we call completeModule here. 513 if (msym.module_info.classfile == null || msym.module_info.classfile.getKind() == Kind.CLASS) { 514 completeModule(msym); 515 } 516 } 517 518 @Override 519 public String toString() { 520 return "mainCompleter"; 521 } 522 }; 523 524 private void setupAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 525 try { 526 ListBuffer<Directive> directives = new ListBuffer<>(); 527 ListBuffer<ExportsDirective> exports = new ListBuffer<>(); 528 Set<String> seenPackages = new HashSet<>(); 529 530 for (JavaFileObject clazz : fileManager.list(msym.classLocation, "", EnumSet.of(Kind.CLASS), true)) { 531 String binName = fileManager.inferBinaryName(msym.classLocation, clazz); 532 String pack = binName.lastIndexOf('.') != (-1) ? binName.substring(0, binName.lastIndexOf('.')) : ""; //unnamed package???? 533 if (seenPackages.add(pack)) { 534 ExportsDirective d = new ExportsDirective(syms.enterPackage(msym, names.fromString(pack)), null); 535 directives.add(d); 536 exports.add(d); 537 } 538 } 539 540 msym.exports = exports.toList(); 541 msym.provides = List.nil(); 542 msym.requires = List.nil(); 543 msym.uses = List.nil(); 544 msym.directives = directives.toList(); 545 msym.flags_field |= Flags.ACYCLIC; 546 } catch (IOException ex) { 547 throw new IllegalStateException(ex); 548 } 549 } 550 551 private void completeAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 552 ListBuffer<Directive> directives = new ListBuffer<>(); 553 554 directives.addAll(msym.directives); 555 556 ListBuffer<RequiresDirective> requires = new ListBuffer<>(); 557 558 for (ModuleSymbol ms : allModules()) { 559 if (ms == syms.unnamedModule || ms == msym) 560 continue; 561 Set<RequiresFlag> flags = (ms.flags_field & Flags.AUTOMATIC_MODULE) != 0 ? 562 EnumSet.of(RequiresFlag.PUBLIC) : EnumSet.noneOf(RequiresFlag.class); 563 RequiresDirective d = new RequiresDirective(ms, flags); 564 directives.add(d); 565 requires.add(d); 566 } 567 568 RequiresDirective requiresUnnamed = new RequiresDirective(syms.unnamedModule); 569 directives.add(requiresUnnamed); 570 requires.add(requiresUnnamed); 571 572 msym.requires = requires.toList(); 573 msym.directives = directives.toList(); 574 } 575 576 private Completer getSourceCompleter(JCCompilationUnit tree) { 577 return new Completer() { 578 @Override 579 public void complete(Symbol sym) throws CompletionFailure { 580 ModuleSymbol msym = (ModuleSymbol) sym; 581 msym.flags_field |= UNATTRIBUTED; 582 ModuleVisitor v = new ModuleVisitor(); 583 JavaFileObject prev = log.useSource(tree.sourcefile); 584 try { 585 tree.defs.head.accept(v); 586 checkCyclicDependencies((JCModuleDecl) tree.defs.head); 587 completeModule(msym); 588 } finally { 589 log.useSource(prev); 590 msym.flags_field &= ~UNATTRIBUTED; 591 } 592 } 593 594 @Override 595 public String toString() { 596 return "SourceCompleter: " + tree.sourcefile.getName(); 597 } 598 599 }; 600 } 601 602 class ModuleVisitor extends JCTree.Visitor { 603 private ModuleSymbol sym; 604 private final Set<ModuleSymbol> allRequires = new HashSet<>(); 605 private final Set<PackageSymbol> allExports = new HashSet<>(); 606 607 @Override 608 public void visitModuleDef(JCModuleDecl tree) { 609 sym = Assert.checkNonNull(tree.sym); 610 611 sym.requires = List.nil(); 612 sym.exports = List.nil(); 613 tree.directives.forEach(t -> t.accept(this)); 614 sym.requires = sym.requires.reverse(); 615 sym.exports = sym.exports.reverse(); 616 ensureJavaBase(); 617 } 618 619 @Override 620 public void visitRequires(JCRequires tree) { 621 ModuleSymbol msym = lookupModule(tree.moduleName); 622 if (msym.kind != MDL) { 623 log.error(tree.moduleName.pos(), Errors.ModuleNotFound(msym)); 624 } else if (allRequires.contains(msym)) { 625 log.error(tree.moduleName.pos(), Errors.DuplicateRequires(msym)); 626 } else { 627 allRequires.add(msym); 628 Set<RequiresFlag> flags = EnumSet.noneOf(RequiresFlag.class); 629 if (tree.isPublic) 630 flags.add(RequiresFlag.PUBLIC); 631 RequiresDirective d = new RequiresDirective(msym, flags); 632 tree.directive = d; 633 sym.requires = sym.requires.prepend(d); 634 } 635 } 636 637 @Override 638 public void visitExports(JCExports tree) { 639 Name name = TreeInfo.fullName(tree.qualid); 640 PackageSymbol packge = syms.enterPackage(sym, name); 641 attr.setPackageSymbols(tree.qualid, packge); 642 if (!allExports.add(packge)) { 643 log.error(tree.qualid.pos(), Errors.DuplicateExports(packge)); 644 } 645 646 List<ModuleSymbol> toModules = null; 647 if (tree.moduleNames != null) { 648 Set<ModuleSymbol> to = new HashSet<>(); 649 for (JCExpression n: tree.moduleNames) { 650 ModuleSymbol msym = lookupModule(n); 651 if (msym.kind != MDL) { 652 log.error(n.pos(), Errors.ModuleNotFound(msym)); 653 } else if (!to.add(msym)) { 654 log.error(n.pos(), Errors.DuplicateExports(msym)); 655 } 656 } 657 toModules = List.from(to); 658 } 659 660 if (toModules == null || !toModules.isEmpty()) { 661 ExportsDirective d = new ExportsDirective(packge, toModules); 662 tree.directive = d; 663 sym.exports = sym.exports.prepend(d); 664 } 665 } 666 667 @Override 668 public void visitProvides(JCProvides tree) { } 669 670 @Override 671 public void visitUses(JCUses tree) { } 672 673 private void ensureJavaBase() { 674 if (sym.name == names.java_base) 675 return; 676 677 for (RequiresDirective d: sym.requires) { 678 if (d.module.name == names.java_base) 679 return; 680 } 681 682 ModuleSymbol java_base = syms.enterModule(names.java_base); 683 Directive.RequiresDirective d = 684 new Directive.RequiresDirective(java_base, 685 EnumSet.of(Directive.RequiresFlag.MANDATED)); 686 sym.requires = sym.requires.prepend(d); 687 } 688 689 private ModuleSymbol lookupModule(JCExpression moduleName) { 690 try { 691 Name name = TreeInfo.fullName(moduleName); 692 ModuleSymbol msym = moduleFinder.findModule(name); 693 TreeInfo.setSymbol(moduleName, msym); 694 return msym; 695 } catch (Throwable t) { 696 System.err.println("Module " + sym + "; lookup export " + moduleName); 697 throw t; 698 } 699 } 700 } 701 702 public Completer getUsesProvidesCompleter() { 703 return sym -> { 704 ModuleSymbol msym = (ModuleSymbol) sym; 705 706 msym.complete(); 707 708 Env<AttrContext> env = typeEnvs.get(msym); 709 UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env); 710 JavaFileObject prev = log.useSource(env.toplevel.sourcefile); 711 try { 712 env.toplevel.defs.head.accept(v); 713 } finally { 714 log.useSource(prev); 715 } 716 }; 717 } 718 719 class UsesProvidesVisitor extends JCTree.Visitor { 720 private final ModuleSymbol msym; 721 private final Env<AttrContext> env; 722 723 private final Set<Directive.UsesDirective> allUses = new HashSet<>(); 724 private final Set<Directive.ProvidesDirective> allProvides = new HashSet<>(); 725 726 public UsesProvidesVisitor(ModuleSymbol msym, Env<AttrContext> env) { 727 this.msym = msym; 728 this.env = env; 729 } 730 731 @Override @SuppressWarnings("unchecked") 732 public void visitModuleDef(JCModuleDecl tree) { 733 msym.directives = List.nil(); 734 msym.provides = List.nil(); 735 msym.uses = List.nil(); 736 tree.directives.forEach(t -> t.accept(this)); 737 msym.directives = msym.directives.reverse(); 738 msym.provides = msym.provides.reverse(); 739 msym.uses = msym.uses.reverse(); 740 741 if (msym.requires.nonEmpty() && msym.requires.head.flags.contains(RequiresFlag.MANDATED)) 742 msym.directives = msym.directives.prepend(msym.requires.head); 743 744 msym.directives = msym.directives.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 745 746 checkForCorrectness(); 747 } 748 749 @Override 750 public void visitExports(JCExports tree) { 751 if (tree.directive.packge.members().isEmpty()) { 752 log.error(tree.qualid.pos(), Errors.PackageEmptyOrNotFound(tree.directive.packge)); 753 } 754 msym.directives = msym.directives.prepend(tree.directive); 755 } 756 757 MethodSymbol noArgsConstructor(ClassSymbol tsym) { 758 for (Symbol sym : tsym.members().getSymbolsByName(names.init)) { 759 MethodSymbol mSym = (MethodSymbol)sym; 760 if (mSym.params().isEmpty()) { 761 return mSym; 762 } 763 } 764 return null; 765 } 766 767 Map<Directive.ProvidesDirective, JCProvides> directiveToTreeMap = new HashMap<>(); 768 769 @Override 770 public void visitProvides(JCProvides tree) { 771 Type st = attr.attribType(tree.serviceName, env, syms.objectType); 772 Type it = attr.attribType(tree.implName, env, syms.objectType); 773 ClassSymbol service = (ClassSymbol) st.tsym; 774 ClassSymbol impl = (ClassSymbol) it.tsym; 775 if (!types.isSubtype(it, st)) { 776 log.error(tree.implName.pos(), Errors.ServiceImplementationMustBeSubtypeOfServiceInterface); 777 } 778 if ((impl.flags() & ABSTRACT) != 0) { 779 log.error(tree.implName.pos(), Errors.ServiceImplementationIsAbstract(impl)); 780 } else if (impl.isInner()) { 781 log.error(tree.implName.pos(), Errors.ServiceImplementationIsInner(impl)); 782 } else if (service.isInner()) { 783 log.error(tree.serviceName.pos(), Errors.ServiceDefinitionIsInner(service)); 784 } else { 785 MethodSymbol constr = noArgsConstructor(impl); 786 if (constr == null) { 787 log.error(tree.implName.pos(), Errors.ServiceImplementationDoesntHaveANoArgsConstructor(impl)); 788 } else if ((constr.flags() & PUBLIC) == 0) { 789 log.error(tree.implName.pos(), Errors.ServiceImplementationNoArgsConstructorNotPublic(impl)); 790 } 791 } 792 if (st.hasTag(CLASS) && it.hasTag(CLASS)) { 793 Directive.ProvidesDirective d = new Directive.ProvidesDirective(service, impl); 794 if (!allProvides.add(d)) { 795 log.error(tree.pos(), Errors.DuplicateProvides(service, impl)); 796 } 797 msym.provides = msym.provides.prepend(d); 798 msym.directives = msym.directives.prepend(d); 799 directiveToTreeMap.put(d, tree); 800 } 801 } 802 803 @Override 804 public void visitRequires(JCRequires tree) { 805 if (tree.directive != null) { 806 msym.directives = msym.directives.prepend(tree.directive); 807 } 808 } 809 810 @Override 811 public void visitUses(JCUses tree) { 812 Type st = attr.attribType(tree.qualid, env, syms.objectType); 813 Symbol sym = TreeInfo.symbol(tree.qualid); 814 if ((sym.flags() & ENUM) != 0) { 815 log.error(tree.qualid.pos(), Errors.ServiceDefinitionIsEnum(st.tsym)); 816 } else if (st.hasTag(CLASS)) { 817 ClassSymbol service = (ClassSymbol) st.tsym; 818 Directive.UsesDirective d = new Directive.UsesDirective(service); 819 if (!allUses.add(d)) { 820 log.error(tree.pos(), Errors.DuplicateUses(service)); 821 } 822 msym.uses = msym.uses.prepend(d); 823 msym.directives = msym.directives.prepend(d); 824 } 825 } 826 827 private void checkForCorrectness() { 828 for (Directive.ProvidesDirective provides : allProvides) { 829 JCProvides tree = directiveToTreeMap.get(provides); 830 /* The implementation must be defined in the same module as the provides directive 831 * (else, error) 832 */ 833 PackageSymbol implementationDefiningPackage = provides.impl.packge(); 834 if (implementationDefiningPackage.modle != msym) { 835 log.error(tree.pos(), Errors.ServiceImplementationNotInRightModule(implementationDefiningPackage.modle)); 836 } 837 838 /* There is no inherent requirement that module that provides a service should actually 839 * use it itself. However, it is a pointless declaration if the service package is not 840 * exported and there is no uses for the service. 841 */ 842 PackageSymbol interfaceDeclaringPackage = provides.service.packge(); 843 boolean isInterfaceDeclaredInCurrentModule = interfaceDeclaringPackage.modle == msym; 844 boolean isInterfaceExportedFromAReadableModule = 845 msym.visiblePackages.get(interfaceDeclaringPackage.fullname) == interfaceDeclaringPackage; 846 if (isInterfaceDeclaredInCurrentModule && !isInterfaceExportedFromAReadableModule) { 847 // ok the interface is declared in this module. Let's check if it's exported 848 boolean warn = true; 849 for (ExportsDirective export : msym.exports) { 850 if (interfaceDeclaringPackage == export.packge) { 851 warn = false; 852 break; 853 } 854 } 855 if (warn) { 856 for (UsesDirective uses : msym.uses) { 857 if (provides.service == uses.service) { 858 warn = false; 859 break; 860 } 861 } 862 } 863 if (warn) { 864 log.warning(tree.pos(), Warnings.ServiceProvidedButNotExportedOrUsed(provides.service)); 865 } 866 } 867 } 868 } 869 } 870 871 private Set<ModuleSymbol> allModules; 872 873 public Set<ModuleSymbol> allModules() { 874 Assert.checkNonNull(allModules); 875 return allModules; 876 } 877 878 private void setupAllModules() { 879 Assert.checkNonNull(rootModules); 880 Assert.checkNull(allModules); 881 882 Set<ModuleSymbol> observable; 883 884 if (limitModsOpt == null && extraLimitMods.isEmpty()) { 885 observable = null; 886 } else { 887 Set<ModuleSymbol> limitMods = new HashSet<>(); 888 if (limitModsOpt != null) { 889 for (String limit : limitModsOpt.split(",")) { 890 limitMods.add(syms.enterModule(names.fromString(limit))); 891 } 892 } 893 for (String limit : extraLimitMods) { 894 limitMods.add(syms.enterModule(names.fromString(limit))); 895 } 896 observable = computeTransitiveClosure(limitMods, null); 897 observable.addAll(rootModules); 898 } 899 900 Predicate<ModuleSymbol> observablePred = sym -> observable == null || observable.contains(sym); 901 Predicate<ModuleSymbol> systemModulePred = sym -> (sym.flags() & Flags.SYSTEM_MODULE) != 0; 902 Set<ModuleSymbol> enabledRoot = new LinkedHashSet<>(); 903 904 if (rootModules.contains(syms.unnamedModule)) { 905 ModuleSymbol javaSE = syms.getModule(java_se); 906 Predicate<ModuleSymbol> jdkModulePred; 907 908 if (javaSE != null && (observable == null || observable.contains(javaSE))) { 909 jdkModulePred = sym -> { 910 sym.complete(); 911 return !sym.name.startsWith(java_) 912 && sym.exports.stream().anyMatch(e -> e.modules == null); 913 }; 914 enabledRoot.add(javaSE); 915 } else { 916 jdkModulePred = sym -> true; 917 } 918 919 for (ModuleSymbol sym : new HashSet<>(syms.getAllModules())) { 920 if (systemModulePred.test(sym) && observablePred.test(sym) && jdkModulePred.test(sym)) { 921 enabledRoot.add(sym); 922 } 923 } 924 } 925 926 enabledRoot.addAll(rootModules); 927 928 if (addModsOpt != null || !extraAddMods.isEmpty()) { 929 Set<String> fullAddMods = new HashSet<>(); 930 fullAddMods.addAll(extraAddMods); 931 932 if (addModsOpt != null) { 933 fullAddMods.addAll(Arrays.asList(addModsOpt.split(","))); 934 } 935 936 for (String added : fullAddMods) { 937 Stream<ModuleSymbol> modules; 938 switch (added) { 939 case ALL_SYSTEM: 940 modules = syms.getAllModules() 941 .stream() 942 .filter(systemModulePred.and(observablePred)); 943 break; 944 case ALL_MODULE_PATH: 945 modules = syms.getAllModules() 946 .stream() 947 .filter(systemModulePred.negate().and(observablePred)); 948 break; 949 default: 950 modules = Stream.of(syms.enterModule(names.fromString(added))); 951 break; 952 } 953 modules.forEach(sym -> { 954 enabledRoot.add(sym); 955 if (observable != null) 956 observable.add(sym); 957 }); 958 } 959 } 960 961 Set<ModuleSymbol> result = computeTransitiveClosure(enabledRoot, observable); 962 963 result.add(syms.unnamedModule); 964 965 allModules = result; 966 } 967 968 private Set<ModuleSymbol> computeTransitiveClosure(Iterable<? extends ModuleSymbol> base, Set<ModuleSymbol> observable) { 969 List<ModuleSymbol> todo = List.nil(); 970 971 for (ModuleSymbol ms : base) { 972 todo = todo.prepend(ms); 973 } 974 975 Set<ModuleSymbol> result = new LinkedHashSet<>(); 976 result.add(syms.java_base); 977 978 while (todo.nonEmpty()) { 979 ModuleSymbol current = todo.head; 980 todo = todo.tail; 981 if (observable != null && !observable.contains(current)) 982 continue; 983 if (!result.add(current) || current == syms.unnamedModule || ((current.flags_field & Flags.AUTOMATIC_MODULE) != 0)) 984 continue; 985 current.complete(); 986 for (RequiresDirective rd : current.requires) { 987 todo = todo.prepend(rd.module); 988 } 989 } 990 991 return result; 992 } 993 994 public ModuleSymbol getObservableModule(Name name) { 995 ModuleSymbol mod = syms.getModule(name); 996 997 if (allModules().contains(mod)) { 998 return mod; 999 } 1000 1001 return null; 1002 } 1003 1004 private Completer getUnnamedModuleCompleter() { 1005 moduleFinder.findAllModules(); 1006 return new Symbol.Completer() { 1007 @Override 1008 public void complete(Symbol sym) throws CompletionFailure { 1009 ModuleSymbol msym = (ModuleSymbol) sym; 1010 Set<ModuleSymbol> allModules = allModules(); 1011 for (ModuleSymbol m : allModules) { 1012 m.complete(); 1013 } 1014 initVisiblePackages(msym, allModules); 1015 } 1016 1017 @Override 1018 public String toString() { 1019 return "unnamedModule Completer"; 1020 } 1021 }; 1022 } 1023 1024 private final Map<ModuleSymbol, Set<ModuleSymbol>> requiresPublicCache = new HashMap<>(); 1025 1026 private void completeModule(ModuleSymbol msym) { 1027 if (inInitModules) { 1028 msym.completer = sym -> completeModule(msym); 1029 return ; 1030 } 1031 1032 if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 1033 completeAutomaticModule(msym); 1034 } 1035 1036 Assert.checkNonNull(msym.requires); 1037 1038 initAddReads(); 1039 1040 msym.requires = msym.requires.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 1041 1042 List<RequiresDirective> requires = msym.requires; 1043 List<RequiresDirective> previous = null; 1044 1045 while (requires.nonEmpty()) { 1046 if (!allModules().contains(requires.head.module)) { 1047 Env<AttrContext> env = typeEnvs.get(msym); 1048 if (env != null) { 1049 JavaFileObject origSource = log.useSource(env.toplevel.sourcefile); 1050 try { 1051 log.error(/*XXX*/env.tree, Errors.ModuleNotFound(requires.head.module)); 1052 } finally { 1053 log.useSource(origSource); 1054 } 1055 } else { 1056 Assert.check((msym.flags() & Flags.AUTOMATIC_MODULE) == 0); 1057 } 1058 if (previous != null) { 1059 previous.tail = requires.tail; 1060 } else { 1061 msym.requires.tail = requires.tail; 1062 } 1063 } else { 1064 previous = requires; 1065 } 1066 requires = requires.tail; 1067 } 1068 1069 Set<ModuleSymbol> readable = new LinkedHashSet<>(); 1070 Set<ModuleSymbol> requiresPublic = new HashSet<>(); 1071 1072 for (RequiresDirective d : msym.requires) { 1073 d.module.complete(); 1074 readable.add(d.module); 1075 Set<ModuleSymbol> s = retrieveRequiresPublic(d.module); 1076 Assert.checkNonNull(s, () -> "no entry in cache for " + d.module); 1077 readable.addAll(s); 1078 if (d.flags.contains(RequiresFlag.PUBLIC)) { 1079 requiresPublic.add(d.module); 1080 requiresPublic.addAll(s); 1081 } 1082 } 1083 1084 requiresPublicCache.put(msym, requiresPublic); 1085 initVisiblePackages(msym, readable); 1086 for (ExportsDirective d: msym.exports) { 1087 d.packge.modle = msym; 1088 } 1089 1090 } 1091 1092 private Set<ModuleSymbol> retrieveRequiresPublic(ModuleSymbol msym) { 1093 Set<ModuleSymbol> requiresPublic = requiresPublicCache.get(msym); 1094 1095 if (requiresPublic == null) { 1096 //the module graph may contain cycles involving automatic modules or --add-reads edges 1097 requiresPublic = new HashSet<>(); 1098 1099 Set<ModuleSymbol> seen = new HashSet<>(); 1100 List<ModuleSymbol> todo = List.of(msym); 1101 1102 while (todo.nonEmpty()) { 1103 ModuleSymbol current = todo.head; 1104 todo = todo.tail; 1105 if (!seen.add(current)) 1106 continue; 1107 requiresPublic.add(current); 1108 current.complete(); 1109 Iterable<? extends RequiresDirective> requires; 1110 if (current != syms.unnamedModule) { 1111 Assert.checkNonNull(current.requires, () -> current + ".requires == null; " + msym); 1112 requires = current.requires; 1113 for (RequiresDirective rd : requires) { 1114 if (rd.isPublic()) 1115 todo = todo.prepend(rd.module); 1116 } 1117 } else { 1118 for (ModuleSymbol mod : allModules()) { 1119 todo = todo.prepend(mod); 1120 } 1121 } 1122 } 1123 1124 requiresPublic.remove(msym); 1125 } 1126 1127 return requiresPublic; 1128 } 1129 1130 private void initVisiblePackages(ModuleSymbol msym, Collection<ModuleSymbol> readable) { 1131 initAddExports(); 1132 1133 msym.visiblePackages = new LinkedHashMap<>(); 1134 1135 Map<Name, ModuleSymbol> seen = new HashMap<>(); 1136 1137 for (ModuleSymbol rm : readable) { 1138 if (rm == syms.unnamedModule) 1139 continue; 1140 addVisiblePackages(msym, seen, rm, rm.exports); 1141 } 1142 1143 for (Entry<ModuleSymbol, Set<ExportsDirective>> addExportsEntry : addExports.entrySet()) 1144 addVisiblePackages(msym, seen, addExportsEntry.getKey(), addExportsEntry.getValue()); 1145 } 1146 1147 private void addVisiblePackages(ModuleSymbol msym, 1148 Map<Name, ModuleSymbol> seenPackages, 1149 ModuleSymbol exportsFrom, 1150 Collection<ExportsDirective> exports) { 1151 for (ExportsDirective d : exports) { 1152 if (d.modules == null || d.modules.contains(msym)) { 1153 Name packageName = d.packge.fullname; 1154 ModuleSymbol previousModule = seenPackages.get(packageName); 1155 1156 if (previousModule != null && previousModule != exportsFrom) { 1157 Env<AttrContext> env = typeEnvs.get(msym); 1158 JavaFileObject origSource = env != null ? log.useSource(env.toplevel.sourcefile) 1159 : null; 1160 DiagnosticPosition pos = env != null ? env.tree.pos() : null; 1161 try { 1162 log.error(pos, Errors.PackageClashFromRequires(msym, packageName, 1163 previousModule, exportsFrom)); 1164 } finally { 1165 if (env != null) 1166 log.useSource(origSource); 1167 } 1168 continue; 1169 } 1170 1171 seenPackages.put(packageName, exportsFrom); 1172 msym.visiblePackages.put(d.packge.fullname, d.packge); 1173 } 1174 } 1175 } 1176 1177 private void initAddExports() { 1178 if (addExports != null) 1179 return; 1180 1181 addExports = new LinkedHashMap<>(); 1182 1183 if (addExportsOpt == null) 1184 return; 1185 1186// System.err.println("Modules.addExports:\n " + addExportsOpt.replace("\0", "\n ")); 1187 1188 Pattern ep = Pattern.compile("([^/]+)/([^=]+)=(.*)"); 1189 for (String s: addExportsOpt.split("\0+")) { 1190 if (s.isEmpty()) 1191 continue; 1192 Matcher em = ep.matcher(s); 1193 if (!em.matches()) { 1194 continue; 1195 } 1196 1197 // Terminology comes from 1198 // --add-exports module/package=target,... 1199 // Compare to 1200 // module module { exports package to target, ... } 1201 String moduleName = em.group(1); 1202 String packageName = em.group(2); 1203 String targetNames = em.group(3); 1204 1205 ModuleSymbol msym = syms.enterModule(names.fromString(moduleName)); 1206 PackageSymbol p = syms.enterPackage(msym, names.fromString(packageName)); 1207 p.modle = msym; // TODO: do we need this? 1208 1209 List<ModuleSymbol> targetModules = List.nil(); 1210 for (String toModule : targetNames.split("[ ,]+")) { 1211 ModuleSymbol m; 1212 if (toModule.equals("ALL-UNNAMED")) { 1213 m = syms.unnamedModule; 1214 } else { 1215 if (!SourceVersion.isName(toModule)) { 1216 // TODO: error: invalid module name 1217 continue; 1218 } 1219 m = syms.enterModule(names.fromString(toModule)); 1220 } 1221 targetModules = targetModules.prepend(m); 1222 } 1223 1224 Set<ExportsDirective> extra = addExports.computeIfAbsent(msym, _x -> new LinkedHashSet<>()); 1225 ExportsDirective d = new ExportsDirective(p, targetModules); 1226 extra.add(d); 1227 } 1228 } 1229 1230 private void initAddReads() { 1231 if (addReads != null) 1232 return; 1233 1234 addReads = new LinkedHashMap<>(); 1235 1236 if (addReadsOpt == null) 1237 return; 1238 1239// System.err.println("Modules.addReads:\n " + addReadsOpt.replace("\0", "\n ")); 1240 1241 Pattern rp = Pattern.compile("([^=]+)=(.*)"); 1242 for (String s : addReadsOpt.split("\0+")) { 1243 if (s.isEmpty()) 1244 continue; 1245 Matcher rm = rp.matcher(s); 1246 if (!rm.matches()) { 1247 continue; 1248 } 1249 1250 // Terminology comes from 1251 // --add-reads target-module=source-module,... 1252 // Compare to 1253 // module target-module { requires source-module; ... } 1254 String targetName = rm.group(1); 1255 String sources = rm.group(2); 1256 1257 ModuleSymbol msym = syms.enterModule(names.fromString(targetName)); 1258 for (String source : sources.split("[ ,]+")) { 1259 ModuleSymbol sourceModule; 1260 if (source.equals("ALL-UNNAMED")) { 1261 sourceModule = syms.unnamedModule; 1262 } else { 1263 if (!SourceVersion.isName(source)) { 1264 // TODO: error: invalid module name 1265 continue; 1266 } 1267 sourceModule = syms.enterModule(names.fromString(source)); 1268 } 1269 addReads.computeIfAbsent(msym, m -> new HashSet<>()) 1270 .add(new RequiresDirective(sourceModule, EnumSet.of(RequiresFlag.EXTRA))); 1271 } 1272 } 1273 } 1274 1275 private void checkCyclicDependencies(JCModuleDecl mod) { 1276 for (JCDirective d : mod.directives) { 1277 JCRequires rd; 1278 if (!d.hasTag(Tag.REQUIRES) || (rd = (JCRequires) d).directive == null) 1279 continue; 1280 Set<ModuleSymbol> nonSyntheticDeps = new HashSet<>(); 1281 List<ModuleSymbol> queue = List.of(rd.directive.module); 1282 while (queue.nonEmpty()) { 1283 ModuleSymbol current = queue.head; 1284 queue = queue.tail; 1285 if (!nonSyntheticDeps.add(current)) 1286 continue; 1287 current.complete(); 1288 if ((current.flags() & Flags.ACYCLIC) != 0) 1289 continue; 1290 Assert.checkNonNull(current.requires, () -> current.toString()); 1291 for (RequiresDirective dep : current.requires) { 1292 if (!dep.flags.contains(RequiresFlag.EXTRA)) 1293 queue = queue.prepend(dep.module); 1294 } 1295 } 1296 if (nonSyntheticDeps.contains(mod.sym)) { 1297 log.error(rd.moduleName.pos(), Errors.CyclicRequires(rd.directive.module)); 1298 } 1299 mod.sym.flags_field |= Flags.ACYCLIC; 1300 } 1301 } 1302 1303 // DEBUG 1304 private String toString(ModuleSymbol msym) { 1305 return msym.name + "[" 1306 + "kind:" + msym.kind + ";" 1307 + "locn:" + toString(msym.sourceLocation) + "," + toString(msym.classLocation) + ";" 1308 + "info:" + toString(msym.module_info.sourcefile) + "," 1309 + toString(msym.module_info.classfile) + "," 1310 + msym.module_info.completer 1311 + "]"; 1312 } 1313 1314 // DEBUG 1315 String toString(Location locn) { 1316 return (locn == null) ? "--" : locn.getName(); 1317 } 1318 1319 // DEBUG 1320 String toString(JavaFileObject fo) { 1321 return (fo == null) ? "--" : fo.getName(); 1322 } 1323 1324 public void newRound() { 1325 rootModules = null; 1326 allModules = null; 1327 } 1328} 1329