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