Skip to content

Commit 70b5277

Browse files
committed
Special handling of Bazel with source generators
- Handle path with filename separated by : - Detect javac' source generation root - Not include semanticdb files for auto-generated files
1 parent a28db33 commit 70b5277

File tree

4 files changed

+99
-46
lines changed

4 files changed

+99
-46
lines changed

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

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.sun.tools.javac.util.Context;
1313

1414
import static javax.tools.StandardLocation.CLASS_OUTPUT;
15+
import static javax.tools.StandardLocation.SOURCE_OUTPUT;
1516

1617
/** Settings that can be configured alongside the -Xplugin compiler option. */
1718
public class SemanticdbJavacOptions {
@@ -25,6 +26,7 @@ public class SemanticdbJavacOptions {
2526
public final ArrayList<String> errors;
2627
public boolean alreadyReportedErrors = false;
2728
public UriScheme uriScheme = UriScheme.DEFAULT;
29+
public Path generatedTargetRoot;
2830

2931
public static String stubClassName = "META-INF-semanticdb-stub";
3032

@@ -49,7 +51,7 @@ public static SemanticdbJavacOptions parse(String[] args, Context ctx) {
4951
String argValue = arg.substring("-targetroot:".length());
5052
if (argValue.equals(JAVAC_CLASSES_DIR_ARG)) {
5153
useJavacClassesDir = true;
52-
result.targetroot = getJavacClassesDir(result, ctx);
54+
result.targetroot = getJavacClassesDir(result, ctx).classes;
5355
} else {
5456
result.targetroot = Paths.get(argValue);
5557
}
@@ -60,7 +62,9 @@ public static SemanticdbJavacOptions parse(String[] args, Context ctx) {
6062
} else if (arg.equals("-build-tool:bazel")) {
6163
result.uriScheme = UriScheme.BAZEL;
6264
useJavacClassesDir = true;
63-
result.targetroot = getJavacClassesDir(result, ctx);
65+
TargetPaths paths = getJavacClassesDir(result, ctx);
66+
result.targetroot = paths.classes;
67+
result.generatedTargetRoot = paths.sources;
6468
} else if (arg.equals("-text:on")) {
6569
result.includeText = true;
6670
} else if (arg.equals("-text:off")) {
@@ -79,9 +83,11 @@ public static SemanticdbJavacOptions parse(String[] args, Context ctx) {
7983
result.errors.add(missingRequiredDirectoryOption("targetroot"));
8084
}
8185
if (!isSourcerootDefined(result)) {
82-
// When using -build-tool:bazel, the sourceroot is automatically inferred from the first
86+
// When using -build-tool:bazel, the sourceroot is automatically inferred from
87+
// the first
8388
// compilation unit.
84-
// See `SemanticdbTaskListener.inferBazelSourceroot()` for the method that infers the
89+
// See `SemanticdbTaskListener.inferBazelSourceroot()` for the method that
90+
// infers the
8591
// sourceroot.
8692
result.errors.add(missingRequiredDirectoryOption("sourceroot"));
8793
}
@@ -95,14 +101,18 @@ private static boolean isSourcerootDefined(SemanticdbJavacOptions options) {
95101
return options.sourceroot != null;
96102
}
97103

98-
private static Path getJavacClassesDir(SemanticdbJavacOptions result, Context ctx) {
104+
private static TargetPaths getJavacClassesDir(SemanticdbJavacOptions result, Context ctx) {
99105
// I'm not aware of a better way to get the class output directory from javac
100-
Path outputDir = null;
106+
Path classOutputDir = null;
107+
Path sourceOutputDir = null;
101108
try {
102109
JavaFileManager fm = ctx.get(JavaFileManager.class);
103-
FileObject outputDirStub =
110+
FileObject sourceOutputDirStub =
111+
fm.getJavaFileForOutput(SOURCE_OUTPUT, stubClassName, JavaFileObject.Kind.SOURCE, null);
112+
FileObject clasSOutputDirStub =
104113
fm.getJavaFileForOutput(CLASS_OUTPUT, stubClassName, JavaFileObject.Kind.CLASS, null);
105-
outputDir = Paths.get(outputDirStub.toUri()).toAbsolutePath().getParent();
114+
classOutputDir = Paths.get(clasSOutputDirStub.toUri()).toAbsolutePath().getParent();
115+
sourceOutputDir = Paths.get(sourceOutputDirStub.toUri()).toAbsolutePath().getParent();
106116
} catch (Exception e) {
107117
ByteArrayOutputStream out = new ByteArrayOutputStream();
108118
e.printStackTrace(new PrintStream(out));
@@ -112,6 +122,6 @@ private static Path getJavacClassesDir(SemanticdbJavacOptions result, Context ct
112122
JAVAC_CLASSES_DIR_ARG, out.toString());
113123
result.errors.add(errorMsg);
114124
}
115-
return outputDir;
125+
return new TargetPaths(classOutputDir, sourceOutputDir);
116126
}
117127
}

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

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.sun.source.tree.CompilationUnitTree;
44
import com.sun.source.tree.Tree;
55
import com.sun.source.util.Trees;
6+
import com.sun.source.util.TaskEvent;
67

78
import javax.tools.Diagnostic;
89
import java.io.ByteArrayOutputStream;
@@ -11,30 +12,44 @@
1112
/**
1213
* Utilities to report error messages.
1314
*
14-
* <p>NOTE(olafur): this class exists because I couldn't find compiler APIs to report diagnostics.
15-
* This class can be removed if the Java compiler has APIs to report info/warning/error messages.
15+
* <p>
16+
* NOTE(olafur): this class exists because I couldn't find compiler APIs to
17+
* report diagnostics. This class can be removed if the Java compiler has APIs
18+
* to report info/warning/error messages.
1619
*/
1720
public class SemanticdbReporter {
18-
private final Trees trees;
19-
20-
public SemanticdbReporter(Trees trees) {
21-
this.trees = trees;
22-
}
23-
24-
public void exception(Throwable e, Tree tree, CompilationUnitTree root) {
25-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
26-
PrintWriter writer = new PrintWriter(baos);
27-
e.printStackTrace(writer);
28-
writer.println(
29-
"Please report a bug to https://github.com/sourcegraph/semanticdb-java with the stack trace above.");
30-
trees.printMessage(Diagnostic.Kind.ERROR, baos.toString(), tree, root);
31-
}
32-
33-
public void error(String message, Tree tree, CompilationUnitTree root) {
34-
// NOTE(olafur): ideally, this message should be reported as a compiler diagnostic, but I dind't
35-
// find
36-
// the reporter API so the message goes to stderr instead for now.
37-
trees.printMessage(
38-
Diagnostic.Kind.ERROR, String.format("semanticdb-javac: %s", message), tree, root);
39-
}
21+
private final Trees trees;
22+
23+
public SemanticdbReporter(Trees trees) {
24+
this.trees = trees;
25+
}
26+
27+
public void exception(Throwable e, Tree tree, CompilationUnitTree root) {
28+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
29+
PrintWriter writer = new PrintWriter(baos);
30+
e.printStackTrace(writer);
31+
writer.println(
32+
"Please report a bug to https://github.com/sourcegraph/semanticdb-java with the stack trace above.");
33+
trees.printMessage(Diagnostic.Kind.ERROR, baos.toString(), tree, root);
34+
}
35+
36+
private void info(String message, TaskEvent e) {
37+
trees.printMessage(Diagnostic.Kind.NOTE, "semanticdb-javac: " + message, e.getCompilationUnit(),
38+
e.getCompilationUnit());
39+
}
40+
41+
public void error(String message, TaskEvent e) {
42+
trees.printMessage(Diagnostic.Kind.ERROR, "semanticdb-javac: " + message, e.getCompilationUnit(),
43+
e.getCompilationUnit());
44+
}
45+
46+
}
47+
48+
public void error(String message, Tree tree, CompilationUnitTree root) {
49+
// NOTE(olafur): ideally, this message should be reported as a compiler
50+
// diagnostic, but I dind't
51+
// find
52+
// the reporter API so the message goes to stderr instead for now.
53+
trees.printMessage(Diagnostic.Kind.ERROR, String.format("semanticdb-javac: %s", message), tree, root);
54+
}
4055
}

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

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,7 @@ public void finished(TaskEvent e) {
5050
if (!options.alreadyReportedErrors) {
5151
options.alreadyReportedErrors = true;
5252
for (String error : options.errors) {
53-
trees.printMessage(
54-
Diagnostic.Kind.ERROR,
55-
"semanticdb-javac: " + error,
56-
e.getCompilationUnit(),
57-
e.getCompilationUnit());
53+
reporter.error(error, e);
5854
}
5955
}
6056
return;
@@ -79,13 +75,15 @@ public void finished(TaskEvent e) {
7975

8076
private void onFinishedAnalyze(TaskEvent e) {
8177
Result<Path, String> path = semanticdbOutputPath(options, e);
82-
if (path.isOk()) {
83-
Semanticdb.TextDocument textDocument =
84-
new SemanticdbVisitor(task, globals, e, options, javacTypes)
85-
.buildTextDocument(e.getCompilationUnit());
86-
writeSemanticdb(e, path.getOrThrow(), textDocument);
87-
} else {
88-
reporter.error(path.getErrorOrThrow(), e.getCompilationUnit(), e.getCompilationUnit());
78+
if (path != null) {
79+
if (path.isOk()) {
80+
Semanticdb.TextDocument textDocument =
81+
new SemanticdbVisitor(task, globals, e, options, javacTypes)
82+
.buildTextDocument(e.getCompilationUnit());
83+
writeSemanticdb(e, path.getOrThrow(), textDocument);
84+
} else {
85+
reporter.error(path.getErrorOrThrow(), e)
86+
}
8987
}
9088
}
9189

@@ -112,12 +110,12 @@ public static Path absolutePathFromUri(SemanticdbJavacOptions options, JavaFileO
112110
throw new IllegalArgumentException("unsupported URI: " + uri);
113111
}
114112
} else if (options.uriScheme == UriScheme.BAZEL) {
115-
String toString = file.toString();
116113
// This solution is hacky, and it would be very nice to use a dedicated API instead.
117114
// The Bazel Java compiler constructs `SimpleFileObject/DirectoryFileObject` with a
118115
// "user-friendly" name that points to the original source file and an underlying/actual
119116
// file path in a temporary directory. We're constrained by having to use only public APIs of
120117
// the Java compiler and `toString()` seems to be the only way to access the user-friendly
118+
String toString = file.toString().replace(":", "/");
121119
// path.
122120
String[] knownBazelToStringPatterns =
123121
new String[] {"SimpleFileObject[", "DirectoryFileObject["};
@@ -184,6 +182,23 @@ private Result<Path, String> semanticdbOutputPath(SemanticdbJavacOptions options
184182
.resolveSibling(filename);
185183
return Result.ok(semanticdbOutputPath);
186184
} else {
185+
186+
if (options.uriScheme == UriScheme.BAZEL && options.generatedTargetRoot != null) {
187+
try {
188+
if (absolutePath.toRealPath().startsWith(options.generatedTargetRoot)) {
189+
reporter.info(
190+
String.format(
191+
"Path '%s' belongs to the root for generated source files, "
192+
+ "as reported by javac ('%s'), therefore a SemanticDB file for it won't be generated",
193+
absolutePath, options.generatedTargetRoot),
194+
e);
195+
196+
return null;
197+
}
198+
} catch (IOException ioe) {
199+
// TODO:
200+
}
201+
}
187202
return Result.error(
188203
String.format(
189204
"sourceroot '%s does not contain path '%s'. To fix this problem, update the -sourceroot flag to "
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.sourcegraph.semanticdb_javac;
2+
3+
import java.nio.file.Path;
4+
5+
public class TargetPaths {
6+
public Path classes;
7+
public Path sources;
8+
9+
public TargetPaths(Path classesDir, Path sourcesDir) {
10+
classes = classesDir;
11+
sources = sourcesDir;
12+
}
13+
}

0 commit comments

Comments
 (0)