1 /* 2 * Copyright (c) 2009, 2021, 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.Set; 40 import java.util.function.Consumer; 41 import java.util.function.Predicate; 42 import java.util.regex.Matcher; 43 import java.util.regex.Pattern; 44 import java.util.stream.Collectors; 45 import java.util.stream.Stream; 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.source.tree.ModuleTree.ModuleKind; 55 import com.sun.tools.javac.code.ClassFinder; 56 import com.sun.tools.javac.code.DeferredLintHandler; 57 import com.sun.tools.javac.code.Directive; 58 import com.sun.tools.javac.code.Directive.ExportsDirective; 59 import com.sun.tools.javac.code.Directive.ExportsFlag; 60 import com.sun.tools.javac.code.Directive.OpensDirective; 61 import com.sun.tools.javac.code.Directive.OpensFlag; 62 import com.sun.tools.javac.code.Directive.RequiresDirective; 63 import com.sun.tools.javac.code.Directive.RequiresFlag; 64 import com.sun.tools.javac.code.Directive.UsesDirective; 65 import com.sun.tools.javac.code.Flags; 66 import com.sun.tools.javac.code.Flags.Flag; 67 import com.sun.tools.javac.code.Lint.LintCategory; 68 import com.sun.tools.javac.code.ModuleFinder; 69 import com.sun.tools.javac.code.Source; 70 import com.sun.tools.javac.code.Source.Feature; 71 import com.sun.tools.javac.code.Symbol; 72 import com.sun.tools.javac.code.Symbol.ClassSymbol; 73 import com.sun.tools.javac.code.Symbol.Completer; 74 import com.sun.tools.javac.code.Symbol.CompletionFailure; 75 import com.sun.tools.javac.code.Symbol.MethodSymbol; 76 import com.sun.tools.javac.code.Symbol.ModuleFlags; 77 import com.sun.tools.javac.code.Symbol.ModuleSymbol; 78 import com.sun.tools.javac.code.Symbol.PackageSymbol; 79 import com.sun.tools.javac.code.Symtab; 80 import com.sun.tools.javac.code.Type; 81 import com.sun.tools.javac.code.Types; 82 import com.sun.tools.javac.jvm.ClassWriter; 83 import com.sun.tools.javac.jvm.JNIWriter; 84 import com.sun.tools.javac.jvm.Target; 85 import com.sun.tools.javac.main.Option; 86 import com.sun.tools.javac.resources.CompilerProperties.Errors; 87 import com.sun.tools.javac.resources.CompilerProperties.Warnings; 88 import com.sun.tools.javac.tree.JCTree; 89 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 90 import com.sun.tools.javac.tree.JCTree.JCDirective; 91 import com.sun.tools.javac.tree.JCTree.JCExports; 92 import com.sun.tools.javac.tree.JCTree.JCExpression; 93 import com.sun.tools.javac.tree.JCTree.JCModuleDecl; 94 import com.sun.tools.javac.tree.JCTree.JCOpens; 95 import com.sun.tools.javac.tree.JCTree.JCProvides; 96 import com.sun.tools.javac.tree.JCTree.JCRequires; 97 import com.sun.tools.javac.tree.JCTree.JCUses; 98 import com.sun.tools.javac.tree.JCTree.Tag; 99 import com.sun.tools.javac.tree.TreeInfo; 100 import com.sun.tools.javac.util.Assert; 101 import com.sun.tools.javac.util.Context; 102 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 103 import com.sun.tools.javac.util.List; 104 import com.sun.tools.javac.util.ListBuffer; 105 import com.sun.tools.javac.util.Log; 106 import com.sun.tools.javac.util.Name; 107 import com.sun.tools.javac.util.Names; 108 import com.sun.tools.javac.util.Options; 109 110 import static com.sun.tools.javac.code.Flags.ABSTRACT; 111 import static com.sun.tools.javac.code.Flags.ENUM; 112 import static com.sun.tools.javac.code.Flags.PUBLIC; 113 import static com.sun.tools.javac.code.Flags.UNATTRIBUTED; 114 115 import com.sun.tools.javac.code.Kinds; 116 117 import static com.sun.tools.javac.code.Kinds.Kind.ERR; 118 import static com.sun.tools.javac.code.Kinds.Kind.MDL; 119 import static com.sun.tools.javac.code.Kinds.Kind.MTH; 120 121 import com.sun.tools.javac.code.Symbol.ModuleResolutionFlags; 122 123 import static com.sun.tools.javac.code.TypeTag.CLASS; 124 125 /** 126 * TODO: fill in 127 * 128 * <p><b>This is NOT part of any supported API. 129 * If you write code that depends on this, you do so at your own risk. 130 * This code and its internal interfaces are subject to change or 131 * deletion without notice.</b> 132 */ 133 public class Modules extends JCTree.Visitor { 134 private static final String ALL_SYSTEM = "ALL-SYSTEM"; 135 private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; 136 137 private final Log log; 138 private final Names names; 139 private final Symtab syms; 140 private final Attr attr; 141 private final Check chk; 142 private final DeferredLintHandler deferredLintHandler; 143 private final TypeEnvs typeEnvs; 144 private final Types types; 145 private final JavaFileManager fileManager; 146 private final ModuleFinder moduleFinder; 147 private final Source source; 148 private final Target target; 149 private final boolean allowModules; 150 private final boolean allowAccessIntoSystem; 151 152 public final boolean multiModuleMode; 153 154 private final Name java_se; 155 private final Name java_; 156 157 ModuleSymbol defaultModule; 158 159 private final String addExportsOpt; 160 private Map<ModuleSymbol, Set<ExportsDirective>> addExports; 161 private final String addReadsOpt; 162 private Map<ModuleSymbol, Set<RequiresDirective>> addReads; 163 private final String addModsOpt; 164 private final Set<String> extraAddMods = new HashSet<>(); 165 private final String limitModsOpt; 166 private final Set<String> extraLimitMods = new HashSet<>(); 167 private final String moduleVersionOpt; 168 private final boolean sourceLauncher; 169 170 private final boolean lintOptions; 171 172 private Set<ModuleSymbol> rootModules = null; 173 private final Set<ModuleSymbol> warnedMissing = new HashSet<>(); 174 175 public PackageNameFinder findPackageInFile; 176 177 public static Modules instance(Context context) { 178 Modules instance = context.get(Modules.class); 179 if (instance == null) 180 instance = new Modules(context); 181 return instance; 182 } 183 184 protected Modules(Context context) { 185 context.put(Modules.class, this); 186 log = Log.instance(context); 187 names = Names.instance(context); 188 syms = Symtab.instance(context); 189 attr = Attr.instance(context); 190 chk = Check.instance(context); 191 deferredLintHandler = DeferredLintHandler.instance(context); 192 typeEnvs = TypeEnvs.instance(context); 193 moduleFinder = ModuleFinder.instance(context); 194 types = Types.instance(context); 195 fileManager = context.get(JavaFileManager.class); 196 source = Source.instance(context); 197 target = Target.instance(context); 198 allowModules = Feature.MODULES.allowedInSource(source); 199 Options options = Options.instance(context); 200 201 allowAccessIntoSystem = options.isUnset(Option.RELEASE); 202 lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option); 203 204 multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH); 205 ClassWriter classWriter = ClassWriter.instance(context); 206 classWriter.multiModuleMode = multiModuleMode; 207 JNIWriter jniWriter = JNIWriter.instance(context); 208 jniWriter.multiModuleMode = multiModuleMode; 209 210 java_se = names.fromString("java.se"); 211 java_ = names.fromString("java."); 212 213 addExportsOpt = options.get(Option.ADD_EXPORTS); 214 addReadsOpt = options.get(Option.ADD_READS); 215 addModsOpt = options.get(Option.ADD_MODULES); 216 limitModsOpt = options.get(Option.LIMIT_MODULES); 217 moduleVersionOpt = options.get(Option.MODULE_VERSION); 218 sourceLauncher = options.isSet("sourceLauncher"); 219 } 220 221 int depth = -1; 222 223 public void addExtraAddModules(String... extras) { 224 extraAddMods.addAll(Arrays.asList(extras)); 225 } 226 227 boolean inInitModules; 228 public void initModules(List<JCCompilationUnit> trees) { 229 Assert.check(!inInitModules); 230 try { 231 inInitModules = true; 232 Assert.checkNull(rootModules); 233 enter(trees, modules -> { 234 Assert.checkNull(rootModules); 235 Assert.checkNull(allModules); 236 this.rootModules = modules; 237 setupAllModules(); //initialize the module graph 238 Assert.checkNonNull(allModules); 239 inInitModules = false; 240 }, null); 241 } finally { 242 inInitModules = false; 243 } 244 } 245 246 public boolean enter(List<JCCompilationUnit> trees, ClassSymbol c) { 247 Assert.check(rootModules != null || inInitModules || !allowModules); 248 return enter(trees, modules -> {}, c); 249 } 250 251 private boolean enter(List<JCCompilationUnit> trees, Consumer<Set<ModuleSymbol>> init, ClassSymbol c) { 252 if (!allowModules) { 253 for (JCCompilationUnit tree: trees) { 254 tree.modle = syms.noModule; 255 } 256 defaultModule = syms.noModule; 257 return true; 258 } 259 260 int startErrors = log.nerrors; 261 262 depth++; 263 try { 264 // scan trees for module defs 265 Set<ModuleSymbol> roots = enterModules(trees, c); 266 267 setCompilationUnitModules(trees, roots, c); 268 269 init.accept(roots); 270 271 for (ModuleSymbol msym: roots) { 272 msym.complete(); 273 } 274 } catch (CompletionFailure ex) { 275 chk.completionError(null, ex); 276 } finally { 277 depth--; 278 } 279 280 return (log.nerrors == startErrors); 281 } 282 283 public Completer getCompleter() { 284 return mainCompleter; 285 } 286 287 public ModuleSymbol getDefaultModule() { 288 return defaultModule; 289 } 290 291 public boolean modulesInitialized() { 292 return allModules != null; 293 } 294 295 private Set<ModuleSymbol> enterModules(List<JCCompilationUnit> trees, ClassSymbol c) { 296 Set<ModuleSymbol> modules = new LinkedHashSet<>(); 297 for (JCCompilationUnit tree : trees) { 298 JavaFileObject prev = log.useSource(tree.sourcefile); 299 try { 300 enterModule(tree, c, modules); 301 } finally { 302 log.useSource(prev); 303 } 304 } 305 return modules; 306 } 307 308 309 private void enterModule(JCCompilationUnit toplevel, ClassSymbol c, Set<ModuleSymbol> modules) { 310 boolean isModuleInfo = toplevel.sourcefile.isNameCompatible("module-info", Kind.SOURCE); 311 boolean isModuleDecl = toplevel.getModuleDecl() != null; 312 if (isModuleDecl) { 313 JCModuleDecl decl = toplevel.getModuleDecl(); 314 if (!isModuleInfo) { 315 log.error(decl.pos(), Errors.ModuleDeclSbInModuleInfoJava); 316 } 317 Name name = TreeInfo.fullName(decl.qualId); 318 ModuleSymbol sym; 319 if (c != null) { 320 sym = (ModuleSymbol) c.owner; 321 Assert.checkNonNull(sym.name); 322 Name treeName = TreeInfo.fullName(decl.qualId); 323 if (sym.name != treeName) { 324 log.error(decl.pos(), Errors.ModuleNameMismatch(name, sym.name)); 325 } 326 } else { 327 sym = syms.enterModule(name); 328 if (sym.module_info.sourcefile != null && sym.module_info.sourcefile != toplevel.sourcefile) { 329 log.error(decl.pos(), Errors.DuplicateModule(sym)); 330 return; 331 } 332 } 333 sym.completer = getSourceCompleter(toplevel); 334 sym.module_info.classfile = sym.module_info.sourcefile = toplevel.sourcefile; 335 decl.sym = sym; 336 337 if (multiModuleMode || modules.isEmpty()) { 338 modules.add(sym); 339 } else { 340 log.error(toplevel.pos(), Errors.TooManyModules); 341 } 342 343 Env<AttrContext> provisionalEnv = new Env<>(decl, null); 344 345 provisionalEnv.toplevel = toplevel; 346 typeEnvs.put(sym, provisionalEnv); 347 } else if (isModuleInfo) { 348 if (multiModuleMode) { 349 JCTree tree = toplevel.defs.isEmpty() ? toplevel : toplevel.defs.head; 350 log.error(tree.pos(), Errors.ExpectedModule); 351 } 352 } 353 } 354 355 private void setCompilationUnitModules(List<JCCompilationUnit> trees, Set<ModuleSymbol> rootModules, ClassSymbol c) { 356 // update the module for each compilation unit 357 if (multiModuleMode) { 358 boolean patchesAutomaticModules = false; 359 for (JCCompilationUnit tree: trees) { 360 if (tree.defs.isEmpty()) { 361 tree.modle = syms.unnamedModule; 362 continue; 363 } 364 365 JavaFileObject prev = log.useSource(tree.sourcefile); 366 try { 367 Location msplocn = getModuleLocation(tree); 368 Location plocn = fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH) ? 369 fileManager.getLocationForModule(StandardLocation.PATCH_MODULE_PATH, 370 tree.sourcefile) : 371 null; 372 373 if (plocn != null) { 374 Name name = names.fromString(fileManager.inferModuleName(plocn)); 375 ModuleSymbol msym = moduleFinder.findModule(name); 376 tree.modle = msym; 377 rootModules.add(msym); 378 patchesAutomaticModules |= (msym.flags_field & Flags.AUTOMATIC_MODULE) != 0; 379 380 if (msplocn != null) { 381 Name mspname = names.fromString(fileManager.inferModuleName(msplocn)); 382 if (name != mspname) { 383 log.error(tree.pos(), Errors.FilePatchedAndMsp(name, mspname)); 384 } 385 } 386 } else if (msplocn != null) { 387 if (tree.getModuleDecl() != null) { 388 JavaFileObject canonical = 389 fileManager.getJavaFileForInput(msplocn, "module-info", Kind.SOURCE); 390 if (canonical == null || !fileManager.isSameFile(canonical, tree.sourcefile)) { 391 log.error(tree.pos(), Errors.ModuleNotFoundOnModuleSourcePath); 392 } 393 } 394 Name name = names.fromString(fileManager.inferModuleName(msplocn)); 395 ModuleSymbol msym; 396 JCModuleDecl decl = tree.getModuleDecl(); 397 if (decl != null) { 398 msym = decl.sym; 399 if (msym.name != name) { 400 log.error(decl.qualId, Errors.ModuleNameMismatch(msym.name, name)); 401 } 402 } else { 403 if (tree.getPackage() == null) { 404 log.error(tree.pos(), Errors.UnnamedPkgNotAllowedNamedModules); 405 } 406 msym = syms.enterModule(name); 407 } 408 if (msym.sourceLocation == null) { 409 msym.sourceLocation = msplocn; 410 if (fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) { 411 msym.patchLocation = fileManager.getLocationForModule( 412 StandardLocation.PATCH_MODULE_PATH, msym.name.toString()); 413 } 414 if (fileManager.hasLocation(StandardLocation.CLASS_OUTPUT)) { 415 Location outputLocn = fileManager.getLocationForModule( 416 StandardLocation.CLASS_OUTPUT, msym.name.toString()); 417 if (msym.patchLocation == null) { 418 msym.classLocation = outputLocn; 419 } else { 420 msym.patchOutputLocation = outputLocn; 421 } 422 } 423 } 424 tree.modle = msym; 425 rootModules.add(msym); 426 } else if (c != null && c.packge().modle == syms.unnamedModule) { 427 tree.modle = syms.unnamedModule; 428 } else { 429 if (tree.getModuleDecl() != null) { 430 log.error(tree.pos(), Errors.ModuleNotFoundOnModuleSourcePath); 431 } else { 432 log.error(tree.pos(), Errors.NotInModuleOnModuleSourcePath); 433 } 434 tree.modle = syms.errModule; 435 } 436 } catch (IOException e) { 437 throw new Error(e); // FIXME 438 } finally { 439 log.useSource(prev); 440 } 441 } 442 if (!patchesAutomaticModules) { 443 checkNoAllModulePath(); 444 } 445 if (syms.unnamedModule.sourceLocation == null) { 446 syms.unnamedModule.completer = getUnnamedModuleCompleter(); 447 syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH; 448 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH; 449 } 450 defaultModule = syms.unnamedModule; 451 } else { 452 ModuleSymbol module = null; 453 if (defaultModule == null) { 454 String moduleOverride = singleModuleOverride(trees); 455 switch (rootModules.size()) { 456 case 0: 457 try { 458 defaultModule = moduleFinder.findSingleModule(); 459 } catch (CompletionFailure cf) { 460 chk.completionError(null, cf); 461 defaultModule = syms.unnamedModule; 462 } 463 if (defaultModule == syms.unnamedModule) { 464 if (moduleOverride != null) { 465 defaultModule = moduleFinder.findModule(names.fromString(moduleOverride)); 466 defaultModule.patchOutputLocation = StandardLocation.CLASS_OUTPUT; 467 if ((defaultModule.flags_field & Flags.AUTOMATIC_MODULE) == 0) { 468 checkNoAllModulePath(); 469 } 470 } else { 471 // Question: why not do findAllModules and initVisiblePackages here? 472 // i.e. body of unnamedModuleCompleter 473 defaultModule.completer = getUnnamedModuleCompleter(); 474 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 475 defaultModule.classLocation = StandardLocation.CLASS_PATH; 476 } 477 } else { 478 checkNoAllModulePath(); 479 defaultModule.complete(); 480 // Question: why not do completeModule here? 481 defaultModule.completer = sym -> completeModule((ModuleSymbol) sym); 482 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 483 } 484 rootModules.add(defaultModule); 485 break; 486 case 1: 487 checkNoAllModulePath(); 488 defaultModule = rootModules.iterator().next(); 489 defaultModule.sourceLocation = StandardLocation.SOURCE_PATH; 490 if (fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) { 491 try { 492 defaultModule.patchLocation = fileManager.getLocationForModule( 493 StandardLocation.PATCH_MODULE_PATH, defaultModule.name.toString()); 494 } catch (IOException ex) { 495 throw new Error(ex); 496 } 497 } 498 if (defaultModule.patchLocation == null) { 499 defaultModule.classLocation = StandardLocation.CLASS_OUTPUT; 500 } else { 501 defaultModule.patchOutputLocation = StandardLocation.CLASS_OUTPUT; 502 } 503 break; 504 default: 505 Assert.error("too many modules"); 506 } 507 } else if (rootModules.size() == 1) { 508 module = rootModules.iterator().next(); 509 module.complete(); 510 module.completer = sym -> completeModule((ModuleSymbol) sym); 511 } else { 512 Assert.check(rootModules.isEmpty()); 513 Assert.checkNonNull(c); 514 module = c.packge().modle; 515 rootModules.add(module); 516 } 517 518 if (defaultModule != syms.unnamedModule) { 519 syms.unnamedModule.completer = getUnnamedModuleCompleter(); 520 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH; 521 } 522 523 if (module == null) { 524 module = defaultModule; 525 } 526 527 for (JCCompilationUnit tree : trees) { 528 if (defaultModule != syms.unnamedModule 529 && defaultModule.sourceLocation == StandardLocation.SOURCE_PATH 530 && fileManager.hasLocation(StandardLocation.SOURCE_PATH)) { 531 checkSourceLocation(tree, module); 532 } 533 tree.modle = module; 534 } 535 } 536 } 537 538 private void checkSourceLocation(JCCompilationUnit tree, ModuleSymbol msym) { 539 try { 540 JavaFileObject fo = tree.sourcefile; 541 if (fileManager.contains(msym.sourceLocation, fo)) { 542 return; 543 } 544 if (msym.patchLocation != null && fileManager.contains(msym.patchLocation, fo)) { 545 return; 546 } 547 if (fileManager.hasLocation(StandardLocation.SOURCE_OUTPUT)) { 548 if (fileManager.contains(StandardLocation.SOURCE_OUTPUT, fo)) { 549 return; 550 } 551 } else { 552 if (fileManager.contains(StandardLocation.CLASS_OUTPUT, fo)) { 553 return; 554 } 555 } 556 } catch (IOException e) { 557 throw new Error(e); 558 } 559 560 JavaFileObject prev = log.useSource(tree.sourcefile); 561 try { 562 log.error(tree.pos(), Errors.FileSbOnSourceOrPatchPathForModule); 563 } finally { 564 log.useSource(prev); 565 } 566 } 567 568 private String singleModuleOverride(List<JCCompilationUnit> trees) { 569 if (!fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) { 570 return null; 571 } 572 573 Set<String> override = new LinkedHashSet<>(); 574 for (JCCompilationUnit tree : trees) { 575 JavaFileObject fo = tree.sourcefile; 576 577 try { 578 Location loc = 579 fileManager.getLocationForModule(StandardLocation.PATCH_MODULE_PATH, fo); 580 581 if (loc != null) { 582 override.add(fileManager.inferModuleName(loc)); 583 } 584 } catch (IOException ex) { 585 throw new Error(ex); 586 } 587 } 588 589 switch (override.size()) { 590 case 0: return null; 591 case 1: return override.iterator().next(); 592 default: 593 log.error(Errors.TooManyPatchedModules(override)); 594 return null; 595 } 596 } 597 598 /** 599 * Determine the location for the module on the module source path 600 * or source output directory which contains a given CompilationUnit. 601 * If the source output directory is unset, the class output directory 602 * will be checked instead. 603 * {@code null} is returned if no such module can be found. 604 * @param tree the compilation unit tree 605 * @return the location for the enclosing module 606 * @throws IOException if there is a problem while searching for the module. 607 */ 608 private Location getModuleLocation(JCCompilationUnit tree) throws IOException { 609 JavaFileObject fo = tree.sourcefile; 610 611 Location loc = 612 fileManager.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, fo); 613 if (loc == null) { 614 Location sourceOutput = fileManager.hasLocation(StandardLocation.SOURCE_OUTPUT) ? 615 StandardLocation.SOURCE_OUTPUT : StandardLocation.CLASS_OUTPUT; 616 loc = 617 fileManager.getLocationForModule(sourceOutput, fo); 618 } 619 return loc; 620 } 621 622 private void checkNoAllModulePath() { 623 if (addModsOpt != null && Arrays.asList(addModsOpt.split(",")).contains(ALL_MODULE_PATH)) { 624 log.error(Errors.AddmodsAllModulePathInvalid); 625 } 626 } 627 628 private final Completer mainCompleter = new Completer() { 629 @Override 630 public void complete(Symbol sym) throws CompletionFailure { 631 ModuleSymbol msym = moduleFinder.findModule((ModuleSymbol) sym); 632 633 if (msym.kind == ERR) { 634 //make sure the module is initialized: 635 initErrModule(msym); 636 } else if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 637 setupAutomaticModule(msym); 638 } else { 639 try { 640 msym.module_info.complete(); 641 } catch (CompletionFailure cf) { 642 msym.kind = ERR; 643 //make sure the module is initialized: 644 initErrModule(msym); 645 completeModule(msym); 646 throw cf; 647 } 648 } 649 650 // If module-info comes from a .java file, the underlying 651 // call of classFinder.fillIn will have called through the 652 // source completer, to Enter, and then to Modules.enter, 653 // which will call completeModule. 654 // But, if module-info comes from a .class file, the underlying 655 // call of classFinder.fillIn will just call ClassReader to read 656 // the .class file, and so we call completeModule here. 657 if (msym.module_info.classfile == null || msym.module_info.classfile.getKind() == Kind.CLASS) { 658 completeModule(msym); 659 } 660 } 661 662 private void initErrModule(ModuleSymbol msym) { 663 msym.directives = List.nil(); 664 msym.exports = List.nil(); 665 msym.provides = List.nil(); 666 msym.requires = List.nil(); 667 msym.uses = List.nil(); 668 } 669 670 @Override 671 public String toString() { 672 return "mainCompleter"; 673 } 674 }; 675 676 private void setupAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 677 try { 678 ListBuffer<Directive> directives = new ListBuffer<>(); 679 ListBuffer<ExportsDirective> exports = new ListBuffer<>(); 680 Set<String> seenPackages = new HashSet<>(); 681 682 for (JavaFileObject clazz : fileManager.list(msym.classLocation, "", EnumSet.of(Kind.CLASS), true)) { 683 String binName = fileManager.inferBinaryName(msym.classLocation, clazz); 684 String pack = binName.lastIndexOf('.') != (-1) ? binName.substring(0, binName.lastIndexOf('.')) : ""; //unnamed package???? 685 if (seenPackages.add(pack)) { 686 ExportsDirective d = new ExportsDirective(syms.enterPackage(msym, names.fromString(pack)), null); 687 //TODO: opens? 688 directives.add(d); 689 exports.add(d); 690 } 691 } 692 693 msym.exports = exports.toList(); 694 msym.provides = List.nil(); 695 msym.requires = List.nil(); 696 msym.uses = List.nil(); 697 msym.directives = directives.toList(); 698 } catch (IOException ex) { 699 throw new IllegalStateException(ex); 700 } 701 } 702 703 private void completeAutomaticModule(ModuleSymbol msym) throws CompletionFailure { 704 ListBuffer<Directive> directives = new ListBuffer<>(); 705 706 directives.addAll(msym.directives); 707 708 ListBuffer<RequiresDirective> requires = new ListBuffer<>(); 709 710 for (ModuleSymbol ms : allModules()) { 711 if (ms == syms.unnamedModule || ms == msym) 712 continue; 713 Set<RequiresFlag> flags = (ms.flags_field & Flags.AUTOMATIC_MODULE) != 0 ? 714 EnumSet.of(RequiresFlag.TRANSITIVE) : EnumSet.noneOf(RequiresFlag.class); 715 RequiresDirective d = new RequiresDirective(ms, flags); 716 directives.add(d); 717 requires.add(d); 718 } 719 720 RequiresDirective requiresUnnamed = new RequiresDirective(syms.unnamedModule); 721 directives.add(requiresUnnamed); 722 requires.add(requiresUnnamed); 723 724 msym.requires = requires.toList(); 725 msym.directives = directives.toList(); 726 } 727 728 private Completer getSourceCompleter(JCCompilationUnit tree) { 729 return new Completer() { 730 @Override 731 public void complete(Symbol sym) throws CompletionFailure { 732 ModuleSymbol msym = (ModuleSymbol) sym; 733 msym.flags_field |= UNATTRIBUTED; 734 ModuleVisitor v = new ModuleVisitor(); 735 JavaFileObject prev = log.useSource(tree.sourcefile); 736 JCModuleDecl moduleDecl = tree.getModuleDecl(); 737 DiagnosticPosition prevLintPos = deferredLintHandler.setPos(moduleDecl.pos()); 738 739 try { 740 moduleDecl.accept(v); 741 completeModule(msym); 742 checkCyclicDependencies(moduleDecl); 743 } finally { 744 log.useSource(prev); 745 deferredLintHandler.setPos(prevLintPos); 746 msym.flags_field &= ~UNATTRIBUTED; 747 } 748 } 749 750 @Override 751 public String toString() { 752 return "SourceCompleter: " + tree.sourcefile.getName(); 753 } 754 755 }; 756 } 757 758 public boolean isRootModule(ModuleSymbol module) { 759 Assert.checkNonNull(rootModules); 760 return rootModules.contains(module); 761 } 762 763 public Set<ModuleSymbol> getRootModules() { 764 Assert.checkNonNull(rootModules); 765 return rootModules; 766 } 767 768 class ModuleVisitor extends JCTree.Visitor { 769 private ModuleSymbol sym; 770 private final Set<ModuleSymbol> allRequires = new HashSet<>(); 771 private final Map<PackageSymbol,List<ExportsDirective>> allExports = new HashMap<>(); 772 private final Map<PackageSymbol,List<OpensDirective>> allOpens = new HashMap<>(); 773 774 @Override 775 public void visitModuleDef(JCModuleDecl tree) { 776 sym = Assert.checkNonNull(tree.sym); 777 778 if (tree.getModuleType() == ModuleKind.OPEN) { 779 sym.flags.add(ModuleFlags.OPEN); 780 } 781 sym.flags_field |= (tree.mods.flags & Flags.DEPRECATED); 782 783 sym.requires = List.nil(); 784 sym.exports = List.nil(); 785 sym.opens = List.nil(); 786 tree.directives.forEach(t -> t.accept(this)); 787 sym.requires = sym.requires.reverse(); 788 sym.exports = sym.exports.reverse(); 789 sym.opens = sym.opens.reverse(); 790 ensureJavaBase(); 791 } 792 793 @Override 794 public void visitRequires(JCRequires tree) { 795 ModuleSymbol msym = lookupModule(tree.moduleName); 796 if (msym.kind != MDL) { 797 log.error(tree.moduleName.pos(), Errors.ModuleNotFound(msym)); 798 warnedMissing.add(msym); 799 } else if (allRequires.contains(msym)) { 800 log.error(tree.moduleName.pos(), Errors.DuplicateRequires(msym)); 801 } else { 802 allRequires.add(msym); 803 Set<RequiresFlag> flags = EnumSet.noneOf(RequiresFlag.class); 804 if (tree.isTransitive) { 805 if (msym == syms.java_base && source.compareTo(Source.JDK10) >= 0) { 806 log.error(tree.pos(), Errors.ModifierNotAllowedHere(names.transitive)); 807 } else { 808 flags.add(RequiresFlag.TRANSITIVE); 809 } 810 } 811 if (tree.isStaticPhase) { 812 if (msym == syms.java_base && source.compareTo(Source.JDK10) >= 0) { 813 log.error(tree.pos(), Errors.ModNotAllowedHere(EnumSet.of(Flag.STATIC))); 814 } else { 815 flags.add(RequiresFlag.STATIC_PHASE); 816 } 817 } 818 RequiresDirective d = new RequiresDirective(msym, flags); 819 tree.directive = d; 820 sym.requires = sym.requires.prepend(d); 821 } 822 } 823 824 @Override 825 public void visitExports(JCExports tree) { 826 Name name = TreeInfo.fullName(tree.qualid); 827 PackageSymbol packge = syms.enterPackage(sym, name); 828 attr.setPackageSymbols(tree.qualid, packge); 829 830 List<ExportsDirective> exportsForPackage = allExports.computeIfAbsent(packge, p -> List.nil()); 831 for (ExportsDirective d : exportsForPackage) { 832 reportExportsConflict(tree, packge); 833 } 834 835 List<ModuleSymbol> toModules = null; 836 if (tree.moduleNames != null) { 837 Set<ModuleSymbol> to = new LinkedHashSet<>(); 838 for (JCExpression n: tree.moduleNames) { 839 ModuleSymbol msym = lookupModule(n); 840 chk.checkModuleExists(n.pos(), msym); 841 for (ExportsDirective d : exportsForPackage) { 842 checkDuplicateExportsToModule(n, msym, d); 843 } 844 if (!to.add(msym)) { 845 reportExportsConflictToModule(n, msym); 846 } 847 } 848 toModules = List.from(to); 849 } 850 851 if (toModules == null || !toModules.isEmpty()) { 852 Set<ExportsFlag> flags = EnumSet.noneOf(ExportsFlag.class); 853 ExportsDirective d = new ExportsDirective(packge, toModules, flags); 854 sym.exports = sym.exports.prepend(d); 855 tree.directive = d; 856 857 allExports.put(packge, exportsForPackage.prepend(d)); 858 } 859 } 860 861 private void reportExportsConflict(JCExports tree, PackageSymbol packge) { 862 log.error(tree.qualid.pos(), Errors.ConflictingExports(packge)); 863 } 864 865 private void checkDuplicateExportsToModule(JCExpression name, ModuleSymbol msym, 866 ExportsDirective d) { 867 if (d.modules != null) { 868 for (ModuleSymbol other : d.modules) { 869 if (msym == other) { 870 reportExportsConflictToModule(name, msym); 871 } 872 } 873 } 874 } 875 876 private void reportExportsConflictToModule(JCExpression name, ModuleSymbol msym) { 877 log.error(name.pos(), Errors.ConflictingExportsToModule(msym)); 878 } 879 880 @Override 881 public void visitOpens(JCOpens tree) { 882 Name name = TreeInfo.fullName(tree.qualid); 883 PackageSymbol packge = syms.enterPackage(sym, name); 884 attr.setPackageSymbols(tree.qualid, packge); 885 886 if (sym.flags.contains(ModuleFlags.OPEN)) { 887 log.error(tree.pos(), Errors.NoOpensUnlessStrong); 888 } 889 List<OpensDirective> opensForPackage = allOpens.computeIfAbsent(packge, p -> List.nil()); 890 for (OpensDirective d : opensForPackage) { 891 reportOpensConflict(tree, packge); 892 } 893 894 List<ModuleSymbol> toModules = null; 895 if (tree.moduleNames != null) { 896 Set<ModuleSymbol> to = new LinkedHashSet<>(); 897 for (JCExpression n: tree.moduleNames) { 898 ModuleSymbol msym = lookupModule(n); 899 chk.checkModuleExists(n.pos(), msym); 900 for (OpensDirective d : opensForPackage) { 901 checkDuplicateOpensToModule(n, msym, d); 902 } 903 if (!to.add(msym)) { 904 reportOpensConflictToModule(n, msym); 905 } 906 } 907 toModules = List.from(to); 908 } 909 910 if (toModules == null || !toModules.isEmpty()) { 911 Set<OpensFlag> flags = EnumSet.noneOf(OpensFlag.class); 912 OpensDirective d = new OpensDirective(packge, toModules, flags); 913 sym.opens = sym.opens.prepend(d); 914 tree.directive = d; 915 916 allOpens.put(packge, opensForPackage.prepend(d)); 917 } 918 } 919 920 private void reportOpensConflict(JCOpens tree, PackageSymbol packge) { 921 log.error(tree.qualid.pos(), Errors.ConflictingOpens(packge)); 922 } 923 924 private void checkDuplicateOpensToModule(JCExpression name, ModuleSymbol msym, 925 OpensDirective d) { 926 if (d.modules != null) { 927 for (ModuleSymbol other : d.modules) { 928 if (msym == other) { 929 reportOpensConflictToModule(name, msym); 930 } 931 } 932 } 933 } 934 935 private void reportOpensConflictToModule(JCExpression name, ModuleSymbol msym) { 936 log.error(name.pos(), Errors.ConflictingOpensToModule(msym)); 937 } 938 939 @Override 940 public void visitProvides(JCProvides tree) { } 941 942 @Override 943 public void visitUses(JCUses tree) { } 944 945 private void ensureJavaBase() { 946 if (sym.name == names.java_base) 947 return; 948 949 for (RequiresDirective d: sym.requires) { 950 if (d.module.name == names.java_base) 951 return; 952 } 953 954 ModuleSymbol java_base = syms.enterModule(names.java_base); 955 Directive.RequiresDirective d = 956 new Directive.RequiresDirective(java_base, 957 EnumSet.of(Directive.RequiresFlag.MANDATED)); 958 sym.requires = sym.requires.prepend(d); 959 } 960 961 private ModuleSymbol lookupModule(JCExpression moduleName) { 962 Name name = TreeInfo.fullName(moduleName); 963 ModuleSymbol msym = moduleFinder.findModule(name); 964 TreeInfo.setSymbol(moduleName, msym); 965 return msym; 966 } 967 } 968 969 public Completer getUsesProvidesCompleter() { 970 return sym -> { 971 ModuleSymbol msym = (ModuleSymbol) sym; 972 973 msym.complete(); 974 975 Env<AttrContext> env = typeEnvs.get(msym); 976 UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env); 977 JavaFileObject prev = log.useSource(env.toplevel.sourcefile); 978 JCModuleDecl decl = env.toplevel.getModuleDecl(); 979 DiagnosticPosition prevLintPos = deferredLintHandler.setPos(decl.pos()); 980 981 try { 982 decl.accept(v); 983 } finally { 984 log.useSource(prev); 985 deferredLintHandler.setPos(prevLintPos); 986 } 987 }; 988 } 989 990 class UsesProvidesVisitor extends JCTree.Visitor { 991 private final ModuleSymbol msym; 992 private final Env<AttrContext> env; 993 994 private final Set<ClassSymbol> allUses = new HashSet<>(); 995 private final Map<ClassSymbol, Set<ClassSymbol>> allProvides = new HashMap<>(); 996 997 public UsesProvidesVisitor(ModuleSymbol msym, Env<AttrContext> env) { 998 this.msym = msym; 999 this.env = env; 1000 } 1001 1002 @Override @SuppressWarnings("unchecked") 1003 public void visitModuleDef(JCModuleDecl tree) { 1004 msym.directives = List.nil(); 1005 msym.provides = List.nil(); 1006 msym.uses = List.nil(); 1007 tree.directives.forEach(t -> t.accept(this)); 1008 msym.directives = msym.directives.reverse(); 1009 msym.provides = msym.provides.reverse(); 1010 msym.uses = msym.uses.reverse(); 1011 1012 if (msym.requires.nonEmpty() && msym.requires.head.flags.contains(RequiresFlag.MANDATED)) 1013 msym.directives = msym.directives.prepend(msym.requires.head); 1014 1015 msym.directives = msym.directives.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 1016 1017 checkForCorrectness(); 1018 } 1019 1020 @Override 1021 public void visitExports(JCExports tree) { 1022 Iterable<Symbol> packageContent = tree.directive.packge.members().getSymbols(); 1023 List<JavaFileObject> filesToCheck = List.nil(); 1024 boolean packageNotEmpty = false; 1025 for (Symbol sym : packageContent) { 1026 if (sym.kind != Kinds.Kind.TYP) 1027 continue; 1028 ClassSymbol csym = (ClassSymbol) sym; 1029 if (sym.completer.isTerminal() || 1030 csym.classfile.getKind() == Kind.CLASS) { 1031 packageNotEmpty = true; 1032 filesToCheck = List.nil(); 1033 break; 1034 } 1035 if (csym.classfile.getKind() == Kind.SOURCE) { 1036 filesToCheck = filesToCheck.prepend(csym.classfile); 1037 } 1038 } 1039 for (JavaFileObject jfo : filesToCheck) { 1040 if (findPackageInFile.findPackageNameOf(jfo) == tree.directive.packge.fullname) { 1041 packageNotEmpty = true; 1042 break; 1043 } 1044 } 1045 if (!packageNotEmpty) { 1046 log.error(tree.qualid.pos(), Errors.PackageEmptyOrNotFound(tree.directive.packge)); 1047 } 1048 msym.directives = msym.directives.prepend(tree.directive); 1049 } 1050 1051 @Override 1052 public void visitOpens(JCOpens tree) { 1053 chk.checkPackageExistsForOpens(tree.qualid, tree.directive.packge); 1054 msym.directives = msym.directives.prepend(tree.directive); 1055 } 1056 1057 MethodSymbol noArgsConstructor(ClassSymbol tsym) { 1058 Name constructorName = tsym.isConcreteValueClass() ? names.vnew : names.init; 1059 for (Symbol sym : tsym.members().getSymbolsByName(constructorName)) { 1060 MethodSymbol mSym = (MethodSymbol)sym; 1061 if (mSym.params().isEmpty()) { 1062 return mSym; 1063 } 1064 } 1065 return null; 1066 } 1067 1068 MethodSymbol factoryMethod(ClassSymbol tsym) { 1069 for (Symbol sym : tsym.members().getSymbolsByName(names.provider, sym -> sym.kind == MTH)) { 1070 MethodSymbol mSym = (MethodSymbol)sym; 1071 if (mSym.isStatic() && (mSym.flags() & Flags.PUBLIC) != 0 && mSym.params().isEmpty()) { 1072 return mSym; 1073 } 1074 } 1075 return null; 1076 } 1077 1078 Map<Directive.ProvidesDirective, JCProvides> directiveToTreeMap = new HashMap<>(); 1079 1080 @Override 1081 public void visitProvides(JCProvides tree) { 1082 Type st = attr.attribType(tree.serviceName, env, syms.objectType); 1083 ClassSymbol service = (ClassSymbol) st.tsym; 1084 if (allProvides.containsKey(service)) { 1085 log.error(tree.serviceName.pos(), Errors.RepeatedProvidesForService(service)); 1086 } 1087 ListBuffer<ClassSymbol> impls = new ListBuffer<>(); 1088 for (JCExpression implName : tree.implNames) { 1089 Type it; 1090 boolean prevVisitingServiceImplementation = env.info.visitingServiceImplementation; 1091 try { 1092 env.info.visitingServiceImplementation = true; 1093 it = attr.attribType(implName, env, syms.objectType); 1094 } finally { 1095 env.info.visitingServiceImplementation = prevVisitingServiceImplementation; 1096 } 1097 ClassSymbol impl = (ClassSymbol) it.tsym; 1098 if ((impl.flags_field & PUBLIC) == 0) { 1099 log.error(implName.pos(), Errors.NotDefPublic(impl, impl.location())); 1100 } 1101 //find provider factory: 1102 MethodSymbol factory = factoryMethod(impl); 1103 if (factory != null) { 1104 Type returnType = factory.type.getReturnType(); 1105 if (!types.isSubtype(returnType, st)) { 1106 log.error(implName.pos(), Errors.ServiceImplementationProviderReturnMustBeSubtypeOfServiceInterface); 1107 } 1108 } else { 1109 if (!types.isSubtype(it, st)) { 1110 log.error(implName.pos(), Errors.ServiceImplementationMustBeSubtypeOfServiceInterface); 1111 } else if ((impl.flags() & ABSTRACT) != 0) { 1112 log.error(implName.pos(), Errors.ServiceImplementationIsAbstract(impl)); 1113 } else if (impl.isInner()) { 1114 log.error(implName.pos(), Errors.ServiceImplementationIsInner(impl)); 1115 } else { 1116 MethodSymbol constr = noArgsConstructor(impl); 1117 if (constr == null) { 1118 log.error(implName.pos(), Errors.ServiceImplementationDoesntHaveANoArgsConstructor(impl)); 1119 } else if ((constr.flags() & PUBLIC) == 0) { 1120 log.error(implName.pos(), Errors.ServiceImplementationNoArgsConstructorNotPublic(impl)); 1121 } 1122 } 1123 } 1124 if (it.hasTag(CLASS)) { 1125 if (allProvides.computeIfAbsent(service, s -> new HashSet<>()).add(impl)) { 1126 impls.append(impl); 1127 } else { 1128 log.error(implName.pos(), Errors.DuplicateProvides(service, impl)); 1129 } 1130 } 1131 } 1132 if (st.hasTag(CLASS) && !impls.isEmpty()) { 1133 Directive.ProvidesDirective d = new Directive.ProvidesDirective(service, impls.toList()); 1134 msym.provides = msym.provides.prepend(d); 1135 msym.directives = msym.directives.prepend(d); 1136 directiveToTreeMap.put(d, tree); 1137 } 1138 } 1139 1140 @Override 1141 public void visitRequires(JCRequires tree) { 1142 if (tree.directive != null && allModules().contains(tree.directive.module)) { 1143 chk.checkDeprecated(tree.moduleName.pos(), msym, tree.directive.module); 1144 chk.checkPreview(tree.moduleName.pos(), msym, tree.directive.module); 1145 chk.checkModuleRequires(tree.moduleName.pos(), tree.directive); 1146 msym.directives = msym.directives.prepend(tree.directive); 1147 } 1148 } 1149 1150 @Override 1151 public void visitUses(JCUses tree) { 1152 Type st = attr.attribType(tree.qualid, env, syms.objectType); 1153 Symbol sym = TreeInfo.symbol(tree.qualid); 1154 if ((sym.flags() & ENUM) != 0) { 1155 log.error(tree.qualid.pos(), Errors.ServiceDefinitionIsEnum(st.tsym)); 1156 } else if (st.hasTag(CLASS)) { 1157 ClassSymbol service = (ClassSymbol) st.tsym; 1158 if (allUses.add(service)) { 1159 Directive.UsesDirective d = new Directive.UsesDirective(service); 1160 msym.uses = msym.uses.prepend(d); 1161 msym.directives = msym.directives.prepend(d); 1162 } else { 1163 log.error(tree.pos(), Errors.DuplicateUses(service)); 1164 } 1165 } 1166 } 1167 1168 private void checkForCorrectness() { 1169 for (Directive.ProvidesDirective provides : msym.provides) { 1170 JCProvides tree = directiveToTreeMap.get(provides); 1171 for (ClassSymbol impl : provides.impls) { 1172 /* The implementation must be defined in the same module as the provides directive 1173 * (else, error) 1174 */ 1175 PackageSymbol implementationDefiningPackage = impl.packge(); 1176 if (implementationDefiningPackage.modle != msym) { 1177 // TODO: should use tree for the implementation name, not the entire provides tree 1178 // TODO: should improve error message to identify the implementation type 1179 log.error(tree.pos(), Errors.ServiceImplementationNotInRightModule(implementationDefiningPackage.modle)); 1180 } 1181 1182 /* There is no inherent requirement that module that provides a service should actually 1183 * use it itself. However, it is a pointless declaration if the service package is not 1184 * exported and there is no uses for the service. 1185 */ 1186 PackageSymbol interfaceDeclaringPackage = provides.service.packge(); 1187 boolean isInterfaceDeclaredInCurrentModule = interfaceDeclaringPackage.modle == msym; 1188 boolean isInterfaceExportedFromAReadableModule = 1189 msym.visiblePackages.get(interfaceDeclaringPackage.fullname) == interfaceDeclaringPackage; 1190 if (isInterfaceDeclaredInCurrentModule && !isInterfaceExportedFromAReadableModule) { 1191 // ok the interface is declared in this module. Let's check if it's exported 1192 boolean warn = true; 1193 for (ExportsDirective export : msym.exports) { 1194 if (interfaceDeclaringPackage == export.packge) { 1195 warn = false; 1196 break; 1197 } 1198 } 1199 if (warn) { 1200 for (UsesDirective uses : msym.uses) { 1201 if (provides.service == uses.service) { 1202 warn = false; 1203 break; 1204 } 1205 } 1206 } 1207 if (warn) { 1208 log.warning(tree.pos(), Warnings.ServiceProvidedButNotExportedOrUsed(provides.service)); 1209 } 1210 } 1211 } 1212 } 1213 } 1214 } 1215 1216 private Set<ModuleSymbol> allModules; 1217 1218 public Set<ModuleSymbol> allModules() { 1219 Assert.checkNonNull(allModules); 1220 return allModules; 1221 } 1222 1223 private void setupAllModules() { 1224 Assert.checkNonNull(rootModules); 1225 Assert.checkNull(allModules); 1226 1227 //java.base may not be completed yet and computeTransitiveClosure 1228 //may not complete it either, make sure it is completed: 1229 syms.java_base.complete(); 1230 1231 Set<ModuleSymbol> observable; 1232 1233 if (limitModsOpt == null && extraLimitMods.isEmpty()) { 1234 observable = null; 1235 } else { 1236 Set<ModuleSymbol> limitMods = new HashSet<>(); 1237 if (limitModsOpt != null) { 1238 for (String limit : limitModsOpt.split(",")) { 1239 if (!isValidName(limit)) 1240 continue; 1241 limitMods.add(syms.enterModule(names.fromString(limit))); 1242 } 1243 } 1244 for (String limit : extraLimitMods) { 1245 limitMods.add(syms.enterModule(names.fromString(limit))); 1246 } 1247 observable = computeTransitiveClosure(limitMods, rootModules, null); 1248 observable.addAll(rootModules); 1249 if (lintOptions) { 1250 for (ModuleSymbol msym : limitMods) { 1251 if (!observable.contains(msym)) { 1252 log.warning(LintCategory.OPTIONS, 1253 Warnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym)); 1254 } 1255 } 1256 } 1257 } 1258 1259 Predicate<ModuleSymbol> observablePred = sym -> 1260 (observable == null) ? (moduleFinder.findModule(sym).kind != ERR) : observable.contains(sym); 1261 Predicate<ModuleSymbol> systemModulePred = sym -> (sym.flags() & Flags.SYSTEM_MODULE) != 0; 1262 Set<ModuleSymbol> enabledRoot = new LinkedHashSet<>(); 1263 1264 if (rootModules.contains(syms.unnamedModule)) { 1265 Predicate<ModuleSymbol> jdkModulePred; 1266 if (target.allApiModulesAreRoots()) { 1267 jdkModulePred = sym -> { 1268 sym.complete(); 1269 return sym.exports.stream().anyMatch(e -> e.modules == null); 1270 }; 1271 } else { 1272 ModuleSymbol javaSE = syms.getModule(java_se); 1273 if (javaSE != null && (observable == null || observable.contains(javaSE))) { 1274 jdkModulePred = sym -> { 1275 sym.complete(); 1276 return !sym.name.startsWith(java_) 1277 && sym.exports.stream().anyMatch(e -> e.modules == null); 1278 }; 1279 enabledRoot.add(javaSE); 1280 } else { 1281 jdkModulePred = sym -> true; 1282 } 1283 } 1284 1285 Predicate<ModuleSymbol> noIncubatorPred = sym -> { 1286 sym.complete(); 1287 return !sym.resolutionFlags.contains(ModuleResolutionFlags.DO_NOT_RESOLVE_BY_DEFAULT); 1288 }; 1289 1290 for (ModuleSymbol sym : new HashSet<>(syms.getAllModules())) { 1291 try { 1292 if (systemModulePred.test(sym) && observablePred.test(sym) && jdkModulePred.test(sym) && noIncubatorPred.test(sym)) { 1293 enabledRoot.add(sym); 1294 } 1295 } catch (CompletionFailure ex) { 1296 chk.completionError(null, ex); 1297 } 1298 } 1299 } 1300 1301 enabledRoot.addAll(rootModules); 1302 1303 if (addModsOpt != null || !extraAddMods.isEmpty()) { 1304 Set<String> fullAddMods = new HashSet<>(); 1305 fullAddMods.addAll(extraAddMods); 1306 1307 if (addModsOpt != null) { 1308 fullAddMods.addAll(Arrays.asList(addModsOpt.split(","))); 1309 } 1310 1311 for (String added : fullAddMods) { 1312 Stream<ModuleSymbol> modules; 1313 switch (added) { 1314 case ALL_SYSTEM: 1315 modules = new HashSet<>(syms.getAllModules()) 1316 .stream() 1317 .filter(systemModulePred.and(observablePred)); 1318 break; 1319 case ALL_MODULE_PATH: 1320 modules = new HashSet<>(syms.getAllModules()) 1321 .stream() 1322 .filter(systemModulePred.negate().and(observablePred)); 1323 break; 1324 default: 1325 if (!isValidName(added)) 1326 continue; 1327 modules = Stream.of(syms.enterModule(names.fromString(added))); 1328 break; 1329 } 1330 modules.forEach(sym -> { 1331 enabledRoot.add(sym); 1332 if (observable != null) 1333 observable.add(sym); 1334 }); 1335 } 1336 } 1337 1338 Set<ModuleSymbol> result = computeTransitiveClosure(enabledRoot, rootModules, observable); 1339 1340 result.add(syms.unnamedModule); 1341 1342 boolean hasAutomatic = result.stream().anyMatch(IS_AUTOMATIC); 1343 1344 if (hasAutomatic) { 1345 syms.getAllModules() 1346 .stream() 1347 .filter(IS_AUTOMATIC) 1348 .forEach(result::add); 1349 } 1350 1351 String incubatingModules = filterAlreadyWarnedIncubatorModules(result.stream() 1352 .filter(msym -> msym.resolutionFlags.contains(ModuleResolutionFlags.WARN_INCUBATING)) 1353 .map(msym -> msym.name.toString())) 1354 .collect(Collectors.joining(",")); 1355 1356 if (!incubatingModules.isEmpty()) { 1357 log.warning(Warnings.IncubatingModules(incubatingModules)); 1358 } 1359 1360 allModules = result; 1361 1362 //add module versions from options, if any: 1363 if (moduleVersionOpt != null) { 1364 Name version = names.fromString(moduleVersionOpt); 1365 rootModules.forEach(m -> m.version = version); 1366 } 1367 } 1368 //where: 1369 private Stream<String> filterAlreadyWarnedIncubatorModules(Stream<String> incubatingModules) { 1370 if (!sourceLauncher) return incubatingModules; 1371 Set<String> bootModules = ModuleLayer.boot() 1372 .modules() 1373 .stream() 1374 .map(Module::getName) 1375 .collect(Collectors.toSet()); 1376 return incubatingModules.filter(module -> !bootModules.contains(module)); 1377 } 1378 private static final Predicate<ModuleSymbol> IS_AUTOMATIC = 1379 m -> (m.flags_field & Flags.AUTOMATIC_MODULE) != 0; 1380 1381 public boolean isInModuleGraph(ModuleSymbol msym) { 1382 return allModules == null || allModules.contains(msym); 1383 } 1384 1385 private Set<ModuleSymbol> computeTransitiveClosure(Set<? extends ModuleSymbol> base, 1386 Set<? extends ModuleSymbol> rootModules, 1387 Set<ModuleSymbol> observable) { 1388 List<ModuleSymbol> primaryTodo = List.nil(); 1389 List<ModuleSymbol> secondaryTodo = List.nil(); 1390 1391 for (ModuleSymbol ms : base) { 1392 if (rootModules.contains(ms)) { 1393 primaryTodo = primaryTodo.prepend(ms); 1394 } else { 1395 secondaryTodo = secondaryTodo.prepend(ms); 1396 } 1397 } 1398 1399 Set<ModuleSymbol> result = new LinkedHashSet<>(); 1400 result.add(syms.java_base); 1401 1402 while (primaryTodo.nonEmpty() || secondaryTodo.nonEmpty()) { 1403 try { 1404 ModuleSymbol current; 1405 boolean isPrimaryTodo; 1406 if (primaryTodo.nonEmpty()) { 1407 current = primaryTodo.head; 1408 primaryTodo = primaryTodo.tail; 1409 isPrimaryTodo = true; 1410 } else { 1411 current = secondaryTodo.head; 1412 secondaryTodo = secondaryTodo.tail; 1413 isPrimaryTodo = false; 1414 } 1415 if (observable != null && !observable.contains(current)) 1416 continue; 1417 if (!result.add(current) || current == syms.unnamedModule || ((current.flags_field & Flags.AUTOMATIC_MODULE) != 0)) 1418 continue; 1419 current.complete(); 1420 if (current.kind == ERR && (isPrimaryTodo || base.contains(current)) && warnedMissing.add(current)) { 1421 log.error(Errors.ModuleNotFound(current)); 1422 } 1423 for (RequiresDirective rd : current.requires) { 1424 if (rd.module == syms.java_base) continue; 1425 if ((rd.isTransitive() && isPrimaryTodo) || rootModules.contains(current)) { 1426 primaryTodo = primaryTodo.prepend(rd.module); 1427 } else { 1428 secondaryTodo = secondaryTodo.prepend(rd.module); 1429 } 1430 } 1431 } catch (CompletionFailure ex) { 1432 chk.completionError(null, ex); 1433 } 1434 } 1435 1436 return result; 1437 } 1438 1439 public ModuleSymbol getObservableModule(Name name) { 1440 ModuleSymbol mod = syms.getModule(name); 1441 1442 if (allModules().contains(mod)) { 1443 return mod; 1444 } 1445 1446 return null; 1447 } 1448 1449 private Completer getUnnamedModuleCompleter() { 1450 moduleFinder.findAllModules(); 1451 return new Symbol.Completer() { 1452 @Override 1453 public void complete(Symbol sym) throws CompletionFailure { 1454 if (inInitModules) { 1455 sym.completer = this; 1456 return ; 1457 } 1458 ModuleSymbol msym = (ModuleSymbol) sym; 1459 Set<ModuleSymbol> allModules = new HashSet<>(allModules()); 1460 allModules.remove(syms.unnamedModule); 1461 for (ModuleSymbol m : allModules) { 1462 m.complete(); 1463 } 1464 initVisiblePackages(msym, allModules); 1465 } 1466 1467 @Override 1468 public String toString() { 1469 return "unnamedModule Completer"; 1470 } 1471 }; 1472 } 1473 1474 private final Map<ModuleSymbol, Set<ModuleSymbol>> requiresTransitiveCache = new HashMap<>(); 1475 1476 private void completeModule(ModuleSymbol msym) { 1477 if (inInitModules) { 1478 msym.completer = sym -> completeModule(msym); 1479 return ; 1480 } 1481 1482 if ((msym.flags_field & Flags.AUTOMATIC_MODULE) != 0) { 1483 completeAutomaticModule(msym); 1484 } 1485 1486 Assert.checkNonNull(msym.requires); 1487 1488 initAddReads(); 1489 1490 msym.requires = msym.requires.appendList(List.from(addReads.getOrDefault(msym, Collections.emptySet()))); 1491 1492 List<RequiresDirective> requires = msym.requires; 1493 1494 while (requires.nonEmpty()) { 1495 if (!allModules().contains(requires.head.module)) { 1496 Env<AttrContext> env = typeEnvs.get(msym); 1497 if (env != null) { 1498 JavaFileObject origSource = log.useSource(env.toplevel.sourcefile); 1499 try { 1500 log.error(/*XXX*/env.tree, Errors.ModuleNotFound(requires.head.module)); 1501 } finally { 1502 log.useSource(origSource); 1503 } 1504 } else { 1505 Assert.check((msym.flags() & Flags.AUTOMATIC_MODULE) == 0); 1506 } 1507 msym.requires = List.filter(msym.requires, requires.head); 1508 } 1509 requires = requires.tail; 1510 } 1511 1512 Set<ModuleSymbol> readable = new LinkedHashSet<>(); 1513 Set<ModuleSymbol> requiresTransitive = new HashSet<>(); 1514 1515 for (RequiresDirective d : msym.requires) { 1516 d.module.complete(); 1517 readable.add(d.module); 1518 Set<ModuleSymbol> s = retrieveRequiresTransitive(d.module); 1519 Assert.checkNonNull(s, () -> "no entry in cache for " + d.module); 1520 readable.addAll(s); 1521 if (d.flags.contains(RequiresFlag.TRANSITIVE)) { 1522 requiresTransitive.add(d.module); 1523 requiresTransitive.addAll(s); 1524 } 1525 } 1526 1527 requiresTransitiveCache.put(msym, requiresTransitive); 1528 initVisiblePackages(msym, readable); 1529 for (ExportsDirective d: msym.exports) { 1530 if (d.packge != null) { 1531 d.packge.modle = msym; 1532 } 1533 } 1534 } 1535 1536 private Set<ModuleSymbol> retrieveRequiresTransitive(ModuleSymbol msym) { 1537 Set<ModuleSymbol> requiresTransitive = requiresTransitiveCache.get(msym); 1538 1539 if (requiresTransitive == null) { 1540 //the module graph may contain cycles involving automatic modules or --add-reads edges 1541 requiresTransitive = new HashSet<>(); 1542 1543 Set<ModuleSymbol> seen = new HashSet<>(); 1544 List<ModuleSymbol> todo = List.of(msym); 1545 1546 while (todo.nonEmpty()) { 1547 ModuleSymbol current = todo.head; 1548 todo = todo.tail; 1549 if (!seen.add(current)) 1550 continue; 1551 requiresTransitive.add(current); 1552 current.complete(); 1553 Iterable<? extends RequiresDirective> requires; 1554 if (current != syms.unnamedModule) { 1555 Assert.checkNonNull(current.requires, () -> current + ".requires == null; " + msym); 1556 requires = current.requires; 1557 for (RequiresDirective rd : requires) { 1558 if (rd.isTransitive()) 1559 todo = todo.prepend(rd.module); 1560 } 1561 } else { 1562 for (ModuleSymbol mod : allModules()) { 1563 todo = todo.prepend(mod); 1564 } 1565 } 1566 } 1567 1568 requiresTransitive.remove(msym); 1569 } 1570 1571 return requiresTransitive; 1572 } 1573 1574 private void initVisiblePackages(ModuleSymbol msym, Collection<ModuleSymbol> readable) { 1575 initAddExports(); 1576 1577 msym.visiblePackages = new LinkedHashMap<>(); 1578 msym.readModules = new HashSet<>(readable); 1579 1580 Map<Name, ModuleSymbol> seen = new HashMap<>(); 1581 1582 for (ModuleSymbol rm : readable) { 1583 if (rm == syms.unnamedModule) 1584 continue; 1585 addVisiblePackages(msym, seen, rm, rm.exports); 1586 } 1587 1588 addExports.forEach((exportsFrom, exports) -> { 1589 if (msym.readModules.contains(exportsFrom)) { 1590 addVisiblePackages(msym, seen, exportsFrom, exports); 1591 } 1592 }); 1593 } 1594 1595 private void addVisiblePackages(ModuleSymbol msym, 1596 Map<Name, ModuleSymbol> seenPackages, 1597 ModuleSymbol exportsFrom, 1598 Collection<ExportsDirective> exports) { 1599 for (ExportsDirective d : exports) { 1600 if (d.modules == null || d.modules.contains(msym)) { 1601 Name packageName = d.packge.fullname; 1602 ModuleSymbol previousModule = seenPackages.get(packageName); 1603 1604 if (previousModule != null && previousModule != exportsFrom) { 1605 Env<AttrContext> env = typeEnvs.get(msym); 1606 JavaFileObject origSource = env != null ? log.useSource(env.toplevel.sourcefile) 1607 : null; 1608 DiagnosticPosition pos = env != null ? env.tree.pos() : null; 1609 try { 1610 if (msym.isUnnamed()) { 1611 log.error(pos, Errors.PackageClashFromRequiresInUnnamed(packageName, 1612 previousModule, exportsFrom)); 1613 } else { 1614 log.error(pos, Errors.PackageClashFromRequires(msym, packageName, 1615 previousModule, exportsFrom)); 1616 } 1617 } finally { 1618 if (env != null) 1619 log.useSource(origSource); 1620 } 1621 continue; 1622 } 1623 1624 seenPackages.put(packageName, exportsFrom); 1625 msym.visiblePackages.put(d.packge.fullname, d.packge); 1626 } 1627 } 1628 } 1629 1630 private void initAddExports() { 1631 if (addExports != null) 1632 return; 1633 1634 addExports = new LinkedHashMap<>(); 1635 Set<ModuleSymbol> unknownModules = new HashSet<>(); 1636 1637 if (addExportsOpt == null) 1638 return; 1639 1640 Pattern ep = Pattern.compile("([^/]+)/([^=]+)=(.*)"); 1641 for (String s: addExportsOpt.split("\0+")) { 1642 if (s.isEmpty()) 1643 continue; 1644 Matcher em = ep.matcher(s); 1645 if (!em.matches()) { 1646 continue; 1647 } 1648 1649 // Terminology comes from 1650 // --add-exports module/package=target,... 1651 // Compare to 1652 // module module { exports package to target, ... } 1653 String moduleName = em.group(1); 1654 String packageName = em.group(2); 1655 String targetNames = em.group(3); 1656 1657 if (!isValidName(moduleName)) 1658 continue; 1659 1660 ModuleSymbol msym = syms.enterModule(names.fromString(moduleName)); 1661 if (!isKnownModule(msym, unknownModules)) 1662 continue; 1663 1664 if (!isValidName(packageName)) 1665 continue; 1666 1667 if (!allowAccessIntoSystem && (msym.flags() & Flags.SYSTEM_MODULE) != 0) { 1668 log.error(Errors.AddExportsWithRelease(msym)); 1669 continue; 1670 } 1671 1672 PackageSymbol p = syms.enterPackage(msym, names.fromString(packageName)); 1673 p.modle = msym; // TODO: do we need this? 1674 1675 List<ModuleSymbol> targetModules = List.nil(); 1676 for (String toModule : targetNames.split("[ ,]+")) { 1677 ModuleSymbol m; 1678 if (toModule.equals("ALL-UNNAMED")) { 1679 m = syms.unnamedModule; 1680 } else { 1681 if (!isValidName(toModule)) 1682 continue; 1683 m = syms.enterModule(names.fromString(toModule)); 1684 if (!isKnownModule(m, unknownModules)) 1685 continue; 1686 } 1687 targetModules = targetModules.prepend(m); 1688 } 1689 1690 Set<ExportsDirective> extra = addExports.computeIfAbsent(msym, _x -> new LinkedHashSet<>()); 1691 ExportsDirective d = new ExportsDirective(p, targetModules); 1692 extra.add(d); 1693 } 1694 } 1695 1696 private boolean isKnownModule(ModuleSymbol msym, Set<ModuleSymbol> unknownModules) { 1697 if (allModules.contains(msym)) { 1698 return true; 1699 } 1700 1701 if (!unknownModules.contains(msym)) { 1702 if (lintOptions) { 1703 log.warning(LintCategory.OPTIONS, 1704 Warnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym)); 1705 } 1706 unknownModules.add(msym); 1707 } 1708 return false; 1709 } 1710 1711 private void initAddReads() { 1712 if (addReads != null) 1713 return; 1714 1715 addReads = new LinkedHashMap<>(); 1716 1717 if (addReadsOpt == null) 1718 return; 1719 1720 Pattern rp = Pattern.compile("([^=]+)=(.*)"); 1721 for (String s : addReadsOpt.split("\0+")) { 1722 if (s.isEmpty()) 1723 continue; 1724 Matcher rm = rp.matcher(s); 1725 if (!rm.matches()) { 1726 continue; 1727 } 1728 1729 // Terminology comes from 1730 // --add-reads source-module=target-module,... 1731 // Compare to 1732 // module source-module { requires target-module; ... } 1733 String sourceName = rm.group(1); 1734 String targetNames = rm.group(2); 1735 1736 if (!isValidName(sourceName)) 1737 continue; 1738 1739 ModuleSymbol msym = syms.enterModule(names.fromString(sourceName)); 1740 if (!allModules.contains(msym)) { 1741 if (lintOptions) { 1742 log.warning(Warnings.ModuleForOptionNotFound(Option.ADD_READS, msym)); 1743 } 1744 continue; 1745 } 1746 1747 if (!allowAccessIntoSystem && (msym.flags() & Flags.SYSTEM_MODULE) != 0) { 1748 log.error(Errors.AddReadsWithRelease(msym)); 1749 continue; 1750 } 1751 1752 for (String targetName : targetNames.split("[ ,]+", -1)) { 1753 ModuleSymbol targetModule; 1754 if (targetName.equals("ALL-UNNAMED")) { 1755 targetModule = syms.unnamedModule; 1756 } else { 1757 if (!isValidName(targetName)) 1758 continue; 1759 targetModule = syms.enterModule(names.fromString(targetName)); 1760 if (!allModules.contains(targetModule)) { 1761 if (lintOptions) { 1762 log.warning(LintCategory.OPTIONS, Warnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule)); 1763 } 1764 continue; 1765 } 1766 } 1767 addReads.computeIfAbsent(msym, m -> new HashSet<>()) 1768 .add(new RequiresDirective(targetModule, EnumSet.of(RequiresFlag.EXTRA))); 1769 } 1770 } 1771 } 1772 1773 private void checkCyclicDependencies(JCModuleDecl mod) { 1774 for (JCDirective d : mod.directives) { 1775 JCRequires rd; 1776 if (!d.hasTag(Tag.REQUIRES) || (rd = (JCRequires) d).directive == null) 1777 continue; 1778 Set<ModuleSymbol> nonSyntheticDeps = new HashSet<>(); 1779 List<ModuleSymbol> queue = List.of(rd.directive.module); 1780 while (queue.nonEmpty()) { 1781 ModuleSymbol current = queue.head; 1782 queue = queue.tail; 1783 if (!nonSyntheticDeps.add(current)) 1784 continue; 1785 current.complete(); 1786 if ((current.flags() & Flags.AUTOMATIC_MODULE) != 0) 1787 continue; 1788 Assert.checkNonNull(current.requires, current::toString); 1789 for (RequiresDirective dep : current.requires) { 1790 if (!dep.flags.contains(RequiresFlag.EXTRA)) 1791 queue = queue.prepend(dep.module); 1792 } 1793 } 1794 if (nonSyntheticDeps.contains(mod.sym)) { 1795 log.error(rd.moduleName.pos(), Errors.CyclicRequires(rd.directive.module)); 1796 } 1797 } 1798 } 1799 1800 private boolean isValidName(CharSequence name) { 1801 return SourceVersion.isName(name, Source.toSourceVersion(source)); 1802 } 1803 1804 // DEBUG 1805 private String toString(ModuleSymbol msym) { 1806 return msym.name + "[" 1807 + "kind:" + msym.kind + ";" 1808 + "locn:" + toString(msym.sourceLocation) + "," + toString(msym.classLocation) + ";" 1809 + "info:" + toString(msym.module_info.sourcefile) + "," 1810 + toString(msym.module_info.classfile) + "," 1811 + msym.module_info.completer 1812 + "]"; 1813 } 1814 1815 // DEBUG 1816 String toString(Location locn) { 1817 return (locn == null) ? "--" : locn.getName(); 1818 } 1819 1820 // DEBUG 1821 String toString(JavaFileObject fo) { 1822 return (fo == null) ? "--" : fo.getName(); 1823 } 1824 1825 public void newRound() { 1826 allModules = null; 1827 rootModules = null; 1828 defaultModule = null; 1829 warnedMissing.clear(); 1830 } 1831 1832 public interface PackageNameFinder { 1833 public Name findPackageNameOf(JavaFileObject jfo); 1834 } 1835 }