Skip to content

Commit ae26e17

Browse files
author
Win Wang
committed
Allow javac plugin to infer targetroot from javac class output directory
1 parent dcb4ade commit ae26e17

File tree

4 files changed

+78
-25
lines changed

4 files changed

+78
-25
lines changed

docs/manual-configuration.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ compiler plugin. To do this you need to explicitly configure two directories:
6666
It's important that all of the source files that should be index live under
6767
this directory.
6868
- `-targetroot:PATH`: the absolute path to the directory where to generate
69-
SemanticDB file. This directory can be anywhere on your file system.
69+
SemanticDB file. This directory can be anywhere on your file system.
70+
Alternatively, pass in `-targetroot:javac-classes-directory`
71+
for the plugin to automatically use the `javac` output directory.
7072

7173
If you're using Gradle.
7274

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

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,31 @@
33
import java.nio.file.Path;
44
import java.nio.file.Paths;
55
import java.util.ArrayList;
6+
import javax.tools.FileObject;
7+
import javax.tools.JavaFileManager;
8+
import javax.tools.JavaFileObject;
69

7-
/** Settings that can be configured alongside the -Xplugin compiler option. */
10+
import com.sun.tools.javac.util.Context;
11+
12+
import static javax.tools.StandardLocation.CLASS_OUTPUT;
13+
14+
/**
15+
* Settings that can be configured alongside the -Xplugin compiler option.
16+
*/
817
public class SemanticdbJavacOptions {
918

10-
/** The directory to place */
19+
/**
20+
* The directory to place META-INF and its .semanticdb files
21+
*/
1122
public Path targetroot;
1223

1324
public Path sourceroot;
1425
public boolean includeText = false;
1526
public boolean verboseEnabled = false;
1627
public final ArrayList<String> errors;
1728

29+
public static String stubClassName = "META-INF-stub";
30+
1831
public SemanticdbJavacOptions() {
1932
errors = new ArrayList<>();
2033
}
@@ -26,11 +39,20 @@ public static String missingRequiredDirectoryOption(String option) {
2639
option, option);
2740
}
2841

29-
public static SemanticdbJavacOptions parse(String[] args) {
42+
public static String JAVAC_CLASSES_DIR_ARG = "javac-classes-directory";
43+
44+
public static SemanticdbJavacOptions parse(String[] args, Context ctx) {
3045
SemanticdbJavacOptions result = new SemanticdbJavacOptions();
46+
boolean useJavacClassesDir = false;
3147
for (String arg : args) {
3248
if (arg.startsWith("-targetroot:")) {
33-
result.targetroot = Paths.get(arg.substring("-targetroot:".length()));
49+
String argValue = arg.substring("-targetroot:".length());
50+
if (argValue.equals(JAVAC_CLASSES_DIR_ARG)) {
51+
useJavacClassesDir = true;
52+
result.targetroot = getJavacClassesDir(result, ctx);
53+
} else {
54+
result.targetroot = Paths.get(argValue);
55+
}
3456
} else if (arg.startsWith("-sourceroot:")) {
3557
result.sourceroot = Paths.get(arg.substring("-sourceroot:".length())).normalize();
3658
} else if (arg.equals("-text:on")) {
@@ -47,12 +69,32 @@ public static SemanticdbJavacOptions parse(String[] args) {
4769
result.errors.add(String.format("unknown flag '%s'\n", arg));
4870
}
4971
}
50-
if (result.targetroot == null) {
72+
if (result.targetroot == null && !useJavacClassesDir) {
5173
result.errors.add(missingRequiredDirectoryOption("targetroot"));
5274
}
5375
if (result.sourceroot == null) {
5476
result.errors.add(missingRequiredDirectoryOption("sourceroot"));
5577
}
5678
return result;
5779
}
80+
81+
private static Path getJavacClassesDir(SemanticdbJavacOptions result, Context ctx) {
82+
// I'm not aware of a better way to get the class output directory from javac
83+
Path outputDir = null;
84+
try {
85+
JavaFileManager fm = ctx.get(JavaFileManager.class);
86+
FileObject outputDirStub =
87+
fm.getJavaFileForOutput(CLASS_OUTPUT, stubClassName, JavaFileObject.Kind.CLASS, null);
88+
outputDir = Paths.get(outputDirStub.toUri()).toAbsolutePath().getParent();
89+
} catch (Exception e) {
90+
String errorMsg =
91+
String.format(
92+
"-targetroot:%s passed but could not get the class output directory: %s",
93+
JAVAC_CLASSES_DIR_ARG,
94+
e.getMessage()
95+
);
96+
result.errors.add(errorMsg);
97+
}
98+
return outputDir;
99+
}
58100
}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.sourcegraph.semanticdb_javac;
22

3-
import com.sun.source.util.*;
3+
import com.sun.source.util.JavacTask;
4+
import com.sun.source.util.Plugin;
45
import com.sun.tools.javac.api.BasicJavacTask;
56
import com.sun.tools.javac.model.JavacTypes;
7+
import com.sun.tools.javac.util.Context;
68

79
/** Entrypoint of the semanticdb-javac compiler plugin. */
810
public class SemanticdbPlugin implements Plugin {
@@ -14,10 +16,12 @@ public String getName() {
1416

1517
@Override
1618
public void init(JavacTask task, String... args) {
19+
Context ctx = ((BasicJavacTask) task).getContext();
20+
1721
SemanticdbReporter reporter = new SemanticdbReporter();
18-
SemanticdbJavacOptions options = SemanticdbJavacOptions.parse(args);
22+
SemanticdbJavacOptions options = SemanticdbJavacOptions.parse(args, ctx);
1923
GlobalSymbolsCache globals = new GlobalSymbolsCache(options);
20-
JavacTypes javacTypes = JavacTypes.instance(((BasicJavacTask) task).getContext());
24+
JavacTypes javacTypes = JavacTypes.instance(ctx);
2125
if (!options.errors.isEmpty()) {
2226
for (String error : options.errors) {
2327
reporter.error(error);
Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
11
package tests;
22

3+
import java.net.URI;
4+
import java.util.ArrayList;
5+
import java.util.List;
36
import javax.tools.FileObject;
47
import javax.tools.ForwardingJavaFileManager;
58
import javax.tools.JavaFileObject;
69
import javax.tools.StandardJavaFileManager;
7-
import java.net.URI;
8-
import java.util.ArrayList;
9-
import java.util.List;
10+
11+
import com.sourcegraph.semanticdb_javac.SemanticdbJavacOptions;
1012

1113
public class SimpleFileManager
12-
extends ForwardingJavaFileManager<StandardJavaFileManager> {
14+
extends ForwardingJavaFileManager<StandardJavaFileManager> {
1315

14-
public List<SimpleClassFile> compiled = new ArrayList<>();
15-
protected SimpleFileManager(StandardJavaFileManager fileManager) {
16-
super(fileManager);
17-
}
16+
public List<SimpleClassFile> compiled = new ArrayList<>();
17+
18+
protected SimpleFileManager(StandardJavaFileManager fileManager) {
19+
super(fileManager);
20+
}
1821

19-
// standard constructors/getters
22+
// standard constructors/getters
2023

21-
@Override
22-
public JavaFileObject getJavaFileForOutput(Location location,
23-
String className, JavaFileObject.Kind kind, FileObject sibling) {
24-
SimpleClassFile result = new SimpleClassFile(
25-
URI.create("string://" + className));
26-
compiled.add(result);
27-
return result;
24+
@Override
25+
public JavaFileObject getJavaFileForOutput(Location location,
26+
String className, JavaFileObject.Kind kind, FileObject sibling) {
27+
SimpleClassFile result = new SimpleClassFile(
28+
URI.create("string://" + className));
29+
if (!className.equals(SemanticdbJavacOptions.stubClassName)) {
30+
compiled.add(result);
2831
}
32+
return result;
33+
}
2934

3035
}
3136

0 commit comments

Comments
 (0)