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