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