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