11package com .sourcegraph .semanticdb_javac ;
22
33import com .sourcegraph .semanticdb .Semanticdb ;
4+ import com .sourcegraph .semanticdb .SemanticdbDocumentBuilder ;
45import com .sourcegraph .semanticdb .SemanticdbPaths ;
56import com .sourcegraph .semanticdb .SemanticdbWriter ;
67
1213import javax .lang .model .util .Types ;
1314
1415import javax .tools .JavaFileObject ;
15- import java .io .*;
16+ import java .io .ByteArrayOutputStream ;
17+ import java .io .IOException ;
18+ import java .io .PrintWriter ;
1619import java .net .URI ;
1720import java .nio .file .Files ;
1821import java .nio .file .Path ;
1922import java .nio .file .Paths ;
20- import java .util .HashSet ;
23+ import java .util .HashMap ;
24+ import java .util .Map ;
2125import java .util .Optional ;
22- import java .util .Set ;
23- import java .util .stream .Collectors ;
2426
2527/**
2628 * Callback hook that generates SemanticDB when the compiler has completed typechecking a Java
@@ -33,6 +35,8 @@ public final class SemanticdbTaskListener implements TaskListener {
3335 private final Types types ;
3436 private final Trees trees ;
3537 private final Elements elements ;
38+ // Javac fires ANALYZE once per top-level type; accumulate across rounds per output path.
39+ private final Map <Path , PerSourceState > perSourceState = new HashMap <>();
3640 private int noRelativePathCounter = 0 ;
3741
3842 public SemanticdbTaskListener (
@@ -58,8 +62,10 @@ public void started(TaskEvent e) {
5862 inferBazelSourceroot (e .getSourceFile ());
5963 Result <Path , String > semanticdbPath = semanticdbOutputPath (options , e );
6064 if (semanticdbPath .isOk ()) {
65+ Path output = semanticdbPath .getOrThrow ();
66+ perSourceState .remove (output );
6167 try {
62- Files .deleteIfExists (semanticdbPath . getOrThrow () );
68+ Files .deleteIfExists (output );
6369 } catch (IOException ex ) {
6470 this .reportException (ex , e );
6571 }
@@ -116,12 +122,20 @@ private void onFinishedAnalyze(TaskEvent e) {
116122 Result <Path , String > path = semanticdbOutputPath (options , e );
117123 if (path != null ) {
118124 if (path .isOk ()) {
125+ Path output = path .getOrThrow ();
126+ PerSourceState state = perSourceState .computeIfAbsent (output , k -> new PerSourceState ());
119127 Semanticdb .TextDocument textDocument =
120- new SemanticdbVisitor (globals , e .getCompilationUnit (), options , types , trees , elements )
128+ new SemanticdbVisitor (
129+ globals ,
130+ state .locals ,
131+ e .getCompilationUnit (),
132+ options ,
133+ types ,
134+ trees ,
135+ elements ,
136+ state .documentBuilder )
121137 .buildTextDocument (e .getCompilationUnit ());
122- Path output = path .getOrThrow ();
123- if (Files .exists (output )) appendSemanticdb (e , output , textDocument );
124- else writeSemanticdb (e , output , textDocument );
138+ writeSemanticdb (e , output , textDocument );
125139 } else {
126140 reporter .error (path .getErrorOrThrow (), e );
127141 }
@@ -136,76 +150,9 @@ private void writeSemanticdb(TaskEvent event, Path output, Semanticdb.TextDocume
136150 }
137151 }
138152
139- private void appendSemanticdb (
140- TaskEvent event , Path output , Semanticdb .TextDocument textDocument ) {
141- /*
142- * If there already is a semanticdb file at the given path,
143- * we do the following:
144- * - Read a documents collection
145- * - Try to find the document with the matching relative path (matching the incoming textDocument)
146- * - Then, depending on whether a matching document already exists in the collection:
147- * - if YES, mutate it in place to only add entries from the incoming document
148- * - if NO, simply add the incoming text document to the collection
149- * - Write the collection back to disk
150- * */
151- Semanticdb .TextDocument document = null ;
152- int documentIndex = -1 ;
153- Semanticdb .TextDocuments documents = null ;
154-
155- try (InputStream is = Files .newInputStream (output .toFile ().toPath ())) {
156- documents = Semanticdb .TextDocuments .parseFrom (is );
157-
158- for (int i = 0 ; i < documents .getDocumentsCount (); i ++) {
159- Semanticdb .TextDocument candidate = documents .getDocuments (i );
160- if (document == null && candidate .getUri ().equals (textDocument .getUri ())) {
161- document = candidate ;
162- documentIndex = i ;
163- }
164- }
165-
166- } catch (IOException e ) {
167- this .reportException (e , event );
168- return ;
169- }
170-
171- if (document != null ) {
172- // If there is a previous semanticdb document at this path, we need
173- // to deduplicate symbols and occurrences and mutate the document in place
174- Set <Semanticdb .SymbolInformation > symbols = new HashSet <>(textDocument .getSymbolsList ());
175- Set <Semanticdb .SymbolOccurrence > occurrences =
176- new HashSet <>(textDocument .getOccurrencesList ());
177- Set <Semanticdb .Synthetic > synthetics = new HashSet <>(textDocument .getSyntheticsList ());
178-
179- symbols .addAll (document .getSymbolsList ());
180- occurrences .addAll (document .getOccurrencesList ());
181- synthetics .addAll (document .getSyntheticsList ());
182-
183- documents
184- .toBuilder ()
185- .addDocuments (
186- documentIndex ,
187- document
188- .toBuilder ()
189- .clearOccurrences ()
190- .addAllOccurrences (occurrences )
191- .clearSymbols ()
192- .addAllSymbols (symbols )
193- .clearSynthetics ()
194- .addAllSynthetics (synthetics ));
195-
196- } else {
197- // If no prior document was found, we can just add the incoming one to the collection
198- documents = documents .toBuilder ().addDocuments (textDocument ).build ();
199- }
200-
201- byte [] bytes = documents .toByteArray ();
202-
203- try {
204- Files .createDirectories (output .getParent ());
205- Files .write (output , bytes );
206- } catch (IOException e ) {
207- this .reportException (e , event );
208- }
153+ private static final class PerSourceState {
154+ final SemanticdbDocumentBuilder documentBuilder = new SemanticdbDocumentBuilder ();
155+ final LocalSymbolsCache locals = new LocalSymbolsCache ();
209156 }
210157
211158 public static Path absolutePathFromUri (SemanticdbJavacOptions options , JavaFileObject file ) {
0 commit comments