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