ClassFinder.java revision 4202:2bd34895dda2
1141296Sdas/* 2141296Sdas * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. 32116Sjkh * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 42116Sjkh * 52116Sjkh * This code is free software; you can redistribute it and/or modify it 62116Sjkh * under the terms of the GNU General Public License version 2 only, as 7141296Sdas * published by the Free Software Foundation. Oracle designates this 82116Sjkh * particular file as subject to the "Classpath" exception as provided 9141296Sdas * by Oracle in the LICENSE file that accompanied this code. 102116Sjkh * 112116Sjkh * This code is distributed in the hope that it will be useful, but WITHOUT 122116Sjkh * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 132116Sjkh * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14175499Sbde * version 2 for more details (a copy is included in the LICENSE file that 15175499Sbde * accompanied this code). 162116Sjkh * 172116Sjkh * You should have received a copy of the GNU General Public License version 18176356Sdas * 2 along with this work; if not, write to the Free Software Foundation, 19176356Sdas * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20141296Sdas * 21141296Sdas * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 222116Sjkh * or visit www.oracle.com if you need additional information or have any 232116Sjkh * questions. 242116Sjkh */ 25141296Sdas 262116Sjkhpackage com.sun.tools.javac.code; 272116Sjkh 282116Sjkhimport java.io.IOException; 292116Sjkhimport java.nio.file.Path; 302116Sjkhimport java.util.EnumSet; 312116Sjkhimport java.util.HashMap; 322116Sjkhimport java.util.Iterator; 332116Sjkhimport java.util.Map; 34141296Sdasimport java.util.NoSuchElementException; 352116Sjkhimport java.util.Set; 36141296Sdas 37141296Sdasimport javax.lang.model.SourceVersion; 382116Sjkhimport javax.tools.JavaFileManager; 392116Sjkhimport javax.tools.JavaFileManager.Location; 402116Sjkhimport javax.tools.JavaFileObject; 412116Sjkhimport javax.tools.JavaFileObject.Kind; 422116Sjkhimport javax.tools.StandardJavaFileManager; 432116Sjkhimport javax.tools.StandardLocation; 442116Sjkh 452116Sjkhimport com.sun.tools.javac.code.Scope.WriteableScope; 462116Sjkhimport com.sun.tools.javac.code.Symbol.ClassSymbol; 472116Sjkhimport com.sun.tools.javac.code.Symbol.Completer; 482116Sjkhimport com.sun.tools.javac.code.Symbol.CompletionFailure; 492116Sjkhimport com.sun.tools.javac.code.Symbol.ModuleSymbol; 502116Sjkhimport com.sun.tools.javac.code.Symbol.PackageSymbol; 512116Sjkhimport com.sun.tools.javac.code.Symbol.TypeSymbol; 522116Sjkhimport com.sun.tools.javac.comp.Annotate; 532116Sjkhimport com.sun.tools.javac.file.JRTIndex; 542116Sjkhimport com.sun.tools.javac.file.JavacFileManager; 552116Sjkhimport com.sun.tools.javac.jvm.ClassReader; 562116Sjkhimport com.sun.tools.javac.jvm.Profile; 572116Sjkhimport com.sun.tools.javac.main.Option; 582116Sjkhimport com.sun.tools.javac.platform.PlatformDescription; 592116Sjkhimport com.sun.tools.javac.resources.CompilerProperties.Fragments; 602116Sjkhimport com.sun.tools.javac.util.*; 612116Sjkh 622116Sjkhimport static javax.tools.StandardLocation.*; 63176356Sdas 64176356Sdasimport static com.sun.tools.javac.code.Flags.*; 652116Sjkhimport static com.sun.tools.javac.code.Kinds.Kind.*; 662116Sjkh 672116Sjkhimport com.sun.tools.javac.util.Dependencies.CompletionCause; 682116Sjkh 692116Sjkh/** 702116Sjkh * This class provides operations to locate class definitions 712116Sjkh * from the source and class files on the paths provided to javac. 722116Sjkh * 732116Sjkh * <p><b>This is NOT part of any supported API. 742116Sjkh * If you write code that depends on this, you do so at your own risk. 752116Sjkh * This code and its internal interfaces are subject to change or 762116Sjkh * deletion without notice.</b> 772116Sjkh */ 782116Sjkhpublic class ClassFinder { 792116Sjkh /** The context key for the class finder. */ 802116Sjkh protected static final Context.Key<ClassFinder> classFinderKey = new Context.Key<>(); 812116Sjkh 822116Sjkh ClassReader reader; 832116Sjkh 84141296Sdas private final Annotate annotate; 85141296Sdas 862116Sjkh /** Switch: verbose output. 872116Sjkh */ 882116Sjkh boolean verbose; 892116Sjkh 902116Sjkh /** 912116Sjkh * Switch: cache completion failures unless -XDdev is used 922116Sjkh */ 932116Sjkh private boolean cacheCompletionFailure; 942116Sjkh 952116Sjkh /** 962116Sjkh * Switch: prefer source files instead of newer when both source 972116Sjkh * and class are available 982116Sjkh **/ 992116Sjkh protected boolean preferSource; 1002116Sjkh 1012116Sjkh /** 1022116Sjkh * Switch: Search classpath and sourcepath for classes before the 1032116Sjkh * bootclasspath 1042116Sjkh */ 105141296Sdas protected boolean userPathsFirst; 1062116Sjkh 107141296Sdas /** 1082116Sjkh * Switch: should read OTHER classfiles (.sig files) from PLATFORM_CLASS_PATH. 1092116Sjkh */ 1102116Sjkh private boolean allowSigFiles; 1112116Sjkh 1122116Sjkh /** The log to use for verbose output 1132116Sjkh */ 1142116Sjkh final Log log; 1152116Sjkh 1162116Sjkh /** The symbol table. */ 1172116Sjkh Symtab syms; 1182116Sjkh 1192116Sjkh /** The name table. */ 1202116Sjkh final Names names; 121141296Sdas 122141296Sdas /** Force a completion failure on this name 123141296Sdas */ 1242116Sjkh final Name completionFailureName; 1252116Sjkh 1262116Sjkh /** Access to files 127175499Sbde */ 128175499Sbde private final JavaFileManager fileManager; 1292116Sjkh 1302116Sjkh /** Dependency tracker 1312116Sjkh */ 1322116Sjkh private final Dependencies dependencies; 1332116Sjkh 134176356Sdas /** Factory for diagnostics 135176356Sdas */ 136176356Sdas JCDiagnostic.Factory diagFactory; 137176356Sdas 138176356Sdas /** Can be reassigned from outside: 139176356Sdas * the completer to be used for ".java" files. If this remains unassigned 140176356Sdas * ".java" files will not be loaded. 141176356Sdas */ 142176356Sdas public Completer sourceCompleter = Completer.NULL_COMPLETER; 143176356Sdas 144176356Sdas /** The path name of the class file currently being read. 145176356Sdas */ 146176356Sdas protected JavaFileObject currentClassFile = null; 147176356Sdas 148176356Sdas /** The class or method currently being read. 149176356Sdas */ 150176356Sdas protected Symbol currentOwner = null; 151176356Sdas 152176356Sdas /** 153176356Sdas * The currently selected profile. 154176356Sdas */ 155176356Sdas private final Profile profile; 156176356Sdas 157176356Sdas /** 158176356Sdas * Use direct access to the JRTIndex to access the temporary 159176356Sdas * replacement for the info that used to be in ct.sym. 160176356Sdas * In time, this will go away and be replaced by the module system. 161176356Sdas */ 162176356Sdas private final JRTIndex jrtIndex; 163176356Sdas 164176356Sdas /** 165176356Sdas * Completer that delegates to the complete-method of this class. 166176356Sdas */ 167176356Sdas private final Completer thisCompleter = this::complete; 168176356Sdas 169176356Sdas public Completer getCompleter() { 170176356Sdas return thisCompleter; 171176356Sdas } 172176356Sdas 173176356Sdas /** Get the ClassFinder instance for this invocation. */ 174176356Sdas public static ClassFinder instance(Context context) { 175176356Sdas ClassFinder instance = context.get(classFinderKey); 176176356Sdas if (instance == null) 177176356Sdas instance = new ClassFinder(context); 178176356Sdas return instance; 179176356Sdas } 180176356Sdas 181176356Sdas /** Construct a new class finder. */ 182176356Sdas protected ClassFinder(Context context) { 183176356Sdas context.put(classFinderKey, this); 184176356Sdas reader = ClassReader.instance(context); 185176356Sdas names = Names.instance(context); 186176356Sdas syms = Symtab.instance(context); 187176356Sdas fileManager = context.get(JavaFileManager.class); 188176356Sdas dependencies = Dependencies.instance(context); 189176356Sdas if (fileManager == null) 190176356Sdas throw new AssertionError("FileManager initialization error"); 191176356Sdas diagFactory = JCDiagnostic.Factory.instance(context); 192176356Sdas 193176356Sdas log = Log.instance(context); 194176356Sdas annotate = Annotate.instance(context); 195176356Sdas 196176356Sdas Options options = Options.instance(context); 197176356Sdas verbose = options.isSet(Option.VERBOSE); 198176356Sdas cacheCompletionFailure = options.isUnset("dev"); 199176356Sdas preferSource = "source".equals(options.get("-Xprefer")); 200176356Sdas userPathsFirst = options.isSet(Option.XXUSERPATHSFIRST); 201176356Sdas allowSigFiles = context.get(PlatformDescription.class) != null; 202176356Sdas 203176356Sdas completionFailureName = 204176356Sdas options.isSet("failcomplete") 205176356Sdas ? names.fromString(options.get("failcomplete")) 206176356Sdas : null; 207176356Sdas 208176356Sdas // Temporary, until more info is available from the module system. 209176356Sdas boolean useCtProps; 210176356Sdas JavaFileManager fm = context.get(JavaFileManager.class); 211176356Sdas if (fm instanceof JavacFileManager) { 212176356Sdas JavacFileManager jfm = (JavacFileManager) fm; 213176356Sdas useCtProps = jfm.isDefaultBootClassPath() && jfm.isSymbolFileEnabled(); 214176356Sdas } else if (fm.getClass().getName().equals("com.sun.tools.sjavac.comp.SmartFileManager")) { 215176356Sdas useCtProps = !options.isSet("ignore.symbol.file"); 216176356Sdas } else { 217176356Sdas useCtProps = false; 218176356Sdas } 219176356Sdas jrtIndex = useCtProps && JRTIndex.isAvailable() ? JRTIndex.getSharedInstance() : null; 220176356Sdas 221176356Sdas profile = Profile.instance(context); 222176356Sdas } 223176356Sdas 224176356Sdas 225176356Sdas/************************************************************************ 226176356Sdas * Temporary ct.sym replacement 227176356Sdas * 228176356Sdas * The following code is a temporary substitute for the ct.sym mechanism 229176356Sdas * used in JDK 6 thru JDK 8. 230176356Sdas * This mechanism will eventually be superseded by the Jigsaw module system. 231176356Sdas ***********************************************************************/ 232176356Sdas 233176356Sdas /** 234176356Sdas * Returns any extra flags for a class symbol. 235176356Sdas * This information used to be provided using private annotations 236176356Sdas * in the class file in ct.sym; in time, this information will be 237176356Sdas * available from the module system. 238176356Sdas */ 239176356Sdas long getSupplementaryFlags(ClassSymbol c) { 240176356Sdas if (jrtIndex == null || !jrtIndex.isInJRT(c.classfile) || c.name == names.module_info) { 241176356Sdas return 0; 242176356Sdas } 243176356Sdas 244176356Sdas if (supplementaryFlags == null) { 245176356Sdas supplementaryFlags = new HashMap<>(); 246176356Sdas } 247176356Sdas 248176356Sdas Long flags = supplementaryFlags.get(c.packge()); 249176356Sdas if (flags == null) { 250176356Sdas long newFlags = 0; 251176356Sdas try { 252176356Sdas JRTIndex.CtSym ctSym = jrtIndex.getCtSym(c.packge().flatName()); 253176356Sdas Profile minProfile = Profile.DEFAULT; 254176356Sdas if (ctSym.proprietary) 255176356Sdas newFlags |= PROPRIETARY; 256176356Sdas if (ctSym.minProfile != null) 257176356Sdas minProfile = Profile.lookup(ctSym.minProfile); 258176356Sdas if (profile != Profile.DEFAULT && minProfile.value > profile.value) { 259176356Sdas newFlags |= NOT_IN_PROFILE; 260176356Sdas } 261176356Sdas } catch (IOException ignore) { 262176356Sdas } 263176356Sdas supplementaryFlags.put(c.packge(), flags = newFlags); 264176356Sdas } 265176356Sdas return flags; 266176356Sdas } 267176356Sdas 268176356Sdas private Map<PackageSymbol, Long> supplementaryFlags; 269176356Sdas 270176356Sdas/************************************************************************ 2712116Sjkh * Loading Classes 2722116Sjkh ***********************************************************************/ 2732116Sjkh 2742116Sjkh /** Completion for classes to be loaded. Before a class is loaded 2752116Sjkh * we make sure its enclosing class (if any) is loaded. 2762116Sjkh */ 2772116Sjkh private void complete(Symbol sym) throws CompletionFailure { 2782116Sjkh if (sym.kind == TYP) { 2792116Sjkh try { 2802116Sjkh ClassSymbol c = (ClassSymbol) sym; 2812116Sjkh dependencies.push(c, CompletionCause.CLASS_READER); 282141296Sdas annotate.blockAnnotations(); 2832116Sjkh c.members_field = new Scope.ErrorScope(c); // make sure it's always defined 2842116Sjkh completeOwners(c.owner); 2852116Sjkh completeEnclosing(c); 2862116Sjkh fillIn(c); 2872116Sjkh } finally { 288176356Sdas annotate.unblockAnnotationsNoFlush(); 289176356Sdas dependencies.pop(); 2902116Sjkh } 2912116Sjkh } else if (sym.kind == PCK) { 2922116Sjkh PackageSymbol p = (PackageSymbol)sym; 2932116Sjkh try { 2942116Sjkh fillIn(p); 2952116Sjkh } catch (IOException ex) { 2962116Sjkh JCDiagnostic msg = 2972116Sjkh diagFactory.fragment(Fragments.ExceptionMessage(ex.getLocalizedMessage())); 2982116Sjkh throw new CompletionFailure(sym, msg).initCause(ex); 2992116Sjkh } 3002116Sjkh } 3012116Sjkh if (!reader.filling) 3022116Sjkh annotate.flush(); // finish attaching annotations 3032116Sjkh } 3042116Sjkh 3052116Sjkh /** complete up through the enclosing package. */ 3062116Sjkh private void completeOwners(Symbol o) { 3072116Sjkh if (o.kind != PCK) completeOwners(o.owner); 3082116Sjkh o.complete(); 3092116Sjkh } 3102116Sjkh 3112116Sjkh /** 3122116Sjkh * Tries to complete lexically enclosing classes if c looks like a 3132116Sjkh * nested class. This is similar to completeOwners but handles 3142116Sjkh * the situation when a nested class is accessed directly as it is 3152116Sjkh * possible with the Tree API or javax.lang.model.*. 3162116Sjkh */ 3172116Sjkh private void completeEnclosing(ClassSymbol c) { 3182116Sjkh if (c.owner.kind == PCK) { 3192116Sjkh Symbol owner = c.owner; 3202116Sjkh for (Name name : Convert.enclosingCandidates(Convert.shortName(c.name))) { 3212116Sjkh Symbol encl = owner.members().findFirst(name); 3222116Sjkh if (encl == null) 3232116Sjkh encl = syms.getClass(c.packge().modle, TypeSymbol.formFlatName(name, owner)); 3242116Sjkh if (encl != null) 3252116Sjkh encl.complete(); 3262116Sjkh } 3272116Sjkh } 3282116Sjkh } 3292116Sjkh 3302116Sjkh /** Fill in definition of class `c' from corresponding class or 331141296Sdas * source file. 3322116Sjkh */ 3332116Sjkh void fillIn(ClassSymbol c) { 3342116Sjkh if (completionFailureName == c.fullname) { 3352116Sjkh JCDiagnostic msg = 3362116Sjkh diagFactory.fragment(Fragments.UserSelectedCompletionFailure); 3372116Sjkh throw new CompletionFailure(c, msg); 3382116Sjkh } 3392116Sjkh currentOwner = c; 3402116Sjkh JavaFileObject classfile = c.classfile; 3412116Sjkh if (classfile != null) { 3422116Sjkh JavaFileObject previousClassFile = currentClassFile; 3432116Sjkh try { 3442116Sjkh if (reader.filling) { 3452116Sjkh Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile); 3462116Sjkh } 3472116Sjkh currentClassFile = classfile; 3482116Sjkh if (verbose) { 3492116Sjkh log.printVerbose("loading", currentClassFile.getName()); 3502116Sjkh } 3512116Sjkh if (classfile.getKind() == JavaFileObject.Kind.CLASS || 3522116Sjkh classfile.getKind() == JavaFileObject.Kind.OTHER) { 3532116Sjkh reader.readClassFile(c); 3542116Sjkh c.flags_field |= getSupplementaryFlags(c); 3552116Sjkh } else { 3562116Sjkh if (!sourceCompleter.isTerminal()) { 3572116Sjkh sourceCompleter.complete(c); 3582116Sjkh } else { 3592116Sjkh throw new IllegalStateException("Source completer required to read " 3602116Sjkh + classfile.toUri()); 3612116Sjkh } 3622116Sjkh } 3632116Sjkh } finally { 3642116Sjkh currentClassFile = previousClassFile; 3652116Sjkh } 3662116Sjkh } else { 3672116Sjkh throw classFileNotFound(c); 3682116Sjkh } 3692116Sjkh } 3702116Sjkh // where 3712116Sjkh private CompletionFailure classFileNotFound(ClassSymbol c) { 3722116Sjkh JCDiagnostic diag = 3732116Sjkh diagFactory.fragment(Fragments.ClassFileNotFound(c.flatname)); 3742116Sjkh return newCompletionFailure(c, diag); 3752116Sjkh } 3762116Sjkh /** Static factory for CompletionFailure objects. 3772116Sjkh * In practice, only one can be used at a time, so we share one 3782116Sjkh * to reduce the expense of allocating new exception objects. 3792116Sjkh */ 3802116Sjkh private CompletionFailure newCompletionFailure(TypeSymbol c, 3812116Sjkh JCDiagnostic diag) { 382141296Sdas if (!cacheCompletionFailure) { 3832116Sjkh // log.warning("proc.messager", 3842116Sjkh // Log.getLocalizedString("class.file.not.found", c.flatname)); 3852116Sjkh // c.debug.printStackTrace(); 3862116Sjkh return new CompletionFailure(c, diag); 3872116Sjkh } else { 3882116Sjkh CompletionFailure result = cachedCompletionFailure; 3892116Sjkh result.sym = c; 3902116Sjkh result.diag = diag; 3912116Sjkh return result; 3922116Sjkh } 3932116Sjkh } 3942116Sjkh private final CompletionFailure cachedCompletionFailure = 3952116Sjkh new CompletionFailure(null, (JCDiagnostic) null); 3962116Sjkh { 3972116Sjkh cachedCompletionFailure.setStackTrace(new StackTraceElement[0]); 3982116Sjkh } 3992116Sjkh 4002116Sjkh 4012116Sjkh /** Load a toplevel class with given fully qualified name 4022116Sjkh * The class is entered into `classes' only if load was successful. 4032116Sjkh */ 4042116Sjkh public ClassSymbol loadClass(ModuleSymbol msym, Name flatname) throws CompletionFailure { 4052116Sjkh Assert.checkNonNull(msym); 4062116Sjkh Name packageName = Convert.packagePart(flatname); 407141296Sdas PackageSymbol ps = syms.lookupPackage(msym, packageName); 4082116Sjkh 4092116Sjkh Assert.checkNonNull(ps.modle, () -> "msym=" + msym + "; flatName=" + flatname); 4102116Sjkh 4112116Sjkh boolean absent = syms.getClass(ps.modle, flatname) == null; 412141296Sdas ClassSymbol c = syms.enterClass(ps.modle, flatname); 413175507Sbde 414141296Sdas if (c.members_field == null) { 4152116Sjkh try { 4162116Sjkh c.complete(); 417141296Sdas } catch (CompletionFailure ex) { 4182116Sjkh if (absent) syms.removeClass(ps.modle, flatname); 4192116Sjkh throw ex; 4202116Sjkh } 421141296Sdas } 4222116Sjkh return c; 4232116Sjkh } 4242116Sjkh 4252116Sjkh/************************************************************************ 426141296Sdas * Loading Packages 4272116Sjkh ***********************************************************************/ 4282116Sjkh 4292116Sjkh /** Include class corresponding to given class file in package, 430141296Sdas * unless (1) we already have one the same kind (.class or .java), or 4312116Sjkh * (2) we have one of the other kind, and the given class file 4322116Sjkh * is older. 4332116Sjkh */ 4342116Sjkh protected void includeClassFile(PackageSymbol p, JavaFileObject file) { 4352116Sjkh if ((p.flags_field & EXISTS) == 0) 4362116Sjkh for (Symbol q = p; q != null && q.kind == PCK; q = q.owner) 4372116Sjkh q.flags_field |= EXISTS; 4382116Sjkh JavaFileObject.Kind kind = file.getKind(); 439 int seen; 440 if (kind == JavaFileObject.Kind.CLASS || kind == JavaFileObject.Kind.OTHER) 441 seen = CLASS_SEEN; 442 else 443 seen = SOURCE_SEEN; 444 String binaryName = fileManager.inferBinaryName(currentLoc, file); 445 int lastDot = binaryName.lastIndexOf("."); 446 Name classname = names.fromString(binaryName.substring(lastDot + 1)); 447 boolean isPkgInfo = classname == names.package_info; 448 ClassSymbol c = isPkgInfo 449 ? p.package_info 450 : (ClassSymbol) p.members_field.findFirst(classname); 451 if (c == null) { 452 c = syms.enterClass(p.modle, classname, p); 453 if (c.classfile == null) // only update the file if's it's newly created 454 c.classfile = file; 455 if (isPkgInfo) { 456 p.package_info = c; 457 } else { 458 if (c.owner == p) // it might be an inner class 459 p.members_field.enter(c); 460 } 461 } else if (!preferCurrent && c.classfile != null && (c.flags_field & seen) == 0) { 462 // if c.classfile == null, we are currently compiling this class 463 // and no further action is necessary. 464 // if (c.flags_field & seen) != 0, we have already encountered 465 // a file of the same kind; again no further action is necessary. 466 if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0) 467 c.classfile = preferredFileObject(file, c.classfile); 468 } 469 c.flags_field |= seen; 470 } 471 472 /** Implement policy to choose to derive information from a source 473 * file or a class file when both are present. May be overridden 474 * by subclasses. 475 */ 476 protected JavaFileObject preferredFileObject(JavaFileObject a, 477 JavaFileObject b) { 478 479 if (preferSource) 480 return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b; 481 else { 482 long adate = a.getLastModified(); 483 long bdate = b.getLastModified(); 484 // 6449326: policy for bad lastModifiedTime in ClassReader 485 //assert adate >= 0 && bdate >= 0; 486 return (adate > bdate) ? a : b; 487 } 488 } 489 490 /** 491 * specifies types of files to be read when filling in a package symbol 492 */ 493 // Note: overridden by JavadocClassFinder 494 protected EnumSet<JavaFileObject.Kind> getPackageFileKinds() { 495 return EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.SOURCE); 496 } 497 498 /** 499 * this is used to support javadoc 500 */ 501 protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) { 502 } 503 504 protected Location currentLoc; // FIXME 505 506 private boolean verbosePath = true; 507 508 // Set to true when the currently selected file should be kept 509 private boolean preferCurrent; 510 511 /** Load directory of package into members scope. 512 */ 513 private void fillIn(PackageSymbol p) throws IOException { 514 if (p.members_field == null) 515 p.members_field = WriteableScope.create(p); 516 517 ModuleSymbol msym = p.modle; 518 519 Assert.checkNonNull(msym, p::toString); 520 521 msym.complete(); 522 523 if (msym == syms.noModule) { 524 preferCurrent = false; 525 if (userPathsFirst) { 526 scanUserPaths(p, true); 527 preferCurrent = true; 528 scanPlatformPath(p); 529 } else { 530 scanPlatformPath(p); 531 scanUserPaths(p, true); 532 } 533 } else if (msym.classLocation == StandardLocation.CLASS_PATH) { 534 scanUserPaths(p, msym.sourceLocation == StandardLocation.SOURCE_PATH); 535 } else { 536 scanModulePaths(p, msym); 537 } 538 } 539 540 // TODO: for now, this is a much simplified form of scanUserPaths 541 // and (deliberately) does not default sourcepath to classpath. 542 // But, we need to think about retaining existing behavior for 543 // -classpath and -sourcepath for single module mode. 544 // One plausible solution is to detect if the module's sourceLocation 545 // is the same as the module's classLocation. 546 private void scanModulePaths(PackageSymbol p, ModuleSymbol msym) throws IOException { 547 Set<JavaFileObject.Kind> kinds = getPackageFileKinds(); 548 549 Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds); 550 classKinds.remove(JavaFileObject.Kind.SOURCE); 551 boolean wantClassFiles = !classKinds.isEmpty(); 552 553 Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds); 554 sourceKinds.remove(JavaFileObject.Kind.CLASS); 555 boolean wantSourceFiles = !sourceKinds.isEmpty(); 556 557 String packageName = p.fullname.toString(); 558 559 Location classLocn = msym.classLocation; 560 Location sourceLocn = msym.sourceLocation; 561 Location patchLocn = msym.patchLocation; 562 Location patchOutLocn = msym.patchOutputLocation; 563 564 boolean prevPreferCurrent = preferCurrent; 565 566 try { 567 preferCurrent = false; 568 if (wantClassFiles && (patchOutLocn != null)) { 569 fillIn(p, patchOutLocn, 570 list(patchOutLocn, 571 p, 572 packageName, 573 classKinds)); 574 } 575 if ((wantClassFiles || wantSourceFiles) && (patchLocn != null)) { 576 Set<JavaFileObject.Kind> combined = EnumSet.noneOf(JavaFileObject.Kind.class); 577 combined.addAll(classKinds); 578 combined.addAll(sourceKinds); 579 fillIn(p, patchLocn, 580 list(patchLocn, 581 p, 582 packageName, 583 combined)); 584 } 585 preferCurrent = true; 586 if (wantClassFiles && (classLocn != null)) { 587 fillIn(p, classLocn, 588 list(classLocn, 589 p, 590 packageName, 591 classKinds)); 592 } 593 if (wantSourceFiles && (sourceLocn != null)) { 594 fillIn(p, sourceLocn, 595 list(sourceLocn, 596 p, 597 packageName, 598 sourceKinds)); 599 } 600 } finally { 601 preferCurrent = prevPreferCurrent; 602 } 603 } 604 605 /** 606 * Scans class path and source path for files in given package. 607 */ 608 private void scanUserPaths(PackageSymbol p, boolean includeSourcePath) throws IOException { 609 Set<JavaFileObject.Kind> kinds = getPackageFileKinds(); 610 611 Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds); 612 classKinds.remove(JavaFileObject.Kind.SOURCE); 613 boolean wantClassFiles = !classKinds.isEmpty(); 614 615 Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds); 616 sourceKinds.remove(JavaFileObject.Kind.CLASS); 617 boolean wantSourceFiles = !sourceKinds.isEmpty(); 618 619 boolean haveSourcePath = includeSourcePath && fileManager.hasLocation(SOURCE_PATH); 620 621 if (verbose && verbosePath) { 622 if (fileManager instanceof StandardJavaFileManager) { 623 StandardJavaFileManager fm = (StandardJavaFileManager)fileManager; 624 if (haveSourcePath && wantSourceFiles) { 625 List<Path> path = List.nil(); 626 for (Path sourcePath : fm.getLocationAsPaths(SOURCE_PATH)) { 627 path = path.prepend(sourcePath); 628 } 629 log.printVerbose("sourcepath", path.reverse().toString()); 630 } else if (wantSourceFiles) { 631 List<Path> path = List.nil(); 632 for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) { 633 path = path.prepend(classPath); 634 } 635 log.printVerbose("sourcepath", path.reverse().toString()); 636 } 637 if (wantClassFiles) { 638 List<Path> path = List.nil(); 639 for (Path platformPath : fm.getLocationAsPaths(PLATFORM_CLASS_PATH)) { 640 path = path.prepend(platformPath); 641 } 642 for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) { 643 path = path.prepend(classPath); 644 } 645 log.printVerbose("classpath", path.reverse().toString()); 646 } 647 } 648 } 649 650 String packageName = p.fullname.toString(); 651 if (wantSourceFiles && !haveSourcePath) { 652 fillIn(p, CLASS_PATH, 653 list(CLASS_PATH, 654 p, 655 packageName, 656 kinds)); 657 } else { 658 if (wantClassFiles) 659 fillIn(p, CLASS_PATH, 660 list(CLASS_PATH, 661 p, 662 packageName, 663 classKinds)); 664 if (wantSourceFiles) 665 fillIn(p, SOURCE_PATH, 666 list(SOURCE_PATH, 667 p, 668 packageName, 669 sourceKinds)); 670 } 671 } 672 673 /** 674 * Scans platform class path for files in given package. 675 */ 676 private void scanPlatformPath(PackageSymbol p) throws IOException { 677 fillIn(p, PLATFORM_CLASS_PATH, 678 list(PLATFORM_CLASS_PATH, 679 p, 680 p.fullname.toString(), 681 allowSigFiles ? EnumSet.of(JavaFileObject.Kind.CLASS, 682 JavaFileObject.Kind.OTHER) 683 : EnumSet.of(JavaFileObject.Kind.CLASS))); 684 } 685 // where 686 @SuppressWarnings("fallthrough") 687 private void fillIn(PackageSymbol p, 688 Location location, 689 Iterable<JavaFileObject> files) 690 { 691 currentLoc = location; 692 for (JavaFileObject fo : files) { 693 switch (fo.getKind()) { 694 case OTHER: 695 if (!isSigFile(location, fo)) { 696 extraFileActions(p, fo); 697 break; 698 } 699 //intentional fall-through: 700 case CLASS: 701 case SOURCE: { 702 // TODO pass binaryName to includeClassFile 703 String binaryName = fileManager.inferBinaryName(currentLoc, fo); 704 String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1); 705 if (SourceVersion.isIdentifier(simpleName) || 706 simpleName.equals("package-info")) 707 includeClassFile(p, fo); 708 break; 709 } 710 default: 711 extraFileActions(p, fo); 712 break; 713 } 714 } 715 } 716 717 boolean isSigFile(Location location, JavaFileObject fo) { 718 return location == PLATFORM_CLASS_PATH && 719 allowSigFiles && 720 fo.getName().endsWith(".sig"); 721 } 722 723 Iterable<JavaFileObject> list(Location location, 724 PackageSymbol p, 725 String packageName, 726 Set<Kind> kinds) throws IOException { 727 Iterable<JavaFileObject> listed = fileManager.list(location, 728 packageName, 729 EnumSet.allOf(Kind.class), 730 false); 731 return () -> new Iterator<JavaFileObject>() { 732 private final Iterator<JavaFileObject> original = listed.iterator(); 733 private JavaFileObject next; 734 @Override 735 public boolean hasNext() { 736 if (next == null) { 737 while (original.hasNext()) { 738 JavaFileObject fo = original.next(); 739 740 if (fo.getKind() != Kind.CLASS && 741 fo.getKind() != Kind.SOURCE && 742 !isSigFile(currentLoc, fo)) { 743 p.flags_field |= Flags.HAS_RESOURCE; 744 } 745 746 if (kinds.contains(fo.getKind())) { 747 next = fo; 748 break; 749 } 750 } 751 } 752 return next != null; 753 } 754 755 @Override 756 public JavaFileObject next() { 757 if (!hasNext()) 758 throw new NoSuchElementException(); 759 JavaFileObject result = next; 760 next = null; 761 return result; 762 } 763 764 }; 765 } 766 767 /** 768 * Used for bad class definition files, such as bad .class files or 769 * for .java files with unexpected package or class names. 770 */ 771 public static class BadClassFile extends CompletionFailure { 772 private static final long serialVersionUID = 0; 773 774 public BadClassFile(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag, 775 JCDiagnostic.Factory diagFactory) { 776 super(sym, createBadClassFileDiagnostic(file, diag, diagFactory)); 777 } 778 // where 779 private static JCDiagnostic createBadClassFileDiagnostic( 780 JavaFileObject file, JCDiagnostic diag, JCDiagnostic.Factory diagFactory) { 781 String key = (file.getKind() == JavaFileObject.Kind.SOURCE 782 ? "bad.source.file.header" : "bad.class.file.header"); 783 return diagFactory.fragment(key, file, diag); 784 } 785 } 786 787 public static class BadEnclosingMethodAttr extends BadClassFile { 788 private static final long serialVersionUID = 0; 789 790 public BadEnclosingMethodAttr(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag, 791 JCDiagnostic.Factory diagFactory) { 792 super(sym, file, diag, diagFactory); 793 } 794 } 795} 796