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