1 /* 2 * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.code; 27 28 import java.io.IOException; 29 import java.nio.file.Path; 30 import java.util.EnumSet; 31 import java.util.HashMap; 32 import java.util.Iterator; 33 import java.util.Map; 34 import java.util.NoSuchElementException; 35 import java.util.Set; 36 37 import javax.lang.model.SourceVersion; 38 import javax.tools.JavaFileManager; 39 import javax.tools.JavaFileManager.Location; 40 import javax.tools.JavaFileObject; 41 import javax.tools.JavaFileObject.Kind; 42 import javax.tools.StandardJavaFileManager; 43 import javax.tools.StandardLocation; 44 45 import com.sun.tools.javac.code.Scope.WriteableScope; 46 import com.sun.tools.javac.code.Symbol.ClassSymbol; 47 import com.sun.tools.javac.code.Symbol.Completer; 48 import com.sun.tools.javac.code.Symbol.CompletionFailure; 49 import com.sun.tools.javac.code.Symbol.ModuleSymbol; 50 import com.sun.tools.javac.code.Symbol.PackageSymbol; 51 import com.sun.tools.javac.code.Symbol.TypeSymbol; 52 import com.sun.tools.javac.comp.Annotate; 53 import com.sun.tools.javac.file.JRTIndex; 54 import com.sun.tools.javac.file.JavacFileManager; 55 import com.sun.tools.javac.jvm.ClassReader; 56 import com.sun.tools.javac.jvm.Profile; 57 import com.sun.tools.javac.main.Option; 58 import com.sun.tools.javac.platform.PlatformDescription; 59 import com.sun.tools.javac.resources.CompilerProperties.Fragments; 60 import com.sun.tools.javac.util.*; 61 62 import static javax.tools.StandardLocation.*; 63 64 import static com.sun.tools.javac.code.Flags.*; 65 import static com.sun.tools.javac.code.Kinds.Kind.*; 66 import com.sun.tools.javac.code.Symbol; 67 import com.sun.tools.javac.code.Symbol.CompletionFailure; 68 import com.sun.tools.javac.main.DelegatingJavaFileManager; 69 70 import com.sun.tools.javac.util.Dependencies.CompletionCause; 71 72 /** 73 * This class provides operations to locate class definitions 74 * from the source and class files on the paths provided to javac. 75 * 76 * <p><b>This is NOT part of any supported API. 77 * If you write code that depends on this, you do so at your own risk. 78 * This code and its internal interfaces are subject to change or 79 * deletion without notice.</b> 80 */ 81 public class ClassFinder { 82 /** The context key for the class finder. */ 83 protected static final Context.Key<ClassFinder> classFinderKey = new Context.Key<>(); 84 85 ClassReader reader; 86 87 private final Annotate annotate; 88 89 /** Switch: verbose output. 90 */ 91 boolean verbose; 92 93 /** 94 * Switch: cache completion failures unless -XDdev is used 95 */ 96 private boolean cacheCompletionFailure; 97 98 /** 99 * Switch: prefer source files instead of newer when both source 100 * and class are available 101 **/ 102 protected boolean preferSource; 103 104 /** 105 * Switch: Search classpath and sourcepath for classes before the 106 * bootclasspath 107 */ 108 protected boolean userPathsFirst; 109 110 /** The log to use for verbose output 111 */ 112 final Log log; 113 114 /** The symbol table. */ 115 Symtab syms; 116 117 /** The name table. */ 118 final Names names; 119 120 /** Force a completion failure on this name 121 */ 122 final Name completionFailureName; 123 124 /** Access to files 125 */ 126 private final JavaFileManager fileManager; 127 128 /** Dependency tracker 129 */ 130 private final Dependencies dependencies; 131 132 /** Factory for diagnostics 133 */ 134 JCDiagnostic.Factory diagFactory; 135 136 final DeferredCompletionFailureHandler dcfh; 137 138 /** Can be reassigned from outside: 139 * the completer to be used for ".java" files. If this remains unassigned 140 * ".java" files will not be loaded. 141 */ 142 public Completer sourceCompleter = Completer.NULL_COMPLETER; 143 144 /** The path name of the class file currently being read. 145 */ 146 protected JavaFileObject currentClassFile = null; 147 148 /** The class or method currently being read. 149 */ 150 protected Symbol currentOwner = null; 151 152 /** 153 * The currently selected profile. 154 */ 155 private final Profile profile; 156 157 /** 158 * Use direct access to the JRTIndex to access the temporary 159 * replacement for the info that used to be in ct.sym. 160 * In time, this will go away and be replaced by the module system. 161 */ 162 private final JRTIndex jrtIndex; 163 164 /** 165 * Completer that delegates to the complete-method of this class. 166 */ 167 private final Completer thisCompleter = this::complete; 168 getCompleter()169 public Completer getCompleter() { 170 return thisCompleter; 171 } 172 173 /** Get the ClassFinder instance for this invocation. */ instance(Context context)174 public static ClassFinder instance(Context context) { 175 ClassFinder instance = context.get(classFinderKey); 176 if (instance == null) 177 instance = new ClassFinder(context); 178 return instance; 179 } 180 181 /** Construct a new class finder. */ ClassFinder(Context context)182 protected ClassFinder(Context context) { 183 context.put(classFinderKey, this); 184 reader = ClassReader.instance(context); 185 names = Names.instance(context); 186 syms = Symtab.instance(context); 187 fileManager = context.get(JavaFileManager.class); 188 dependencies = Dependencies.instance(context); 189 if (fileManager == null) 190 throw new AssertionError("FileManager initialization error"); 191 diagFactory = JCDiagnostic.Factory.instance(context); 192 dcfh = DeferredCompletionFailureHandler.instance(context); 193 194 log = Log.instance(context); 195 annotate = Annotate.instance(context); 196 197 Options options = Options.instance(context); 198 verbose = options.isSet(Option.VERBOSE); 199 cacheCompletionFailure = options.isUnset("dev"); 200 preferSource = "source".equals(options.get("-Xprefer")); 201 userPathsFirst = options.isSet(Option.XXUSERPATHSFIRST); 202 203 completionFailureName = 204 options.isSet("failcomplete") 205 ? names.fromString(options.get("failcomplete")) 206 : null; 207 208 // Temporary, until more info is available from the module system. 209 boolean useCtProps; 210 JavaFileManager fm = context.get(JavaFileManager.class); 211 if (fm instanceof DelegatingJavaFileManager) { 212 fm = ((DelegatingJavaFileManager) fm).getBaseFileManager(); 213 } 214 if (fm instanceof JavacFileManager) { 215 JavacFileManager jfm = (JavacFileManager) fm; 216 useCtProps = jfm.isDefaultBootClassPath() && jfm.isSymbolFileEnabled(); 217 } else if (fm.getClass().getName().equals("com.sun.tools.sjavac.comp.SmartFileManager")) { 218 useCtProps = !options.isSet("ignore.symbol.file"); 219 } else { 220 useCtProps = false; 221 } 222 jrtIndex = useCtProps && JRTIndex.isAvailable() ? JRTIndex.getSharedInstance() : null; 223 224 profile = Profile.instance(context); 225 cachedCompletionFailure = new CompletionFailure(null, (JCDiagnostic) null, dcfh); 226 cachedCompletionFailure.setStackTrace(new StackTraceElement[0]); 227 } 228 229 230 /************************************************************************ 231 * Temporary ct.sym replacement 232 * 233 * The following code is a temporary substitute for the ct.sym mechanism 234 * used in JDK 6 thru JDK 8. 235 * This mechanism will eventually be superseded by the Jigsaw module system. 236 ***********************************************************************/ 237 238 /** 239 * Returns any extra flags for a class symbol. 240 * This information used to be provided using private annotations 241 * in the class file in ct.sym; in time, this information will be 242 * available from the module system. 243 */ getSupplementaryFlags(ClassSymbol c)244 long getSupplementaryFlags(ClassSymbol c) { 245 if (jrtIndex == null || !jrtIndex.isInJRT(c.classfile) || c.name == names.module_info) { 246 return 0; 247 } 248 249 if (supplementaryFlags == null) { 250 supplementaryFlags = new HashMap<>(); 251 } 252 253 Long flags = supplementaryFlags.get(c.packge()); 254 if (flags == null) { 255 long newFlags = 0; 256 try { 257 JRTIndex.CtSym ctSym = jrtIndex.getCtSym(c.packge().flatName()); 258 Profile minProfile = Profile.DEFAULT; 259 if (ctSym.proprietary) 260 newFlags |= PROPRIETARY; 261 if (ctSym.minProfile != null) 262 minProfile = Profile.lookup(ctSym.minProfile); 263 if (profile != Profile.DEFAULT && minProfile.value > profile.value) { 264 newFlags |= NOT_IN_PROFILE; 265 } 266 } catch (IOException ignore) { 267 } 268 supplementaryFlags.put(c.packge(), flags = newFlags); 269 } 270 return flags; 271 } 272 273 private Map<PackageSymbol, Long> supplementaryFlags; 274 275 /************************************************************************ 276 * Loading Classes 277 ***********************************************************************/ 278 279 /** Completion for classes to be loaded. Before a class is loaded 280 * we make sure its enclosing class (if any) is loaded. 281 */ complete(Symbol sym)282 private void complete(Symbol sym) throws CompletionFailure { 283 if (sym.kind == TYP) { 284 try { 285 ClassSymbol c = (ClassSymbol) sym; 286 dependencies.push(c, CompletionCause.CLASS_READER); 287 annotate.blockAnnotations(); 288 c.members_field = new Scope.ErrorScope(c); // make sure it's always defined 289 completeOwners(c.owner); 290 completeEnclosing(c); 291 fillIn(c); 292 } finally { 293 annotate.unblockAnnotationsNoFlush(); 294 dependencies.pop(); 295 } 296 } else if (sym.kind == PCK) { 297 PackageSymbol p = (PackageSymbol)sym; 298 try { 299 fillIn(p); 300 } catch (IOException ex) { 301 JCDiagnostic msg = 302 diagFactory.fragment(Fragments.ExceptionMessage(ex.getLocalizedMessage())); 303 throw new CompletionFailure(sym, msg, dcfh).initCause(ex); 304 } 305 } 306 if (!reader.filling) 307 annotate.flush(); // finish attaching annotations 308 } 309 310 /** complete up through the enclosing package. */ completeOwners(Symbol o)311 private void completeOwners(Symbol o) { 312 if (o.kind != PCK) completeOwners(o.owner); 313 o.complete(); 314 } 315 316 /** 317 * Tries to complete lexically enclosing classes if c looks like a 318 * nested class. This is similar to completeOwners but handles 319 * the situation when a nested class is accessed directly as it is 320 * possible with the Tree API or javax.lang.model.*. 321 */ completeEnclosing(ClassSymbol c)322 private void completeEnclosing(ClassSymbol c) { 323 if (c.owner.kind == PCK) { 324 Symbol owner = c.owner; 325 for (Name name : Convert.enclosingCandidates(Convert.shortName(c.name))) { 326 Symbol encl = owner.members().findFirst(name); 327 if (encl == null) 328 encl = syms.getClass(c.packge().modle, TypeSymbol.formFlatName(name, owner)); 329 if (encl != null) 330 encl.complete(); 331 } 332 } 333 } 334 335 /** Fill in definition of class `c' from corresponding class or 336 * source file. 337 */ fillIn(ClassSymbol c)338 void fillIn(ClassSymbol c) { 339 if (completionFailureName == c.fullname) { 340 JCDiagnostic msg = 341 diagFactory.fragment(Fragments.UserSelectedCompletionFailure); 342 throw new CompletionFailure(c, msg, dcfh); 343 } 344 currentOwner = c; 345 JavaFileObject classfile = c.classfile; 346 if (classfile != null) { 347 JavaFileObject previousClassFile = currentClassFile; 348 Symbol prevOwner = c.owner; 349 Name prevName = c.fullname; 350 try { 351 if (reader.filling) { 352 Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile); 353 } 354 currentClassFile = classfile; 355 if (verbose) { 356 log.printVerbose("loading", currentClassFile.getName()); 357 } 358 if (classfile.getKind() == JavaFileObject.Kind.CLASS) { 359 reader.readClassFile(c); 360 c.flags_field |= getSupplementaryFlags(c); 361 } else { 362 if (!sourceCompleter.isTerminal()) { 363 sourceCompleter.complete(c); 364 } else { 365 throw new IllegalStateException("Source completer required to read " 366 + classfile.toUri()); 367 } 368 } 369 } catch (BadClassFile cf) { 370 //the symbol may be partially initialized, purge it: 371 c.owner = prevOwner; 372 c.members_field.getSymbols(sym -> sym.kind == TYP).forEach(sym -> { 373 ClassSymbol csym = (ClassSymbol) sym; 374 csym.owner = sym.packge(); 375 csym.owner.members().enter(sym); 376 csym.fullname = sym.flatName(); 377 csym.name = Convert.shortName(sym.flatName()); 378 csym.reset(); 379 }); 380 c.fullname = prevName; 381 c.name = Convert.shortName(prevName); 382 c.reset(); 383 throw cf; 384 } finally { 385 currentClassFile = previousClassFile; 386 } 387 } else { 388 throw classFileNotFound(c); 389 } 390 } 391 // where classFileNotFound(ClassSymbol c)392 private CompletionFailure classFileNotFound(ClassSymbol c) { 393 JCDiagnostic diag = 394 diagFactory.fragment(Fragments.ClassFileNotFound(c.flatname)); 395 return newCompletionFailure(c, diag); 396 } 397 /** Static factory for CompletionFailure objects. 398 * In practice, only one can be used at a time, so we share one 399 * to reduce the expense of allocating new exception objects. 400 */ newCompletionFailure(TypeSymbol c, JCDiagnostic diag)401 private CompletionFailure newCompletionFailure(TypeSymbol c, 402 JCDiagnostic diag) { 403 if (!cacheCompletionFailure) { 404 // log.warning("proc.messager", 405 // Log.getLocalizedString("class.file.not.found", c.flatname)); 406 // c.debug.printStackTrace(); 407 return new CompletionFailure(c, diag, dcfh); 408 } else { 409 CompletionFailure result = cachedCompletionFailure; 410 result.sym = c; 411 result.diag = diag; 412 return result; 413 } 414 } 415 private final CompletionFailure cachedCompletionFailure; 416 417 418 /** Load a toplevel class with given fully qualified name 419 * The class is entered into `classes' only if load was successful. 420 */ loadClass(ModuleSymbol msym, Name flatname)421 public ClassSymbol loadClass(ModuleSymbol msym, Name flatname) throws CompletionFailure { 422 Assert.checkNonNull(msym); 423 Name packageName = Convert.packagePart(flatname); 424 PackageSymbol ps = syms.lookupPackage(msym, packageName); 425 426 Assert.checkNonNull(ps.modle, () -> "msym=" + msym + "; flatName=" + flatname); 427 428 boolean absent = syms.getClass(ps.modle, flatname) == null; 429 ClassSymbol c = syms.enterClass(ps.modle, flatname); 430 431 if (c.members_field == null) { 432 try { 433 c.complete(); 434 } catch (CompletionFailure ex) { 435 if (absent) { 436 syms.removeClass(ps.modle, flatname); 437 ex.dcfh.classSymbolRemoved(c); 438 } 439 throw ex; 440 } 441 } 442 return c; 443 } 444 445 /************************************************************************ 446 * Loading Packages 447 ***********************************************************************/ 448 449 /** Include class corresponding to given class file in package, 450 * unless (1) we already have one the same kind (.class or .java), or 451 * (2) we have one of the other kind, and the given class file 452 * is older. 453 */ includeClassFile(PackageSymbol p, JavaFileObject file)454 protected void includeClassFile(PackageSymbol p, JavaFileObject file) { 455 if ((p.flags_field & EXISTS) == 0) 456 for (Symbol q = p; q != null && q.kind == PCK; q = q.owner) 457 q.flags_field |= EXISTS; 458 JavaFileObject.Kind kind = file.getKind(); 459 int seen; 460 if (kind == JavaFileObject.Kind.CLASS) 461 seen = CLASS_SEEN; 462 else 463 seen = SOURCE_SEEN; 464 String binaryName = fileManager.inferBinaryName(currentLoc, file); 465 int lastDot = binaryName.lastIndexOf("."); 466 Name classname = names.fromString(binaryName.substring(lastDot + 1)); 467 boolean isPkgInfo = classname == names.package_info; 468 ClassSymbol c = isPkgInfo 469 ? p.package_info 470 : (ClassSymbol) p.members_field.findFirst(classname); 471 if (c == null) { 472 c = syms.enterClass(p.modle, classname, p); 473 if (c.classfile == null) // only update the file if's it's newly created 474 c.classfile = file; 475 if (isPkgInfo) { 476 p.package_info = c; 477 } else { 478 if (c.owner == p) // it might be an inner class 479 p.members_field.enter(c); 480 } 481 } else if (!preferCurrent && c.classfile != null && (c.flags_field & seen) == 0) { 482 // if c.classfile == null, we are currently compiling this class 483 // and no further action is necessary. 484 // if (c.flags_field & seen) != 0, we have already encountered 485 // a file of the same kind; again no further action is necessary. 486 if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0) 487 c.classfile = preferredFileObject(file, c.classfile); 488 } 489 c.flags_field |= seen; 490 } 491 492 /** Implement policy to choose to derive information from a source 493 * file or a class file when both are present. May be overridden 494 * by subclasses. 495 */ preferredFileObject(JavaFileObject a, JavaFileObject b)496 protected JavaFileObject preferredFileObject(JavaFileObject a, 497 JavaFileObject b) { 498 499 if (preferSource) 500 return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b; 501 else { 502 long adate = a.getLastModified(); 503 long bdate = b.getLastModified(); 504 // 6449326: policy for bad lastModifiedTime in ClassReader 505 //assert adate >= 0 && bdate >= 0; 506 return (adate > bdate) ? a : b; 507 } 508 } 509 510 /** 511 * specifies types of files to be read when filling in a package symbol 512 */ 513 // Note: overridden by JavadocClassFinder getPackageFileKinds()514 protected EnumSet<JavaFileObject.Kind> getPackageFileKinds() { 515 return EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.SOURCE); 516 } 517 518 /** 519 * this is used to support javadoc 520 */ extraFileActions(PackageSymbol pack, JavaFileObject fe)521 protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) { 522 } 523 524 protected Location currentLoc; // FIXME 525 526 private boolean verbosePath = true; 527 528 // Set to true when the currently selected file should be kept 529 private boolean preferCurrent; 530 531 /** Load directory of package into members scope. 532 */ fillIn(PackageSymbol p)533 private void fillIn(PackageSymbol p) throws IOException { 534 if (p.members_field == null) 535 p.members_field = WriteableScope.create(p); 536 537 ModuleSymbol msym = p.modle; 538 539 Assert.checkNonNull(msym, p::toString); 540 541 msym.complete(); 542 543 if (msym == syms.noModule) { 544 preferCurrent = false; 545 if (userPathsFirst) { 546 scanUserPaths(p, true); 547 preferCurrent = true; 548 scanPlatformPath(p); 549 } else { 550 scanPlatformPath(p); 551 scanUserPaths(p, true); 552 } 553 } else if (msym.classLocation == StandardLocation.CLASS_PATH) { 554 scanUserPaths(p, msym.sourceLocation == StandardLocation.SOURCE_PATH); 555 } else { 556 scanModulePaths(p, msym); 557 } 558 } 559 560 // TODO: for now, this is a much simplified form of scanUserPaths 561 // and (deliberately) does not default sourcepath to classpath. 562 // But, we need to think about retaining existing behavior for 563 // -classpath and -sourcepath for single module mode. 564 // One plausible solution is to detect if the module's sourceLocation 565 // is the same as the module's classLocation. scanModulePaths(PackageSymbol p, ModuleSymbol msym)566 private void scanModulePaths(PackageSymbol p, ModuleSymbol msym) throws IOException { 567 Set<JavaFileObject.Kind> kinds = getPackageFileKinds(); 568 569 Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds); 570 classKinds.remove(JavaFileObject.Kind.SOURCE); 571 boolean wantClassFiles = !classKinds.isEmpty(); 572 573 Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds); 574 sourceKinds.remove(JavaFileObject.Kind.CLASS); 575 boolean wantSourceFiles = !sourceKinds.isEmpty(); 576 577 String packageName = p.fullname.toString(); 578 579 Location classLocn = msym.classLocation; 580 Location sourceLocn = msym.sourceLocation; 581 Location patchLocn = msym.patchLocation; 582 Location patchOutLocn = msym.patchOutputLocation; 583 584 boolean prevPreferCurrent = preferCurrent; 585 586 try { 587 preferCurrent = false; 588 if (wantClassFiles && (patchOutLocn != null)) { 589 fillIn(p, patchOutLocn, 590 list(patchOutLocn, 591 p, 592 packageName, 593 classKinds)); 594 } 595 if ((wantClassFiles || wantSourceFiles) && (patchLocn != null)) { 596 Set<JavaFileObject.Kind> combined = EnumSet.noneOf(JavaFileObject.Kind.class); 597 combined.addAll(classKinds); 598 combined.addAll(sourceKinds); 599 fillIn(p, patchLocn, 600 list(patchLocn, 601 p, 602 packageName, 603 combined)); 604 } 605 preferCurrent = true; 606 if (wantClassFiles && (classLocn != null)) { 607 fillIn(p, classLocn, 608 list(classLocn, 609 p, 610 packageName, 611 classKinds)); 612 } 613 if (wantSourceFiles && (sourceLocn != null)) { 614 fillIn(p, sourceLocn, 615 list(sourceLocn, 616 p, 617 packageName, 618 sourceKinds)); 619 } 620 } finally { 621 preferCurrent = prevPreferCurrent; 622 } 623 } 624 625 /** 626 * Scans class path and source path for files in given package. 627 */ scanUserPaths(PackageSymbol p, boolean includeSourcePath)628 private void scanUserPaths(PackageSymbol p, boolean includeSourcePath) throws IOException { 629 Set<JavaFileObject.Kind> kinds = getPackageFileKinds(); 630 631 Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds); 632 classKinds.remove(JavaFileObject.Kind.SOURCE); 633 boolean wantClassFiles = !classKinds.isEmpty(); 634 635 Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds); 636 sourceKinds.remove(JavaFileObject.Kind.CLASS); 637 boolean wantSourceFiles = !sourceKinds.isEmpty(); 638 639 boolean haveSourcePath = includeSourcePath && fileManager.hasLocation(SOURCE_PATH); 640 641 if (verbose && verbosePath) { 642 verbosePath = false; // print once per compile 643 if (fileManager instanceof StandardJavaFileManager) { 644 StandardJavaFileManager fm = (StandardJavaFileManager)fileManager; 645 if (haveSourcePath && wantSourceFiles) { 646 List<Path> path = List.nil(); 647 for (Path sourcePath : fm.getLocationAsPaths(SOURCE_PATH)) { 648 path = path.prepend(sourcePath); 649 } 650 log.printVerbose("sourcepath", path.reverse().toString()); 651 } else if (wantSourceFiles) { 652 List<Path> path = List.nil(); 653 for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) { 654 path = path.prepend(classPath); 655 } 656 log.printVerbose("sourcepath", path.reverse().toString()); 657 } 658 if (wantClassFiles) { 659 List<Path> path = List.nil(); 660 for (Path platformPath : fm.getLocationAsPaths(PLATFORM_CLASS_PATH)) { 661 path = path.prepend(platformPath); 662 } 663 for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) { 664 path = path.prepend(classPath); 665 } 666 log.printVerbose("classpath", path.reverse().toString()); 667 } 668 } 669 } 670 671 String packageName = p.fullname.toString(); 672 if (wantSourceFiles && !haveSourcePath) { 673 fillIn(p, CLASS_PATH, 674 list(CLASS_PATH, 675 p, 676 packageName, 677 kinds)); 678 } else { 679 if (wantClassFiles) 680 fillIn(p, CLASS_PATH, 681 list(CLASS_PATH, 682 p, 683 packageName, 684 classKinds)); 685 if (wantSourceFiles) 686 fillIn(p, SOURCE_PATH, 687 list(SOURCE_PATH, 688 p, 689 packageName, 690 sourceKinds)); 691 } 692 } 693 694 /** 695 * Scans platform class path for files in given package. 696 */ scanPlatformPath(PackageSymbol p)697 private void scanPlatformPath(PackageSymbol p) throws IOException { 698 fillIn(p, PLATFORM_CLASS_PATH, 699 list(PLATFORM_CLASS_PATH, 700 p, 701 p.fullname.toString(), 702 EnumSet.of(JavaFileObject.Kind.CLASS))); 703 } 704 // where 705 @SuppressWarnings("fallthrough") fillIn(PackageSymbol p, Location location, Iterable<JavaFileObject> files)706 private void fillIn(PackageSymbol p, 707 Location location, 708 Iterable<JavaFileObject> files) 709 { 710 currentLoc = location; 711 for (JavaFileObject fo : files) { 712 switch (fo.getKind()) { 713 case OTHER: 714 extraFileActions(p, fo); 715 break; 716 case CLASS: 717 case SOURCE: { 718 // TODO pass binaryName to includeClassFile 719 String binaryName = fileManager.inferBinaryName(currentLoc, fo); 720 String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1); 721 if (SourceVersion.isIdentifier(simpleName) || 722 simpleName.equals("package-info")) 723 includeClassFile(p, fo); 724 break; 725 } 726 default: 727 extraFileActions(p, fo); 728 break; 729 } 730 } 731 } 732 list(Location location, PackageSymbol p, String packageName, Set<Kind> kinds)733 Iterable<JavaFileObject> list(Location location, 734 PackageSymbol p, 735 String packageName, 736 Set<Kind> kinds) throws IOException { 737 Iterable<JavaFileObject> listed = fileManager.list(location, 738 packageName, 739 EnumSet.allOf(Kind.class), 740 false); 741 return () -> new Iterator<JavaFileObject>() { 742 private final Iterator<JavaFileObject> original = listed.iterator(); 743 private JavaFileObject next; 744 @Override 745 public boolean hasNext() { 746 if (next == null) { 747 while (original.hasNext()) { 748 JavaFileObject fo = original.next(); 749 750 if (fo.getKind() != Kind.CLASS && 751 fo.getKind() != Kind.SOURCE) { 752 p.flags_field |= Flags.HAS_RESOURCE; 753 } 754 755 if (kinds.contains(fo.getKind())) { 756 next = fo; 757 break; 758 } 759 } 760 } 761 return next != null; 762 } 763 764 @Override 765 public JavaFileObject next() { 766 if (!hasNext()) 767 throw new NoSuchElementException(); 768 JavaFileObject result = next; 769 next = null; 770 return result; 771 } 772 773 }; 774 } 775 776 /** 777 * Used for bad class definition files, such as bad .class files or 778 * for .java files with unexpected package or class names. 779 */ 780 public static class BadClassFile extends CompletionFailure { 781 private static final long serialVersionUID = 0; 782 BadClassFile(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag, JCDiagnostic.Factory diagFactory, DeferredCompletionFailureHandler dcfh)783 public BadClassFile(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag, 784 JCDiagnostic.Factory diagFactory, DeferredCompletionFailureHandler dcfh) { 785 super(sym, createBadClassFileDiagnostic(file, diag, diagFactory), dcfh); 786 } 787 // where createBadClassFileDiagnostic( JavaFileObject file, JCDiagnostic diag, JCDiagnostic.Factory diagFactory)788 private static JCDiagnostic createBadClassFileDiagnostic( 789 JavaFileObject file, JCDiagnostic diag, JCDiagnostic.Factory diagFactory) { 790 String key = (file.getKind() == JavaFileObject.Kind.SOURCE 791 ? "bad.source.file.header" : "bad.class.file.header"); 792 return diagFactory.fragment(key, file, diag); 793 } 794 } 795 796 public static class BadEnclosingMethodAttr extends BadClassFile { 797 private static final long serialVersionUID = 0; 798 BadEnclosingMethodAttr(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag, JCDiagnostic.Factory diagFactory, DeferredCompletionFailureHandler dcfh)799 public BadEnclosingMethodAttr(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag, 800 JCDiagnostic.Factory diagFactory, DeferredCompletionFailureHandler dcfh) { 801 super(sym, file, diag, diagFactory, dcfh); 802 } 803 } 804 } 805