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 |
}
|