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