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