11package com .sourcegraph .semanticdb_javac ;
22
3+ import java .io .ByteArrayOutputStream ;
4+ import java .io .PrintStream ;
35import java .nio .file .Path ;
46import java .nio .file .Paths ;
57import java .util .ArrayList ;
8+ import javax .tools .FileObject ;
9+ import javax .tools .JavaFileManager ;
10+ import javax .tools .JavaFileObject ;
11+
12+ import com .sun .tools .javac .util .Context ;
13+
14+ import static javax .tools .StandardLocation .CLASS_OUTPUT ;
615
716/** Settings that can be configured alongside the -Xplugin compiler option. */
817public class SemanticdbJavacOptions {
918
10- /** The directory to place */
19+ /** The directory to place META-INF and its .semanticdb files */
1120 public Path targetroot ;
1221
1322 public Path sourceroot ;
1423 public boolean includeText = false ;
1524 public boolean verboseEnabled = false ;
1625 public final ArrayList <String > errors ;
1726
27+ public static String stubClassName = "META-INF-semanticdb-stub" ;
28+
1829 public SemanticdbJavacOptions () {
1930 errors = new ArrayList <>();
2031 }
@@ -26,11 +37,20 @@ public static String missingRequiredDirectoryOption(String option) {
2637 option , option );
2738 }
2839
29- public static SemanticdbJavacOptions parse (String [] args ) {
40+ public static String JAVAC_CLASSES_DIR_ARG = "javac-classes-directory" ;
41+
42+ public static SemanticdbJavacOptions parse (String [] args , Context ctx ) {
3043 SemanticdbJavacOptions result = new SemanticdbJavacOptions ();
44+ boolean useJavacClassesDir = false ;
3145 for (String arg : args ) {
3246 if (arg .startsWith ("-targetroot:" )) {
33- result .targetroot = Paths .get (arg .substring ("-targetroot:" .length ()));
47+ String argValue = arg .substring ("-targetroot:" .length ());
48+ if (argValue .equals (JAVAC_CLASSES_DIR_ARG )) {
49+ useJavacClassesDir = true ;
50+ result .targetroot = getJavacClassesDir (result , ctx );
51+ } else {
52+ result .targetroot = Paths .get (argValue );
53+ }
3454 } else if (arg .startsWith ("-sourceroot:" )) {
3555 result .sourceroot = Paths .get (arg .substring ("-sourceroot:" .length ())).normalize ();
3656 } else if (arg .equals ("-text:on" )) {
@@ -47,12 +67,32 @@ public static SemanticdbJavacOptions parse(String[] args) {
4767 result .errors .add (String .format ("unknown flag '%s'\n " , arg ));
4868 }
4969 }
50- if (result .targetroot == null ) {
70+ if (result .targetroot == null && ! useJavacClassesDir ) {
5171 result .errors .add (missingRequiredDirectoryOption ("targetroot" ));
5272 }
5373 if (result .sourceroot == null ) {
5474 result .errors .add (missingRequiredDirectoryOption ("sourceroot" ));
5575 }
5676 return result ;
5777 }
78+
79+ private static Path getJavacClassesDir (SemanticdbJavacOptions result , Context ctx ) {
80+ // I'm not aware of a better way to get the class output directory from javac
81+ Path outputDir = null ;
82+ try {
83+ JavaFileManager fm = ctx .get (JavaFileManager .class );
84+ FileObject outputDirStub =
85+ fm .getJavaFileForOutput (CLASS_OUTPUT , stubClassName , JavaFileObject .Kind .CLASS , null );
86+ outputDir = Paths .get (outputDirStub .toUri ()).toAbsolutePath ().getParent ();
87+ } catch (Exception e ) {
88+ ByteArrayOutputStream out = new ByteArrayOutputStream ();
89+ e .printStackTrace (new PrintStream (out ));
90+ String errorMsg =
91+ String .format (
92+ "exception while processing SemanticDB option '-targetroot:%s'\n %s" ,
93+ JAVAC_CLASSES_DIR_ARG , out .toString ());
94+ result .errors .add (errorMsg );
95+ }
96+ return outputDir ;
97+ }
5898}
0 commit comments