Skip to content

Commit 02ccd70

Browse files
authored
Merge pull request #215 from olafurpg/jdk-multiversion
Use the correct JDK version when indexing Java packages.
2 parents 69bba5a + 71de47c commit 02ccd70

File tree

9 files changed

+162
-100
lines changed

9 files changed

+162
-100
lines changed

lsif-java/src/main/scala/com/sourcegraph/lsif_java/Dependencies.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ case class Dependencies(
2828
}
2929

3030
object Dependencies {
31+
val empty = Dependencies(Nil, Fetch.Result(), Fetch.Result())
3132
private val cache: FileCache[Task] = FileCache[Task]()
3233
.noCredentials
3334
.withCachePolicies(List(CachePolicy.LocalOnly, CachePolicy.Update))

lsif-java/src/main/scala/com/sourcegraph/lsif_java/buildtools/BuildTool.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ abstract class BuildTool(val name: String, index: IndexCommand) {
1414

1515
def isHidden: Boolean = false
1616

17-
def indexJdk(): Boolean = true
18-
1917
final def sourceroot: Path = index.workingDirectory
2018
final def targetroot: Path =
2119
AbsolutePath

lsif-java/src/main/scala/com/sourcegraph/lsif_java/buildtools/LsifBuildTool.scala

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ import os.ProcessOutput.Readlines
5050
class LsifBuildTool(index: IndexCommand) extends BuildTool("LSIF", index) {
5151

5252
protected def defaultTargetroot: Path = Paths.get("target")
53-
private def configFile = index.workingDirectory.resolve("lsif-java.json")
53+
private def configFile =
54+
index.workingDirectory.resolve(LsifBuildTool.ConfigFileName)
5455
def usedInCurrentDirectory(): Boolean = Files.isRegularFile(configFile)
55-
override def indexJdk(): Boolean = parsedConfig.getOrElse(Config()).indexJdk
5656
override def isHidden: Boolean = true
5757
def generateSemanticdb(): CommandResult = {
5858
parsedConfig match {
@@ -132,7 +132,7 @@ class LsifBuildTool(index: IndexCommand) extends BuildTool("LSIF", index) {
132132
arguments += actualClasspath.mkString(File.pathSeparator)
133133
arguments +=
134134
s"-Xplugin:semanticdb -targetroot:$targetroot -sourceroot:$sourceroot"
135-
if (!config.indexJdk && moduleInfos.nonEmpty) {
135+
if (config.kind == "jdk" && moduleInfos.nonEmpty) {
136136
moduleInfos.foreach { module =>
137137
arguments += "--module"
138138
arguments += module.getParent.getFileName.toString
@@ -192,7 +192,8 @@ class LsifBuildTool(index: IndexCommand) extends BuildTool("LSIF", index) {
192192
private def clean(): Unit = {
193193
Files.walkFileTree(targetroot, new DeleteVisitor)
194194
}
195-
val moduleInfo = Paths.get("module-info.java")
195+
196+
private val moduleInfo = Paths.get("module-info.java")
196197

197198
/** Recursively collects all Java files in the working directory */
198199
private def collectAllJavaFiles(dir: Path): List[Path] = {
@@ -280,10 +281,14 @@ class LsifBuildTool(index: IndexCommand) extends BuildTool("LSIF", index) {
280281
private case class Config(
281282
dependencies: List[Dependency] = Nil,
282283
jvm: String = "8",
283-
indexJdk: Boolean = true
284+
kind: String = ""
284285
)
285286
private object Config {
286287
implicit lazy val codec = moped.macros.deriveCodec(Config())
287288
}
288289

289290
}
291+
292+
object LsifBuildTool {
293+
val ConfigFileName = "lsif-java.json"
294+
}

lsif-java/src/main/scala/com/sourcegraph/lsif_java/commands/IndexCommand.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ case class IndexCommand(
157157
generateSemanticdbResult.exitCode
158158
} else {
159159
IndexSemanticdbCommand(
160-
indexJdk = tool.indexJdk(),
161160
output = finalOutput,
162161
targetroot = List(tool.targetroot),
163162
packagehub = packagehub,

lsif-java/src/main/scala/com/sourcegraph/lsif_java/commands/IndexSemanticdbCommand.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ final case class IndexSemanticdbCommand(
3333
@Description(
3434
"Whether to process the SemanticDB files in parallel"
3535
) parallel: Boolean = true,
36-
@Description(
37-
"Whether to index against symbols in the JDK codebase. " +
38-
"If false, no 'packageInformation' LSIF edges will be emitted for JDK symbols."
39-
) indexJdk: Boolean = true,
4036
@Description("URL to a PackageHub instance")
4137
@Hidden
4238
packagehub: Option[String] = None,
@@ -76,7 +72,6 @@ final case class IndexSemanticdbCommand(
7672
"java",
7773
format,
7874
parallel,
79-
indexJdk,
8075
packages.map(_.toPackageInformation).asJava
8176
)
8277
LsifSemanticdb.run(options)

lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/JavaVersion.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
11
package com.sourcegraph.lsif_semanticdb;
22

3+
import java.io.DataInputStream;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.nio.file.FileSystems;
7+
import java.nio.file.Files;
8+
import java.nio.file.Path;
9+
import java.nio.file.PathMatcher;
10+
import java.util.Enumeration;
11+
import java.util.Optional;
12+
import java.util.jar.JarEntry;
13+
import java.util.jar.JarFile;
14+
315
public class JavaVersion {
416
public final boolean isJava8;
517
public final JdkPackage pkg;
18+
private static PathMatcher CLASS_PATTERN =
19+
FileSystems.getDefault().getPathMatcher("glob:**.class");
20+
private static PathMatcher JAR_PATTERN = FileSystems.getDefault().getPathMatcher("glob:**.jar");
21+
22+
public static int JAVA8_VERSION = 8;
23+
public static int JAVA11_VERSION = 11;
24+
public static int DEFAULT_JAVA_VERSION = JAVA8_VERSION;
25+
private static int JAVA0_MAJOR_VERSION = 44;
626

727
public JavaVersion() {
828
this(System.getProperty("java.version"));
@@ -19,4 +39,55 @@ private String javaVersion(String version) {
1939
if (parts.length > 0) return parts[0];
2040
else return version;
2141
}
42+
43+
public static int roundToNearestStableRelease(int version) {
44+
if (version <= JAVA8_VERSION) return JAVA8_VERSION;
45+
if (version <= JAVA11_VERSION) return JAVA11_VERSION;
46+
return version;
47+
}
48+
49+
/**
50+
* Return the JVM version of the given jar/class file.
51+
*
52+
* <p>The JVM version is determined by reading the 5-8th bytes of classfiles, according to the
53+
* Java Language spec. See
54+
* https://docs.oracle.com/javase/specs/jvms/se16/html/jvms-4.html#jvms-4.1
55+
*
56+
* @return the JVM version such as <code>8</code> for Java 8 and <code>11</code> for Java 11.
57+
*/
58+
public static Optional<Integer> classfileJvmVersion(Path file) {
59+
try {
60+
int major = classfileMajorVersion(file);
61+
return major < 0 ? Optional.empty() : Optional.of(major - JAVA0_MAJOR_VERSION);
62+
} catch (IOException e) {
63+
return Optional.empty();
64+
}
65+
}
66+
67+
private static int classfileMajorVersion(Path file) throws IOException {
68+
if (CLASS_PATTERN.matches(file)) {
69+
return classfileMajorVersion(Files.newInputStream(file));
70+
} else if (JAR_PATTERN.matches(file)) {
71+
try (JarFile jar = new JarFile(file.toFile())) {
72+
Enumeration<JarEntry> entries = jar.entries();
73+
while (entries.hasMoreElements()) {
74+
JarEntry entry = entries.nextElement();
75+
if (entry.getName().endsWith(".class")) {
76+
return classfileMajorVersion(jar.getInputStream(entry));
77+
}
78+
}
79+
}
80+
}
81+
82+
return -1;
83+
}
84+
85+
private static int classfileMajorVersion(InputStream classfileBytes) throws IOException {
86+
DataInputStream in = new DataInputStream(classfileBytes);
87+
// See https://docs.oracle.com/javase/specs/jvms/se16/html/jvms-4.html#jvms-4.1
88+
int magic = in.readInt(); // u4 magic
89+
if (magic != 0xCAFEBABE) return -1;
90+
in.readUnsignedShort(); // u2 minor_version
91+
return in.readUnsignedShort(); // u2 major_version
92+
}
2293
}

lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/LsifSemanticdbOptions.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ public class LsifSemanticdbOptions {
1515
public final String language;
1616
public final LsifOutputFormat format;
1717
public final boolean parallel;
18-
public final boolean indexJdk;
1918
public final List<MavenPackage> packages;
2019

2120
public LsifSemanticdbOptions(
@@ -27,7 +26,6 @@ public LsifSemanticdbOptions(
2726
String language,
2827
LsifOutputFormat format,
2928
boolean parallel,
30-
boolean indexJdk,
3129
List<MavenPackage> packages) {
3230
this.targetroots = targetroots;
3331
this.output = output;
@@ -37,7 +35,6 @@ public LsifSemanticdbOptions(
3735
this.language = language;
3836
this.format = format;
3937
this.parallel = parallel;
40-
this.indexJdk = indexJdk;
4138
this.packages = packages;
4239
}
4340
}

lsif-semanticdb/src/main/java/com/sourcegraph/lsif_semanticdb/PackageTable.java

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ public class PackageTable implements Function<Package, Integer> {
2626
private final Set<String> cachedJdkSymbols = new HashSet<>();
2727
private final Map<Package, Integer> lsif = new ConcurrentHashMap<>();
2828
private final JavaVersion javaVersion;
29-
private final boolean indexJdk;
3029
private final LsifWriter writer;
3130

3231
private static final PathMatcher JAR_PATTERN =
@@ -37,13 +36,10 @@ public class PackageTable implements Function<Package, Integer> {
3736
public PackageTable(LsifSemanticdbOptions options, LsifWriter writer) throws IOException {
3837
this.writer = writer;
3938
this.javaVersion = new JavaVersion();
40-
this.indexJdk = options.indexJdk;
4139
for (MavenPackage pkg : options.packages) {
4240
indexPackage(pkg);
4341
}
44-
if (indexJdk) {
45-
indexJdk();
46-
}
42+
indexJdk();
4743
}
4844

4945
public void writeImportedSymbol(String symbol, int monikerId) {
@@ -106,7 +102,6 @@ private void indexJdk() throws IOException {
106102
* under the URL "jrt:/".
107103
*/
108104
private boolean isJrtClassfile(String classfile) {
109-
if (!indexJdk) return false;
110105
if (cachedJdkSymbols.contains(classfile)) return true;
111106
URL resource = getClass().getResource("/" + classfile);
112107
boolean isJrt = resource != null && "jrt".equals(resource.getProtocol());
@@ -116,26 +111,6 @@ private boolean isJrtClassfile(String classfile) {
116111
return isJrt;
117112
}
118113

119-
/**
120-
* Returns the equivalent of `Path.toString()` but uses forward slashes on all operating systems
121-
* (including Windows).
122-
*/
123-
private String relativePathToString(Path path) {
124-
StringBuilder out = new StringBuilder();
125-
Iterator<Path> it = path.iterator();
126-
boolean first = true;
127-
while (it.hasNext()) {
128-
if (first) {
129-
first = false;
130-
} else {
131-
out.append('/');
132-
}
133-
String filename = it.next().toString();
134-
out.append(filename);
135-
}
136-
return out.toString();
137-
}
138-
139114
/**
140115
* The boot classpath contains jar files for the JDK in Java 8.
141116
*

0 commit comments

Comments
 (0)