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