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