33 import java.util.Set;
34
35 import javax.lang.model.SourceVersion;
36 import javax.tools.JavaFileManager;
37 import javax.tools.JavaFileManager.Location;
38 import javax.tools.JavaFileObject;
39 import javax.tools.StandardJavaFileManager;
40
41 import com.sun.tools.javac.code.Scope.WriteableScope;
42 import com.sun.tools.javac.code.Symbol.ClassSymbol;
43 import com.sun.tools.javac.code.Symbol.Completer;
44 import com.sun.tools.javac.code.Symbol.CompletionFailure;
45 import com.sun.tools.javac.code.Symbol.PackageSymbol;
46 import com.sun.tools.javac.code.Symbol.TypeSymbol;
47 import com.sun.tools.javac.comp.Annotate;
48 import com.sun.tools.javac.comp.Enter;
49 import com.sun.tools.javac.file.JRTIndex;
50 import com.sun.tools.javac.file.JavacFileManager;
51 import com.sun.tools.javac.jvm.ClassReader;
52 import com.sun.tools.javac.jvm.Profile;
53 import com.sun.tools.javac.util.*;
54
55 import static javax.tools.StandardLocation.*;
56
57 import static com.sun.tools.javac.code.Flags.*;
58 import static com.sun.tools.javac.code.Kinds.Kind.*;
59
60 import static com.sun.tools.javac.main.Option.*;
61 import com.sun.tools.javac.util.Dependencies.CompletionCause;
62
63 /**
64 * This class provides operations to locate class definitions
65 * from the source and class files on the paths provided to javac.
66 *
67 * <p><b>This is NOT part of any supported API.
68 * If you write code that depends on this, you do so at your own risk.
69 * This code and its internal interfaces are subject to change or
70 * deletion without notice.</b>
71 */
72 public class ClassFinder {
73 /** The context key for the class finder. */
74 protected static final Context.Key<ClassFinder> classFinderKey = new Context.Key<>();
75
76 ClassReader reader;
77
78 private final Annotate annotate;
79
80 /** Switch: verbose output.
81 */
82 boolean verbose;
83
84 /**
85 * Switch: cache completion failures unless -XDdev is used
86 */
87 private boolean cacheCompletionFailure;
88
89 /**
90 * Switch: prefer source files instead of newer when both source
91 * and class are available
92 **/
93 protected boolean preferSource;
94
95 /**
96 * Switch: Search classpath and sourcepath for classes before the
97 * bootclasspath
98 */
99 protected boolean userPathsFirst;
100
101 /** The log to use for verbose output
102 */
103 final Log log;
104
105 /** The symbol table. */
106 Symtab syms;
107
108 /** The name table. */
109 final Names names;
110
111 /** Force a completion failure on this name
112 */
113 final Name completionFailureName;
114
115 /** Access to files
116 */
117 private final JavaFileManager fileManager;
118
119 /** Dependency tracker
120 */
175 /** Construct a new class reader. */
176 protected ClassFinder(Context context) {
177 context.put(classFinderKey, this);
178 reader = ClassReader.instance(context);
179 names = Names.instance(context);
180 syms = Symtab.instance(context);
181 fileManager = context.get(JavaFileManager.class);
182 dependencies = Dependencies.instance(context);
183 if (fileManager == null)
184 throw new AssertionError("FileManager initialization error");
185 diagFactory = JCDiagnostic.Factory.instance(context);
186
187 log = Log.instance(context);
188 annotate = Annotate.instance(context);
189
190 Options options = Options.instance(context);
191 verbose = options.isSet(VERBOSE);
192 cacheCompletionFailure = options.isUnset("dev");
193 preferSource = "source".equals(options.get("-Xprefer"));
194 userPathsFirst = options.isSet(XXUSERPATHSFIRST);
195
196 completionFailureName =
197 options.isSet("failcomplete")
198 ? names.fromString(options.get("failcomplete"))
199 : null;
200
201 // Temporary, until more info is available from the module system.
202 boolean useCtProps;
203 JavaFileManager fm = context.get(JavaFileManager.class);
204 if (fm instanceof JavacFileManager) {
205 JavacFileManager jfm = (JavacFileManager) fm;
206 useCtProps = jfm.isDefaultBootClassPath() && jfm.isSymbolFileEnabled();
207 } else if (fm.getClass().getName().equals("com.sun.tools.sjavac.comp.SmartFileManager")) {
208 useCtProps = !options.isSet("ignore.symbol.file");
209 } else {
210 useCtProps = false;
211 }
212 jrtIndex = useCtProps && JRTIndex.isAvailable() ? JRTIndex.getSharedInstance() : null;
213
214 profile = Profile.instance(context);
320
321 /** Fill in definition of class `c' from corresponding class or
322 * source file.
323 */
324 private void fillIn(ClassSymbol c) {
325 if (completionFailureName == c.fullname) {
326 throw new CompletionFailure(c, "user-selected completion failure by class name");
327 }
328 currentOwner = c;
329 JavaFileObject classfile = c.classfile;
330 if (classfile != null) {
331 JavaFileObject previousClassFile = currentClassFile;
332 try {
333 if (reader.filling) {
334 Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile);
335 }
336 currentClassFile = classfile;
337 if (verbose) {
338 log.printVerbose("loading", currentClassFile.toString());
339 }
340 if (classfile.getKind() == JavaFileObject.Kind.CLASS) {
341 reader.readClassFile(c);
342 c.flags_field |= getSupplementaryFlags(c);
343 } else {
344 if (!sourceCompleter.isTerminal()) {
345 sourceCompleter.complete(c);
346 } else {
347 throw new IllegalStateException("Source completer required to read "
348 + classfile.toUri());
349 }
350 }
351 } finally {
352 currentClassFile = previousClassFile;
353 }
354 } else {
355 throw classFileNotFound(c);
356 }
357 }
358 // where
359 private CompletionFailure classFileNotFound(ClassSymbol c) {
360 JCDiagnostic diag =
401 }
402 }
403 return c;
404 }
405
406 /************************************************************************
407 * Loading Packages
408 ***********************************************************************/
409
410 /** Include class corresponding to given class file in package,
411 * unless (1) we already have one the same kind (.class or .java), or
412 * (2) we have one of the other kind, and the given class file
413 * is older.
414 */
415 protected void includeClassFile(PackageSymbol p, JavaFileObject file) {
416 if ((p.flags_field & EXISTS) == 0)
417 for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
418 q.flags_field |= EXISTS;
419 JavaFileObject.Kind kind = file.getKind();
420 int seen;
421 if (kind == JavaFileObject.Kind.CLASS)
422 seen = CLASS_SEEN;
423 else
424 seen = SOURCE_SEEN;
425 String binaryName = fileManager.inferBinaryName(currentLoc, file);
426 int lastDot = binaryName.lastIndexOf(".");
427 Name classname = names.fromString(binaryName.substring(lastDot + 1));
428 boolean isPkgInfo = classname == names.package_info;
429 ClassSymbol c = isPkgInfo
430 ? p.package_info
431 : (ClassSymbol) p.members_field.findFirst(classname);
432 if (c == null) {
433 c = syms.enterClass(classname, p);
434 if (c.classfile == null) // only update the file if's it's newly created
435 c.classfile = file;
436 if (isPkgInfo) {
437 p.package_info = c;
438 } else {
439 if (c.owner == p) // it might be an inner class
440 p.members_field.enter(c);
441 }
564 fileManager.list(CLASS_PATH,
565 packageName,
566 classKinds,
567 false));
568 if (wantSourceFiles)
569 fillIn(p, SOURCE_PATH,
570 fileManager.list(SOURCE_PATH,
571 packageName,
572 sourceKinds,
573 false));
574 }
575 }
576
577 /**
578 * Scans platform class path for files in given package.
579 */
580 private void scanPlatformPath(PackageSymbol p) throws IOException {
581 fillIn(p, PLATFORM_CLASS_PATH,
582 fileManager.list(PLATFORM_CLASS_PATH,
583 p.fullname.toString(),
584 EnumSet.of(JavaFileObject.Kind.CLASS),
585 false));
586 }
587 // where
588 private void fillIn(PackageSymbol p,
589 Location location,
590 Iterable<JavaFileObject> files)
591 {
592 currentLoc = location;
593 for (JavaFileObject fo : files) {
594 switch (fo.getKind()) {
595 case CLASS:
596 case SOURCE: {
597 // TODO pass binaryName to includeClassFile
598 String binaryName = fileManager.inferBinaryName(currentLoc, fo);
599 String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
600 if (SourceVersion.isIdentifier(simpleName) ||
601 simpleName.equals("package-info"))
602 includeClassFile(p, fo);
603 break;
604 }
605 default:
606 extraFileActions(p, fo);
607 }
608 }
609 }
610
611 /**
612 * Used for bad class definition files, such as bad .class files or
613 * for .java files with unexpected package or class names.
614 */
|
33 import java.util.Set;
34
35 import javax.lang.model.SourceVersion;
36 import javax.tools.JavaFileManager;
37 import javax.tools.JavaFileManager.Location;
38 import javax.tools.JavaFileObject;
39 import javax.tools.StandardJavaFileManager;
40
41 import com.sun.tools.javac.code.Scope.WriteableScope;
42 import com.sun.tools.javac.code.Symbol.ClassSymbol;
43 import com.sun.tools.javac.code.Symbol.Completer;
44 import com.sun.tools.javac.code.Symbol.CompletionFailure;
45 import com.sun.tools.javac.code.Symbol.PackageSymbol;
46 import com.sun.tools.javac.code.Symbol.TypeSymbol;
47 import com.sun.tools.javac.comp.Annotate;
48 import com.sun.tools.javac.comp.Enter;
49 import com.sun.tools.javac.file.JRTIndex;
50 import com.sun.tools.javac.file.JavacFileManager;
51 import com.sun.tools.javac.jvm.ClassReader;
52 import com.sun.tools.javac.jvm.Profile;
53 import com.sun.tools.javac.platform.PlatformProvider;
54 import com.sun.tools.javac.util.*;
55
56 import static javax.tools.StandardLocation.*;
57
58 import static com.sun.tools.javac.code.Flags.*;
59 import static com.sun.tools.javac.code.Kinds.Kind.*;
60
61 import static com.sun.tools.javac.main.Option.*;
62
63 import com.sun.tools.javac.util.Dependencies.CompletionCause;
64
65 /**
66 * This class provides operations to locate class definitions
67 * from the source and class files on the paths provided to javac.
68 *
69 * <p><b>This is NOT part of any supported API.
70 * If you write code that depends on this, you do so at your own risk.
71 * This code and its internal interfaces are subject to change or
72 * deletion without notice.</b>
73 */
74 public class ClassFinder {
75 /** The context key for the class finder. */
76 protected static final Context.Key<ClassFinder> classFinderKey = new Context.Key<>();
77
78 ClassReader reader;
79
80 private final Annotate annotate;
81
82 /** Switch: verbose output.
83 */
84 boolean verbose;
85
86 /**
87 * Switch: cache completion failures unless -XDdev is used
88 */
89 private boolean cacheCompletionFailure;
90
91 /**
92 * Switch: prefer source files instead of newer when both source
93 * and class are available
94 **/
95 protected boolean preferSource;
96
97 /**
98 * Switch: Search classpath and sourcepath for classes before the
99 * bootclasspath
100 */
101 protected boolean userPathsFirst;
102
103 /**
104 * Switch: should read OTHER classfiles (.sig files) from PLATFORM_CLASS_PATH.
105 */
106 private boolean allowSigFiles;
107
108 /** The log to use for verbose output
109 */
110 final Log log;
111
112 /** The symbol table. */
113 Symtab syms;
114
115 /** The name table. */
116 final Names names;
117
118 /** Force a completion failure on this name
119 */
120 final Name completionFailureName;
121
122 /** Access to files
123 */
124 private final JavaFileManager fileManager;
125
126 /** Dependency tracker
127 */
182 /** Construct a new class reader. */
183 protected ClassFinder(Context context) {
184 context.put(classFinderKey, this);
185 reader = ClassReader.instance(context);
186 names = Names.instance(context);
187 syms = Symtab.instance(context);
188 fileManager = context.get(JavaFileManager.class);
189 dependencies = Dependencies.instance(context);
190 if (fileManager == null)
191 throw new AssertionError("FileManager initialization error");
192 diagFactory = JCDiagnostic.Factory.instance(context);
193
194 log = Log.instance(context);
195 annotate = Annotate.instance(context);
196
197 Options options = Options.instance(context);
198 verbose = options.isSet(VERBOSE);
199 cacheCompletionFailure = options.isUnset("dev");
200 preferSource = "source".equals(options.get("-Xprefer"));
201 userPathsFirst = options.isSet(XXUSERPATHSFIRST);
202 allowSigFiles = context.get(PlatformProvider.class) != null;
203
204 completionFailureName =
205 options.isSet("failcomplete")
206 ? names.fromString(options.get("failcomplete"))
207 : null;
208
209 // Temporary, until more info is available from the module system.
210 boolean useCtProps;
211 JavaFileManager fm = context.get(JavaFileManager.class);
212 if (fm instanceof JavacFileManager) {
213 JavacFileManager jfm = (JavacFileManager) fm;
214 useCtProps = jfm.isDefaultBootClassPath() && jfm.isSymbolFileEnabled();
215 } else if (fm.getClass().getName().equals("com.sun.tools.sjavac.comp.SmartFileManager")) {
216 useCtProps = !options.isSet("ignore.symbol.file");
217 } else {
218 useCtProps = false;
219 }
220 jrtIndex = useCtProps && JRTIndex.isAvailable() ? JRTIndex.getSharedInstance() : null;
221
222 profile = Profile.instance(context);
328
329 /** Fill in definition of class `c' from corresponding class or
330 * source file.
331 */
332 private void fillIn(ClassSymbol c) {
333 if (completionFailureName == c.fullname) {
334 throw new CompletionFailure(c, "user-selected completion failure by class name");
335 }
336 currentOwner = c;
337 JavaFileObject classfile = c.classfile;
338 if (classfile != null) {
339 JavaFileObject previousClassFile = currentClassFile;
340 try {
341 if (reader.filling) {
342 Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile);
343 }
344 currentClassFile = classfile;
345 if (verbose) {
346 log.printVerbose("loading", currentClassFile.toString());
347 }
348 if (classfile.getKind() == JavaFileObject.Kind.CLASS ||
349 classfile.getKind() == JavaFileObject.Kind.OTHER) {
350 reader.readClassFile(c);
351 c.flags_field |= getSupplementaryFlags(c);
352 } else {
353 if (!sourceCompleter.isTerminal()) {
354 sourceCompleter.complete(c);
355 } else {
356 throw new IllegalStateException("Source completer required to read "
357 + classfile.toUri());
358 }
359 }
360 } finally {
361 currentClassFile = previousClassFile;
362 }
363 } else {
364 throw classFileNotFound(c);
365 }
366 }
367 // where
368 private CompletionFailure classFileNotFound(ClassSymbol c) {
369 JCDiagnostic diag =
410 }
411 }
412 return c;
413 }
414
415 /************************************************************************
416 * Loading Packages
417 ***********************************************************************/
418
419 /** Include class corresponding to given class file in package,
420 * unless (1) we already have one the same kind (.class or .java), or
421 * (2) we have one of the other kind, and the given class file
422 * is older.
423 */
424 protected void includeClassFile(PackageSymbol p, JavaFileObject file) {
425 if ((p.flags_field & EXISTS) == 0)
426 for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
427 q.flags_field |= EXISTS;
428 JavaFileObject.Kind kind = file.getKind();
429 int seen;
430 if (kind == JavaFileObject.Kind.CLASS || kind == JavaFileObject.Kind.OTHER)
431 seen = CLASS_SEEN;
432 else
433 seen = SOURCE_SEEN;
434 String binaryName = fileManager.inferBinaryName(currentLoc, file);
435 int lastDot = binaryName.lastIndexOf(".");
436 Name classname = names.fromString(binaryName.substring(lastDot + 1));
437 boolean isPkgInfo = classname == names.package_info;
438 ClassSymbol c = isPkgInfo
439 ? p.package_info
440 : (ClassSymbol) p.members_field.findFirst(classname);
441 if (c == null) {
442 c = syms.enterClass(classname, p);
443 if (c.classfile == null) // only update the file if's it's newly created
444 c.classfile = file;
445 if (isPkgInfo) {
446 p.package_info = c;
447 } else {
448 if (c.owner == p) // it might be an inner class
449 p.members_field.enter(c);
450 }
573 fileManager.list(CLASS_PATH,
574 packageName,
575 classKinds,
576 false));
577 if (wantSourceFiles)
578 fillIn(p, SOURCE_PATH,
579 fileManager.list(SOURCE_PATH,
580 packageName,
581 sourceKinds,
582 false));
583 }
584 }
585
586 /**
587 * Scans platform class path for files in given package.
588 */
589 private void scanPlatformPath(PackageSymbol p) throws IOException {
590 fillIn(p, PLATFORM_CLASS_PATH,
591 fileManager.list(PLATFORM_CLASS_PATH,
592 p.fullname.toString(),
593 allowSigFiles ? EnumSet.of(JavaFileObject.Kind.CLASS,
594 JavaFileObject.Kind.OTHER)
595 : EnumSet.of(JavaFileObject.Kind.CLASS),
596 false));
597 }
598 // where
599 @SuppressWarnings("fallthrough")
600 private void fillIn(PackageSymbol p,
601 Location location,
602 Iterable<JavaFileObject> files)
603 {
604 currentLoc = location;
605 for (JavaFileObject fo : files) {
606 switch (fo.getKind()) {
607 case OTHER:
608 boolean sigFile = location == PLATFORM_CLASS_PATH &&
609 allowSigFiles &&
610 fo.getName().endsWith(".sig");
611 if (!sigFile) {
612 extraFileActions(p, fo);
613 break;
614 }
615 //intentional fall-through:
616 case CLASS:
617 case SOURCE: {
618 // TODO pass binaryName to includeClassFile
619 String binaryName = fileManager.inferBinaryName(currentLoc, fo);
620 String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
621 if (SourceVersion.isIdentifier(simpleName) ||
622 simpleName.equals("package-info"))
623 includeClassFile(p, fo);
624 break;
625 }
626 default:
627 extraFileActions(p, fo);
628 }
629 }
630 }
631
632 /**
633 * Used for bad class definition files, such as bad .class files or
634 * for .java files with unexpected package or class names.
635 */
|