ClassFinder.java revision 3634:5a2d38a840cc
1271743Sbz/*
2271743Sbz * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
3271743Sbz * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4271743Sbz *
5271743Sbz * This code is free software; you can redistribute it and/or modify it
6271743Sbz * under the terms of the GNU General Public License version 2 only, as
7271743Sbz * published by the Free Software Foundation.  Oracle designates this
8271743Sbz * particular file as subject to the "Classpath" exception as provided
9271743Sbz * by Oracle in the LICENSE file that accompanied this code.
10271743Sbz *
11271743Sbz * This code is distributed in the hope that it will be useful, but WITHOUT
12271743Sbz * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13271743Sbz * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14271743Sbz * version 2 for more details (a copy is included in the LICENSE file that
15271743Sbz * accompanied this code).
16271743Sbz *
17271743Sbz * You should have received a copy of the GNU General Public License version
18271743Sbz * 2 along with this work; if not, write to the Free Software Foundation,
19271743Sbz * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20271743Sbz *
21271743Sbz * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22271743Sbz * or visit www.oracle.com if you need additional information or have any
23271743Sbz * questions.
24271743Sbz */
25271743Sbz
26271743Sbzpackage com.sun.tools.javac.code;
27271743Sbz
28271743Sbzimport java.io.IOException;
29271743Sbzimport java.nio.file.Path;
30271743Sbzimport java.util.EnumSet;
31271743Sbzimport java.util.HashMap;
32271743Sbzimport java.util.Map;
33271743Sbzimport java.util.Set;
34271743Sbz
35271743Sbzimport javax.lang.model.SourceVersion;
36271743Sbzimport javax.tools.JavaFileManager;
37271743Sbzimport javax.tools.JavaFileManager.Location;
38271743Sbzimport javax.tools.JavaFileObject;
39271743Sbzimport javax.tools.StandardJavaFileManager;
40271743Sbzimport javax.tools.StandardLocation;
41271743Sbz
42271743Sbzimport com.sun.tools.javac.code.Scope.WriteableScope;
43271743Sbzimport com.sun.tools.javac.code.Symbol.ClassSymbol;
44271743Sbzimport com.sun.tools.javac.code.Symbol.Completer;
45271743Sbzimport com.sun.tools.javac.code.Symbol.CompletionFailure;
46271743Sbzimport com.sun.tools.javac.code.Symbol.ModuleSymbol;
47271743Sbzimport com.sun.tools.javac.code.Symbol.PackageSymbol;
48271743Sbzimport com.sun.tools.javac.code.Symbol.TypeSymbol;
49271743Sbzimport com.sun.tools.javac.comp.Annotate;
50271743Sbzimport com.sun.tools.javac.file.JRTIndex;
51271743Sbzimport com.sun.tools.javac.file.JavacFileManager;
52271743Sbzimport com.sun.tools.javac.jvm.ClassReader;
53271743Sbzimport com.sun.tools.javac.jvm.Profile;
54271743Sbzimport com.sun.tools.javac.main.Option;
55271743Sbzimport com.sun.tools.javac.platform.PlatformDescription;
56271743Sbzimport com.sun.tools.javac.util.*;
57271743Sbz
58271743Sbzimport static javax.tools.StandardLocation.*;
59271743Sbz
60292744Sdchaginimport static com.sun.tools.javac.code.Flags.*;
61292744Sdchaginimport static com.sun.tools.javac.code.Kinds.Kind.*;
62271743Sbz
63283476Sdchaginimport com.sun.tools.javac.util.Dependencies.CompletionCause;
64271743Sbz
65271743Sbz/**
66271743Sbz *  This class provides operations to locate class definitions
67271743Sbz *  from the source and class files on the paths provided to javac.
68271743Sbz *
69271743Sbz *  <p><b>This is NOT part of any supported API.
70271743Sbz *  If you write code that depends on this, you do so at your own risk.
71271743Sbz *  This code and its internal interfaces are subject to change or
72271743Sbz *  deletion without notice.</b>
73271743Sbz */
74271743Sbzpublic class ClassFinder {
75271743Sbz    /** The context key for the class finder. */
76271743Sbz    protected static final Context.Key<ClassFinder> classFinderKey = new Context.Key<>();
77271743Sbz
78292744Sdchagin    ClassReader reader;
79292744Sdchagin
80271743Sbz    private final Annotate annotate;
81271743Sbz
82283476Sdchagin    /** Switch: verbose output.
83271743Sbz     */
84271743Sbz    boolean verbose;
85271743Sbz
86271743Sbz    /**
87271743Sbz     * Switch: cache completion failures unless -XDdev is used
88271743Sbz     */
89271743Sbz    private boolean cacheCompletionFailure;
90271743Sbz
91271743Sbz    /**
92271743Sbz     * Switch: prefer source files instead of newer when both source
93271743Sbz     * and class are available
94271743Sbz     **/
95271743Sbz    protected boolean preferSource;
96283464Sdchagin
97271743Sbz    /**
98271743Sbz     * Switch: Search classpath and sourcepath for classes before the
99271743Sbz     * bootclasspath
100271743Sbz     */
101271743Sbz    protected boolean userPathsFirst;
102271743Sbz
103271743Sbz    /**
104271743Sbz     * Switch: should read OTHER classfiles (.sig files) from PLATFORM_CLASS_PATH.
105271743Sbz     */
106271743Sbz    private boolean allowSigFiles;
107271743Sbz
108271743Sbz    /** The log to use for verbose output
109271743Sbz     */
110283464Sdchagin    final Log log;
111271743Sbz
112271743Sbz    /** The symbol table. */
113283464Sdchagin    Symtab syms;
114271743Sbz
115271743Sbz    /** The name table. */
116271743Sbz    final Names names;
117271743Sbz
118271743Sbz    /** Force a completion failure on this name
119271743Sbz     */
120271743Sbz    final Name completionFailureName;
121271743Sbz
122271743Sbz    /** Access to files
123271743Sbz     */
124271743Sbz    private final JavaFileManager fileManager;
125271743Sbz
126271743Sbz    /** Dependency tracker
127271743Sbz     */
128271743Sbz    private final Dependencies dependencies;
129271743Sbz
130271743Sbz    /** Factory for diagnostics
131271743Sbz     */
132271743Sbz    JCDiagnostic.Factory diagFactory;
133271743Sbz
134271743Sbz    /** Can be reassigned from outside:
135271743Sbz     *  the completer to be used for ".java" files. If this remains unassigned
136271743Sbz     *  ".java" files will not be loaded.
137271743Sbz     */
138271743Sbz    public Completer sourceCompleter = Completer.NULL_COMPLETER;
139271743Sbz
140271743Sbz    /** The path name of the class file currently being read.
141271743Sbz     */
142271743Sbz    protected JavaFileObject currentClassFile = null;
143271743Sbz
144271743Sbz    /** The class or method currently being read.
145271743Sbz     */
146271743Sbz    protected Symbol currentOwner = null;
147271743Sbz
148271743Sbz    /**
149271743Sbz     * The currently selected profile.
150271743Sbz     */
151271743Sbz    private final Profile profile;
152271743Sbz
153271743Sbz    /**
154271743Sbz     * Use direct access to the JRTIndex to access the temporary
155271743Sbz     * replacement for the info that used to be in ct.sym.
156271743Sbz     * In time, this will go away and be replaced by the module system.
157271743Sbz     */
158271743Sbz    private final JRTIndex jrtIndex;
159271743Sbz
160271743Sbz    /**
161271743Sbz     * Completer that delegates to the complete-method of this class.
162271743Sbz     */
163271743Sbz    private final Completer thisCompleter = new Completer() {
164271743Sbz        @Override
165271743Sbz        public void complete(Symbol sym) throws CompletionFailure {
166271743Sbz            ClassFinder.this.complete(sym);
167271743Sbz        }
168271743Sbz    };
169271743Sbz
170    public Completer getCompleter() {
171        return thisCompleter;
172    }
173
174    /** Get the ClassFinder instance for this invocation. */
175    public static ClassFinder instance(Context context) {
176        ClassFinder instance = context.get(classFinderKey);
177        if (instance == null)
178            instance = new ClassFinder(context);
179        return instance;
180    }
181
182    /** Construct a new class finder. */
183    protected ClassFinder(Context context) {
184        context.put(classFinderKey, this);
185        reader = ClassReader.instance(context);
186        names = Names.instance(context);
187        syms = Symtab.instance(context);
188        fileManager = context.get(JavaFileManager.class);
189        dependencies = Dependencies.instance(context);
190        if (fileManager == null)
191            throw new AssertionError("FileManager initialization error");
192        diagFactory = JCDiagnostic.Factory.instance(context);
193
194        log = Log.instance(context);
195        annotate = Annotate.instance(context);
196
197        Options options = Options.instance(context);
198        verbose = options.isSet(Option.VERBOSE);
199        cacheCompletionFailure = options.isUnset("dev");
200        preferSource = "source".equals(options.get("-Xprefer"));
201        userPathsFirst = options.isSet(Option.XXUSERPATHSFIRST);
202        allowSigFiles = context.get(PlatformDescription.class) != null;
203
204        completionFailureName =
205            options.isSet("failcomplete")
206            ? names.fromString(options.get("failcomplete"))
207            : null;
208
209        // Temporary, until more info is available from the module system.
210        boolean useCtProps;
211        JavaFileManager fm = context.get(JavaFileManager.class);
212        if (fm instanceof JavacFileManager) {
213            JavacFileManager jfm = (JavacFileManager) fm;
214            useCtProps = jfm.isDefaultBootClassPath() && jfm.isSymbolFileEnabled();
215        } else if (fm.getClass().getName().equals("com.sun.tools.sjavac.comp.SmartFileManager")) {
216            useCtProps = !options.isSet("ignore.symbol.file");
217        } else {
218            useCtProps = false;
219        }
220        jrtIndex = useCtProps && JRTIndex.isAvailable() ? JRTIndex.getSharedInstance() : null;
221
222        profile = Profile.instance(context);
223    }
224
225
226/************************************************************************
227 * Temporary ct.sym replacement
228 *
229 * The following code is a temporary substitute for the ct.sym mechanism
230 * used in JDK 6 thru JDK 8.
231 * This mechanism will eventually be superseded by the Jigsaw module system.
232 ***********************************************************************/
233
234    /**
235     * Returns any extra flags for a class symbol.
236     * This information used to be provided using private annotations
237     * in the class file in ct.sym; in time, this information will be
238     * available from the module system.
239     */
240    long getSupplementaryFlags(ClassSymbol c) {
241        if (jrtIndex == null || !jrtIndex.isInJRT(c.classfile) || c.name == names.module_info) {
242            return 0;
243        }
244
245        if (supplementaryFlags == null) {
246            supplementaryFlags = new HashMap<>();
247        }
248
249        Long flags = supplementaryFlags.get(c.packge());
250        if (flags == null) {
251            long newFlags = 0;
252            try {
253                JRTIndex.CtSym ctSym = jrtIndex.getCtSym(c.packge().flatName());
254                Profile minProfile = Profile.DEFAULT;
255                if (ctSym.proprietary)
256                    newFlags |= PROPRIETARY;
257                if (ctSym.minProfile != null)
258                    minProfile = Profile.lookup(ctSym.minProfile);
259                if (profile != Profile.DEFAULT && minProfile.value > profile.value) {
260                    newFlags |= NOT_IN_PROFILE;
261                }
262            } catch (IOException ignore) {
263            }
264            supplementaryFlags.put(c.packge(), flags = newFlags);
265        }
266        return flags;
267    }
268
269    private Map<PackageSymbol, Long> supplementaryFlags;
270
271/************************************************************************
272 * Loading Classes
273 ***********************************************************************/
274
275    /** Completion for classes to be loaded. Before a class is loaded
276     *  we make sure its enclosing class (if any) is loaded.
277     */
278    private void complete(Symbol sym) throws CompletionFailure {
279        if (sym.kind == TYP) {
280            try {
281                ClassSymbol c = (ClassSymbol) sym;
282                dependencies.push(c, CompletionCause.CLASS_READER);
283                annotate.blockAnnotations();
284                c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
285                completeOwners(c.owner);
286                completeEnclosing(c);
287                fillIn(c);
288            } finally {
289                annotate.unblockAnnotationsNoFlush();
290                dependencies.pop();
291            }
292        } else if (sym.kind == PCK) {
293            PackageSymbol p = (PackageSymbol)sym;
294            try {
295                fillIn(p);
296            } catch (IOException ex) {
297                throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex);
298            }
299        }
300        if (!reader.filling)
301            annotate.flush(); // finish attaching annotations
302    }
303
304    /** complete up through the enclosing package. */
305    private void completeOwners(Symbol o) {
306        if (o.kind != PCK) completeOwners(o.owner);
307        o.complete();
308    }
309
310    /**
311     * Tries to complete lexically enclosing classes if c looks like a
312     * nested class.  This is similar to completeOwners but handles
313     * the situation when a nested class is accessed directly as it is
314     * possible with the Tree API or javax.lang.model.*.
315     */
316    private void completeEnclosing(ClassSymbol c) {
317        if (c.owner.kind == PCK) {
318            Symbol owner = c.owner;
319            for (Name name : Convert.enclosingCandidates(Convert.shortName(c.name))) {
320                Symbol encl = owner.members().findFirst(name);
321                if (encl == null)
322                    encl = syms.getClass(c.packge().modle, TypeSymbol.formFlatName(name, owner));
323                if (encl != null)
324                    encl.complete();
325            }
326        }
327    }
328
329    /** Fill in definition of class `c' from corresponding class or
330     *  source file.
331     */
332    void fillIn(ClassSymbol c) {
333        if (completionFailureName == c.fullname) {
334            throw new CompletionFailure(c, "user-selected completion failure by class name");
335        }
336        currentOwner = c;
337        JavaFileObject classfile = c.classfile;
338        if (classfile != null) {
339            JavaFileObject previousClassFile = currentClassFile;
340            try {
341                if (reader.filling) {
342                    Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile);
343                }
344                currentClassFile = classfile;
345                if (verbose) {
346                    log.printVerbose("loading", currentClassFile.getName());
347                }
348                if (classfile.getKind() == JavaFileObject.Kind.CLASS ||
349                    classfile.getKind() == JavaFileObject.Kind.OTHER) {
350                    reader.readClassFile(c);
351                    c.flags_field |= getSupplementaryFlags(c);
352                } else {
353                    if (!sourceCompleter.isTerminal()) {
354                        sourceCompleter.complete(c);
355                    } else {
356                        throw new IllegalStateException("Source completer required to read "
357                                                        + classfile.toUri());
358                    }
359                }
360            } finally {
361                currentClassFile = previousClassFile;
362            }
363        } else {
364            throw classFileNotFound(c);
365        }
366    }
367    // where
368        private CompletionFailure classFileNotFound(ClassSymbol c) {
369            JCDiagnostic diag =
370                diagFactory.fragment("class.file.not.found", c.flatname);
371            return newCompletionFailure(c, diag);
372        }
373        /** Static factory for CompletionFailure objects.
374         *  In practice, only one can be used at a time, so we share one
375         *  to reduce the expense of allocating new exception objects.
376         */
377        private CompletionFailure newCompletionFailure(TypeSymbol c,
378                                                       JCDiagnostic diag) {
379            if (!cacheCompletionFailure) {
380                // log.warning("proc.messager",
381                //             Log.getLocalizedString("class.file.not.found", c.flatname));
382                // c.debug.printStackTrace();
383                return new CompletionFailure(c, diag);
384            } else {
385                CompletionFailure result = cachedCompletionFailure;
386                result.sym = c;
387                result.diag = diag;
388                return result;
389            }
390        }
391        private final CompletionFailure cachedCompletionFailure =
392            new CompletionFailure(null, (JCDiagnostic) null);
393        {
394            cachedCompletionFailure.setStackTrace(new StackTraceElement[0]);
395        }
396
397
398    /** Load a toplevel class with given fully qualified name
399     *  The class is entered into `classes' only if load was successful.
400     */
401    public ClassSymbol loadClass(ModuleSymbol msym, Name flatname) throws CompletionFailure {
402        Assert.checkNonNull(msym);
403        Name packageName = Convert.packagePart(flatname);
404        PackageSymbol ps = syms.lookupPackage(msym, packageName);
405
406        Assert.checkNonNull(ps.modle, () -> "msym=" + msym + "; flatName=" + flatname);
407
408        boolean absent = syms.getClass(ps.modle, flatname) == null;
409        ClassSymbol c = syms.enterClass(ps.modle, flatname);
410
411        if (c.members_field == null) {
412            try {
413                c.complete();
414            } catch (CompletionFailure ex) {
415                if (absent) syms.removeClass(ps.modle, flatname);
416                throw ex;
417            }
418        }
419        return c;
420    }
421
422/************************************************************************
423 * Loading Packages
424 ***********************************************************************/
425
426    /** Include class corresponding to given class file in package,
427     *  unless (1) we already have one the same kind (.class or .java), or
428     *         (2) we have one of the other kind, and the given class file
429     *             is older.
430     */
431    protected void includeClassFile(PackageSymbol p, JavaFileObject file) {
432        if ((p.flags_field & EXISTS) == 0)
433            for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
434                q.flags_field |= EXISTS;
435        JavaFileObject.Kind kind = file.getKind();
436        int seen;
437        if (kind == JavaFileObject.Kind.CLASS || kind == JavaFileObject.Kind.OTHER)
438            seen = CLASS_SEEN;
439        else
440            seen = SOURCE_SEEN;
441        String binaryName = fileManager.inferBinaryName(currentLoc, file);
442        int lastDot = binaryName.lastIndexOf(".");
443        Name classname = names.fromString(binaryName.substring(lastDot + 1));
444        boolean isPkgInfo = classname == names.package_info;
445        ClassSymbol c = isPkgInfo
446            ? p.package_info
447            : (ClassSymbol) p.members_field.findFirst(classname);
448        if (c == null) {
449            c = syms.enterClass(p.modle, classname, p);
450            if (c.classfile == null) // only update the file if's it's newly created
451                c.classfile = file;
452            if (isPkgInfo) {
453                p.package_info = c;
454            } else {
455                if (c.owner == p)  // it might be an inner class
456                    p.members_field.enter(c);
457            }
458        } else if (!preferCurrent && c.classfile != null && (c.flags_field & seen) == 0) {
459            // if c.classfile == null, we are currently compiling this class
460            // and no further action is necessary.
461            // if (c.flags_field & seen) != 0, we have already encountered
462            // a file of the same kind; again no further action is necessary.
463            if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0)
464                c.classfile = preferredFileObject(file, c.classfile);
465        }
466        c.flags_field |= seen;
467    }
468
469    /** Implement policy to choose to derive information from a source
470     *  file or a class file when both are present.  May be overridden
471     *  by subclasses.
472     */
473    protected JavaFileObject preferredFileObject(JavaFileObject a,
474                                           JavaFileObject b) {
475
476        if (preferSource)
477            return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b;
478        else {
479            long adate = a.getLastModified();
480            long bdate = b.getLastModified();
481            // 6449326: policy for bad lastModifiedTime in ClassReader
482            //assert adate >= 0 && bdate >= 0;
483            return (adate > bdate) ? a : b;
484        }
485    }
486
487    /**
488     * specifies types of files to be read when filling in a package symbol
489     */
490    // Note: overridden by JavadocClassFinder
491    protected EnumSet<JavaFileObject.Kind> getPackageFileKinds() {
492        return EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.SOURCE);
493    }
494
495    /**
496     * this is used to support javadoc
497     */
498    protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) {
499    }
500
501    protected Location currentLoc; // FIXME
502
503    private boolean verbosePath = true;
504
505    // Set to true when the currently selected file should be kept
506    private boolean preferCurrent;
507
508    /** Load directory of package into members scope.
509     */
510    private void fillIn(PackageSymbol p) throws IOException {
511        if (p.members_field == null)
512            p.members_field = WriteableScope.create(p);
513
514        ModuleSymbol msym = p.modle;
515
516        Assert.checkNonNull(msym, () -> p.toString());
517
518        msym.complete();
519
520        if (msym == syms.noModule) {
521            preferCurrent = false;
522            if (userPathsFirst) {
523                scanUserPaths(p, true);
524                preferCurrent = true;
525                scanPlatformPath(p);
526            } else {
527                scanPlatformPath(p);
528                scanUserPaths(p, true);
529            }
530        } else if (msym.classLocation == StandardLocation.CLASS_PATH) {
531            scanUserPaths(p, msym.sourceLocation == StandardLocation.SOURCE_PATH);
532        } else {
533            scanModulePaths(p, msym);
534        }
535    }
536
537    // TODO: for now, this is a much simplified form of scanUserPaths
538    // and (deliberately) does not default sourcepath to classpath.
539    // But, we need to think about retaining existing behavior for
540    // -classpath and -sourcepath for single module mode.
541    // One plausible solution is to detect if the module's sourceLocation
542    // is the same as the module's classLocation.
543    private void scanModulePaths(PackageSymbol p, ModuleSymbol msym) throws IOException {
544        Set<JavaFileObject.Kind> kinds = getPackageFileKinds();
545
546        Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds);
547        classKinds.remove(JavaFileObject.Kind.SOURCE);
548        boolean wantClassFiles = !classKinds.isEmpty();
549
550        Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds);
551        sourceKinds.remove(JavaFileObject.Kind.CLASS);
552        boolean wantSourceFiles = !sourceKinds.isEmpty();
553
554        String packageName = p.fullname.toString();
555
556        Location classLocn = msym.classLocation;
557        Location sourceLocn = msym.sourceLocation;
558
559        if (wantClassFiles && (classLocn != null)) {
560            fillIn(p, classLocn,
561                   fileManager.list(classLocn,
562                                    packageName,
563                                    classKinds,
564                                    false));
565        }
566        if (wantSourceFiles && (sourceLocn != null)) {
567            fillIn(p, sourceLocn,
568                   fileManager.list(sourceLocn,
569                                    packageName,
570                                    sourceKinds,
571                                    false));
572        }
573    }
574
575    /**
576     * Scans class path and source path for files in given package.
577     */
578    private void scanUserPaths(PackageSymbol p, boolean includeSourcePath) throws IOException {
579        Set<JavaFileObject.Kind> kinds = getPackageFileKinds();
580
581        Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds);
582        classKinds.remove(JavaFileObject.Kind.SOURCE);
583        boolean wantClassFiles = !classKinds.isEmpty();
584
585        Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds);
586        sourceKinds.remove(JavaFileObject.Kind.CLASS);
587        boolean wantSourceFiles = !sourceKinds.isEmpty();
588
589        boolean haveSourcePath = includeSourcePath && fileManager.hasLocation(SOURCE_PATH);
590
591        if (verbose && verbosePath) {
592            if (fileManager instanceof StandardJavaFileManager) {
593                StandardJavaFileManager fm = (StandardJavaFileManager)fileManager;
594                if (haveSourcePath && wantSourceFiles) {
595                    List<Path> path = List.nil();
596                    for (Path sourcePath : fm.getLocationAsPaths(SOURCE_PATH)) {
597                        path = path.prepend(sourcePath);
598                    }
599                    log.printVerbose("sourcepath", path.reverse().toString());
600                } else if (wantSourceFiles) {
601                    List<Path> path = List.nil();
602                    for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) {
603                        path = path.prepend(classPath);
604                    }
605                    log.printVerbose("sourcepath", path.reverse().toString());
606                }
607                if (wantClassFiles) {
608                    List<Path> path = List.nil();
609                    for (Path platformPath : fm.getLocationAsPaths(PLATFORM_CLASS_PATH)) {
610                        path = path.prepend(platformPath);
611                    }
612                    for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) {
613                        path = path.prepend(classPath);
614                    }
615                    log.printVerbose("classpath",  path.reverse().toString());
616                }
617            }
618        }
619
620        String packageName = p.fullname.toString();
621        if (wantSourceFiles && !haveSourcePath) {
622            fillIn(p, CLASS_PATH,
623                   fileManager.list(CLASS_PATH,
624                                    packageName,
625                                    kinds,
626                                    false));
627        } else {
628            if (wantClassFiles)
629                fillIn(p, CLASS_PATH,
630                       fileManager.list(CLASS_PATH,
631                                        packageName,
632                                        classKinds,
633                                        false));
634            if (wantSourceFiles)
635                fillIn(p, SOURCE_PATH,
636                       fileManager.list(SOURCE_PATH,
637                                        packageName,
638                                        sourceKinds,
639                                        false));
640        }
641    }
642
643    /**
644     * Scans platform class path for files in given package.
645     */
646    private void scanPlatformPath(PackageSymbol p) throws IOException {
647        fillIn(p, PLATFORM_CLASS_PATH,
648               fileManager.list(PLATFORM_CLASS_PATH,
649                                p.fullname.toString(),
650                                allowSigFiles ? EnumSet.of(JavaFileObject.Kind.CLASS,
651                                                           JavaFileObject.Kind.OTHER)
652                                              : EnumSet.of(JavaFileObject.Kind.CLASS),
653                                false));
654    }
655    // where
656        @SuppressWarnings("fallthrough")
657        private void fillIn(PackageSymbol p,
658                            Location location,
659                            Iterable<JavaFileObject> files)
660        {
661            currentLoc = location;
662            for (JavaFileObject fo : files) {
663                switch (fo.getKind()) {
664                case OTHER:
665                    boolean sigFile = location == PLATFORM_CLASS_PATH &&
666                                      allowSigFiles &&
667                                      fo.getName().endsWith(".sig");
668                    if (!sigFile) {
669                        extraFileActions(p, fo);
670                        break;
671                    }
672                    //intentional fall-through:
673                case CLASS:
674                case SOURCE: {
675                    // TODO pass binaryName to includeClassFile
676                    String binaryName = fileManager.inferBinaryName(currentLoc, fo);
677                    String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
678                    if (SourceVersion.isIdentifier(simpleName) ||
679                        simpleName.equals("package-info"))
680                        includeClassFile(p, fo);
681                    break;
682                }
683                default:
684                    extraFileActions(p, fo);
685                }
686            }
687        }
688
689    /**
690     * Used for bad class definition files, such as bad .class files or
691     * for .java files with unexpected package or class names.
692     */
693    public static class BadClassFile extends CompletionFailure {
694        private static final long serialVersionUID = 0;
695
696        public BadClassFile(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag,
697                JCDiagnostic.Factory diagFactory) {
698            super(sym, createBadClassFileDiagnostic(file, diag, diagFactory));
699        }
700        // where
701        private static JCDiagnostic createBadClassFileDiagnostic(
702                JavaFileObject file, JCDiagnostic diag, JCDiagnostic.Factory diagFactory) {
703            String key = (file.getKind() == JavaFileObject.Kind.SOURCE
704                        ? "bad.source.file.header" : "bad.class.file.header");
705            return diagFactory.fragment(key, file, diag);
706        }
707    }
708
709    public static class BadEnclosingMethodAttr extends BadClassFile {
710        private static final long serialVersionUID = 0;
711
712        public BadEnclosingMethodAttr(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag,
713                JCDiagnostic.Factory diagFactory) {
714            super(sym, file, diag, diagFactory);
715        }
716    }
717}
718