1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
package org.javacs;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.*;
import java.util.logging.Logger;
import javax.tools.*;
class SourceFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
public SourceFileManager() {
super(createDelegateFileManager());
}
private static StandardJavaFileManager createDelegateFileManager() {
var compiler = ServiceLoader.load(JavaCompiler.class).iterator().next();
return compiler.getStandardFileManager(SourceFileManager::logError, null, Charset.defaultCharset());
}
private static void logError(Diagnostic<?> error) {
LOG.warning(error.getMessage(null));
}
// TODO if .class files get moved around, this could become wrong
// class path includes generated .class files, so this can definitely happen
private final LruCache<String, Iterable<JavaFileObject>> cacheClassPath = new LruCache<>(1000, this::listClassPath);
@Override
public Iterable<JavaFileObject> list(
Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
if (location == StandardLocation.SOURCE_PATH) {
var stream = FileStore.list(packageName).stream().map(this::asJavaFileObject);
return stream::iterator;
} else if (location == StandardLocation.CLASS_PATH) {
// Listing large class paths is expensive
return cacheClassPath.get(packageName);
} else {
return super.list(location, packageName, kinds, recurse);
}
}
private Iterable<JavaFileObject> listClassPath(String packageName) {
try {
return super.list(StandardLocation.CLASS_PATH, packageName, Set.of(JavaFileObject.Kind.values()), false);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private JavaFileObject asJavaFileObject(Path file) {
return new SourceFileObject(file);
}
@Override
public String inferBinaryName(Location location, JavaFileObject file) {
if (location == StandardLocation.SOURCE_PATH) {
var source = (SourceFileObject) file;
var packageName = FileStore.packageName(source.path);
var className = removeExtension(source.path.getFileName().toString());
if (!packageName.isEmpty()) className = packageName + "." + className;
return className;
} else {
return super.inferBinaryName(location, file);
}
}
private String removeExtension(String fileName) {
var lastDot = fileName.lastIndexOf(".");
return (lastDot == -1 ? fileName : fileName.substring(0, lastDot));
}
@Override
public boolean isSameFile(FileObject a, FileObject b) {
return a.equals(b);
}
@Override
public boolean hasLocation(Location location) {
return location == StandardLocation.SOURCE_PATH || super.hasLocation(location);
}
@Override
public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind)
throws IOException {
if (location == StandardLocation.SOURCE_PATH) {
var packageName = Parser.mostName(className);
var simpleClassName = Parser.lastName(className);
for (var f : FileStore.list(packageName)) {
if (f.getFileName().toString().equals(simpleClassName + kind.extension)) return new SourceFileObject(f);
}
return null;
}
return super.getJavaFileForInput(location, className, kind);
}
@Override
public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
if (location == StandardLocation.SOURCE_PATH) {
return null;
}
return super.getFileForInput(location, packageName, relativeName);
}
@Override
public boolean contains(Location location, FileObject file) throws IOException {
if (location == StandardLocation.SOURCE_PATH) {
var source = (SourceFileObject) file;
return FileStore.contains(source.path);
} else {
return super.contains(location, file);
}
}
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
var result = new ArrayList<JavaFileObject>();
for (var f : files) {
result.add(new SourceFileObject(f.toPath()));
}
return result;
}
public void setLocation(Location location, Iterable<? extends File> files) throws IOException {
fileManager.setLocation(location, files);
}
public void setLocationFromPaths(Location location, Collection<? extends Path> searchpath) throws IOException {
fileManager.setLocationFromPaths(location, searchpath);
}
private static final Logger LOG = Logger.getLogger("main");
}
|