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