Skip to content

Commit b750397

Browse files
committed
Add support for Java 17
Previously, the SemanticDB compiler plugin crashed when compiling code with Java 17 because it was using private APIs. This commit refactors the code to use blessed public APIs so that compiling with Java 17 works successfully. This commit only fixes the issues for the compiler plugin. Running `lsif-java index` on Gradle/Maven projects will still fail on Java 17 projects since we don't automatically configure the requried `--add-exports` flags.
1 parent 11e988d commit b750397

File tree

6 files changed

+111
-24
lines changed

6 files changed

+111
-24
lines changed

.jvmopts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
-Xss2m
22
-Xms1G
33
-Xmx4G
4-
-Dfile.encoding=UTF-8
4+
-Dfile.encoding=UTF-8

bin/coursier

6.2 KB
Binary file not shown.

build.sbt

+67-10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import java.io.File
44
import java.nio.file.Files
55
import java.util.Properties
66
import scala.collection.mutable.ListBuffer
7+
import scala.util.control.NoStackTrace
78

89
lazy val V =
910
new {
@@ -271,12 +272,9 @@ commands +=
271272

272273
def minimizedSourceDirectory =
273274
file("tests/minimized/src/main/java").getAbsoluteFile
274-
lazy val minimizedSettings = List[Def.Setting[_]](
275-
autoScalaLibrary := false,
276-
(publish / skip) := true,
277-
(run / fork) := true,
278-
(Compile / unmanagedSourceDirectories) += minimizedSourceDirectory,
279-
(Compile / javacOptions) ++=
275+
276+
def semanticdbCompileOptions =
277+
Def.setting {
280278
List[String](
281279
s"-Arandomtimestamp=${System.nanoTime()}",
282280
List(
@@ -288,6 +286,13 @@ lazy val minimizedSettings = List[Def.Setting[_]](
288286
s"-targetroot:${(Compile / semanticdbTargetRoot).value}"
289287
).mkString(" ")
290288
)
289+
}
290+
lazy val minimizedSettings = List[Def.Setting[_]](
291+
autoScalaLibrary := false,
292+
(publish / skip) := true,
293+
(run / fork) := true,
294+
(Compile / unmanagedSourceDirectories) += minimizedSourceDirectory,
295+
(Compile / javacOptions) ++= semanticdbCompileOptions.value
291296
)
292297

293298
lazy val minimized = project
@@ -302,13 +307,65 @@ lazy val minimized8 = project
302307
.dependsOn(agent, plugin)
303308
.disablePlugins(JavaFormatterPlugin)
304309

310+
def javaModuleExports =
311+
List(
312+
"-J--add-exports",
313+
"-Jjdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
314+
"-J--add-exports",
315+
"-Jjdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
316+
"-J--add-exports",
317+
"-Jjdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
318+
"-J--add-exports",
319+
"-Jjdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
320+
"-J--add-exports",
321+
"-Jjdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"
322+
)
323+
324+
def compileWithJava17 =
325+
Def.task {
326+
val args = ListBuffer.empty[String]
327+
val javaSources = (minimized8 / Compile / sources)
328+
.value
329+
.map(_.getAbsolutePath)
330+
val javac = (Compile / javaHome)
331+
.value
332+
.get
333+
.toPath
334+
.resolve("bin")
335+
.resolve("javac")
336+
.toString
337+
val compileClasspath = List(
338+
"-classpath",
339+
(Compile / dependencyClasspath)
340+
.value
341+
.map(_.data.getAbsolutePath)
342+
.mkString(java.io.File.pathSeparator)
343+
)
344+
val outputDirectory = (Compile / classDirectory).value
345+
IO.delete(outputDirectory)
346+
347+
args += javac
348+
args ++= javaModuleExports
349+
args ++= List("-d", outputDirectory.getAbsolutePath)
350+
args ++= semanticdbCompileOptions.value
351+
args ++= compileClasspath
352+
args ++= javaSources
353+
val exit = scala.sys.process.Process(args.toList).!
354+
if (exit != 0) {
355+
throw new RuntimeException("javac compilation failed") with NoStackTrace
356+
}
357+
}
358+
305359
lazy val minimized17 = project
306-
.in(file("tests/minimized/.j15"))
360+
.in(file("tests/minimized/.j17"))
307361
.settings(
308362
minimizedSettings,
309-
// Non-zulu release is blocked by https://github.com/coursier/jvm-index/pull/53
310-
javaToolchainVersion := "zulu:17",
311-
Compile / javaHome := None
363+
Compile / sources := Nil,
364+
javaToolchainJvmIndex :=
365+
Some("https://github.com/coursier/jvm-index/blob/master/index.json"),
366+
javaToolchainVersion := "temurin:17",
367+
Compile / compile :=
368+
(Compile / compile).dependsOn(compileWithJava17).value
312369
)
313370
.dependsOn(agent, plugin)
314371
.disablePlugins(JavaFormatterPlugin)

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

+12-6
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@
1515
public class JavaVersion {
1616
public final boolean isJava8;
1717
public final JdkPackage pkg;
18-
private static PathMatcher CLASS_PATTERN =
18+
private static final PathMatcher CLASS_PATTERN =
1919
FileSystems.getDefault().getPathMatcher("glob:**.class");
20-
private static PathMatcher JAR_PATTERN = FileSystems.getDefault().getPathMatcher("glob:**.jar");
20+
private static final PathMatcher JAR_PATTERN =
21+
FileSystems.getDefault().getPathMatcher("glob:**.jar");
2122

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;
23+
public static final int JAVA8_VERSION = 8;
24+
public static final int JAVA11_VERSION = 11;
25+
public static final int JAVA17_VERSION = 17;
26+
public static final int DEFAULT_JAVA_VERSION = JAVA8_VERSION;
27+
28+
@SuppressWarnings("FieldCanBeLocal")
29+
private static final int JAVA0_MAJOR_VERSION = 44;
2630

2731
public JavaVersion() {
2832
this(System.getProperty("java.version"));
@@ -40,9 +44,11 @@ private String javaVersion(String version) {
4044
else return version;
4145
}
4246

47+
@SuppressWarnings("ManualMinMaxCalculation")
4348
public static int roundToNearestStableRelease(int version) {
4449
if (version <= JAVA8_VERSION) return JAVA8_VERSION;
4550
if (version <= JAVA11_VERSION) return JAVA11_VERSION;
51+
if (version <= JAVA17_VERSION) return JAVA17_VERSION;
4652
return version;
4753
}
4854

project/JavaToolchainPlugin.scala

+22-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ object JavaToolchainPlugin extends AutoPlugin {
2020
lazy val javaToolchainVersion = settingKey[String](
2121
"The version of the Java"
2222
)
23+
lazy val javaToolchainJvmIndex = settingKey[Option[String]](
24+
"The JVM index to use"
25+
)
2326
}
2427
import autoImport._
2528

@@ -36,14 +39,21 @@ object JavaToolchainPlugin extends AutoPlugin {
3639
(doc / javacOptions) --= List("-target", "1.8"),
3740
(doc / javacOptions) --= bootclasspathSettings(javaToolchainVersion.value),
3841
(doc / javacOptions) --= List("-g"),
39-
javaHome := Some(getJavaHome(javaToolchainVersion.value)),
42+
javaHome :=
43+
Some(
44+
getJavaHome(javaToolchainVersion.value, javaToolchainJvmIndex.value)
45+
),
4046
javacOptions ++= bootclasspathSettings(javaToolchainVersion.value),
4147
javaOptions ++= bootclasspathSettings(javaToolchainVersion.value)
4248
)
4349

4450
override lazy val projectSettings: Seq[Def.Setting[_]] =
4551
List(Compile, Test).flatMap(c => inConfig(c)(configSettings)) ++
46-
List(fork := true, javaToolchainVersion := "11")
52+
List(
53+
fork := true,
54+
javaToolchainVersion := "11",
55+
javaToolchainJvmIndex := None
56+
)
4757

4858
/**
4959
* For Java 8, we need to manually add the Java compiler to the boot
@@ -70,14 +80,20 @@ object JavaToolchainPlugin extends AutoPlugin {
7080

7181
private val javaHomeCache: util.Map[String, File] = Collections
7282
.synchronizedMap(new util.HashMap[String, File]())
73-
private def getJavaHome(version: String): File = {
83+
private def getJavaHome(
84+
version: String,
85+
jvmIndex: Option[String] = None
86+
): File = {
7487
javaHomeCache.computeIfAbsent(
7588
version,
7689
(v: String) => {
7790
val coursier = Paths.get("bin", "coursier")
78-
new File(
79-
Process(List(coursier.toString, "java-home", "--jvm", v)).!!.trim
80-
)
91+
val index = jvmIndex
92+
.toList
93+
.flatMap(index => "--jvm-index" :: index :: Nil)
94+
val arguments =
95+
List(coursier.toString, "java-home", "--jvm", v) ++ index
96+
new File(Process(arguments).!!.trim)
8197
}
8298
)
8399
}

semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/GlobalSymbolsCache.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.sun.tools.javac.code.Symbol;
44

55
import javax.lang.model.element.Element;
6+
import javax.lang.model.element.ElementKind;
67
import javax.lang.model.element.ExecutableElement;
78
import java.util.*;
89

@@ -57,7 +58,14 @@ private String uncachedSemanticdbSymbol(Symbol sym, LocalSymbolsCache locals) {
5758
}
5859

5960
private boolean isLocalVariable(Symbol sym) {
60-
return sym instanceof Symbol.VarSymbol && sym.isLocal();
61+
switch (sym.getKind()) {
62+
case PARAMETER:
63+
case EXCEPTION_PARAMETER:
64+
case LOCAL_VARIABLE:
65+
return true;
66+
default:
67+
return false;
68+
}
6169
}
6270

6371
private boolean isAnonymousClass(Symbol sym) {

0 commit comments

Comments
 (0)