--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Thu Nov 12 08:48:42 2015 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Thu Nov 12 15:10:01 2015 +0100
@@ -75,8 +75,14 @@
import static jdk.internal.jshell.debug.InternalDebugControl.DBG_COMPA;
import java.io.IOException;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Comparator;
-import java.util.EnumSet;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.Set;
@@ -92,6 +98,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+import javax.lang.model.SourceVersion;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.QualifiedNameable;
@@ -100,10 +107,8 @@
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.JavaFileManager.Location;
-import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME;
@@ -584,42 +589,114 @@
.collect(toList());
}
+ private Set<String> emptyContextPackages = null;
+
+ void classpathChanged() {
+ emptyContextPackages = null;
+ }
+
private Set<PackageElement> listPackages(AnalyzeTask at, String enclosingPackage) {
- Set<PackageElement> packs = new HashSet<>();
- listPackages(at, StandardLocation.PLATFORM_CLASS_PATH, enclosingPackage, packs);
- listPackages(at, StandardLocation.CLASS_PATH, enclosingPackage, packs);
- listPackages(at, StandardLocation.SOURCE_PATH, enclosingPackage, packs);
- return packs;
+ Set<String> packs;
+
+ if (enclosingPackage.isEmpty() && emptyContextPackages != null) {
+ packs = emptyContextPackages;
+ } else {
+ packs = new HashSet<>();
+
+ listPackages(StandardLocation.PLATFORM_CLASS_PATH, enclosingPackage, packs);
+ listPackages(StandardLocation.CLASS_PATH, enclosingPackage, packs);
+ listPackages(StandardLocation.SOURCE_PATH, enclosingPackage, packs);
+
+ if (enclosingPackage.isEmpty()) {
+ emptyContextPackages = packs;
+ }
+ }
+
+ return packs.stream()
+ .map(pkg -> createPackageElement(at, pkg))
+ .collect(Collectors.toSet());
+ }
+
+ private PackageElement createPackageElement(AnalyzeTask at, String packageName) {
+ Names names = Names.instance(at.getContext());
+ Symtab syms = Symtab.instance(at.getContext());
+ PackageElement existing = syms.enterPackage(names.fromString(packageName));
+
+ return existing;
+ }
+
+ private void listPackages(Location loc, String enclosing, Set<String> packs) {
+ Iterable<? extends Path> paths = proc.taskFactory.fileManager().getLocationAsPaths(loc);
+
+ if (paths == null)
+ return ;
+
+ for (Path p : paths) {
+ listPackages(p, enclosing, packs);
+ }
}
- private void listPackages(AnalyzeTask at, Location loc, String currentPackage, Set<PackageElement> packs) {
+ private void listPackages(Path path, String enclosing, Set<String> packages) {
try {
- MemoryFileManager fm = proc.taskFactory.fileManager();
- for (JavaFileObject file : fm.list(loc, currentPackage, fileKinds, true)) {
- String binaryName = fm.inferBinaryName(loc, file);
- if (!currentPackage.isEmpty() && !binaryName.startsWith(currentPackage + "."))
- continue;
- int nextDot = binaryName.indexOf('.', !currentPackage.isEmpty() ? currentPackage.length() + 1 : 0);
- if (nextDot == (-1))
- continue;
- Elements elements = at.getElements();
- PackageElement pack =
- elements.getPackageElement(binaryName.substring(0, nextDot));
- if (pack == null) {
- //if no types in the package have ever been seen, the package will be unknown
- //try to load a type, and then try to recognize the package again:
- elements.getTypeElement(binaryName);
- pack = elements.getPackageElement(binaryName.substring(0, nextDot));
+ if (path.equals(Paths.get("JRT_MARKER_FILE"))) {
+ FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/"));
+ Path modules = jrtfs.getPath("modules");
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(modules)) {
+ for (Path c : stream) {
+ listDirectory(c, enclosing, packages);
+ }
}
- if (pack != null)
- packs.add(pack);
+ } else if (!Files.isDirectory(path)) {
+ if (Files.exists(path)) {
+ ClassLoader cl = SourceCodeAnalysisImpl.class.getClassLoader();
+
+ try (FileSystem zip = FileSystems.newFileSystem(path, cl)) {
+ listDirectory(zip.getRootDirectories().iterator().next(), enclosing, packages);
+ }
+ }
+ } else {
+ listDirectory(path, enclosing, packages);
}
} catch (IOException ex) {
- //TODO: should log?
+ proc.debug(ex, "SourceCodeAnalysisImpl.listPackages(" + path.toString() + ", " + enclosing + ", " + packages + ")");
}
}
- //where:
- private final Set<JavaFileObject.Kind> fileKinds = EnumSet.of(JavaFileObject.Kind.CLASS);
+
+ private void listDirectory(Path path, String enclosing, Set<String> packages) throws IOException {
+ String separator = path.getFileSystem().getSeparator();
+ Path resolved = path.resolve(enclosing.replace(".", separator));
+
+ if (Files.isDirectory(resolved)) {
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(resolved)) {
+ for (Path entry : ds) {
+ String name = pathName(entry);
+
+ if (SourceVersion.isIdentifier(name) &&
+ Files.isDirectory(entry) &&
+ validPackageCandidate(entry)) {
+ packages.add(enclosing + (enclosing.isEmpty() ? "" : ".") + name);
+ }
+ }
+ }
+ }
+ }
+
+ private boolean validPackageCandidate(Path p) throws IOException {
+ try (Stream<Path> dir = Files.list(p)) {
+ return dir.anyMatch(e -> Files.isDirectory(e) && SourceVersion.isIdentifier(pathName(e)) ||
+ e.getFileName().toString().endsWith(".class"));
+ }
+ }
+
+ private String pathName(Path p) {
+ String separator = p.getFileSystem().getSeparator();
+ String name = p.getFileName().toString();
+
+ if (name.endsWith(separator)) //jars have '/' appended
+ name = name.substring(0, name.length() - separator.length());
+
+ return name;
+ }
private Element createArrayLengthSymbol(AnalyzeTask at, TypeMirror site) {
Name length = Names.instance(at.getContext()).length;