Skip to content

Commit f17fb5f

Browse files
committed
ExtractSemanticDB.PostInlining now update the .semanticdb file on disk
1 parent e1d0ec9 commit f17fb5f

File tree

1 file changed

+54
-42
lines changed

1 file changed

+54
-42
lines changed

compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala

+54-42
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import dotty.tools.dotc.{semanticdb => s}
2727
import dotty.tools.io.{AbstractFile, JarArchive}
2828
import dotty.tools.dotc.util.Property
2929
import dotty.tools.dotc.semanticdb.DiagnosticOps.*
30+
import scala.util.{Using, Failure, Success}
3031

3132

3233
/** Extract symbol references and uses to semanticdb files.
@@ -36,17 +37,15 @@ import dotty.tools.dotc.semanticdb.DiagnosticOps.*
3637
* Here, we define two phases for "ExtractSemanticDB", "PostTyper" and "PostInlining".
3738
*
3839
* The "PostTyper" phase extracts SemanticDB information such as symbol
39-
* definitions, symbol occurrences, type information, and synthetics.
40-
* This phase does not write the information to a .semanticdb file;
41-
* instead, it attaches the SemanticDB information to the top-level tree.
40+
* definitions, symbol occurrences, type information, and synthetics
41+
* and write .semanticdb file.
4242
*
4343
* The "PostInlining" phase extracts diagnostics from "ctx.reporter" and
4444
* attaches them to the SemanticDB information extracted in the "PostTyper" phase.
45-
* Afterwards, it writes the SemanticDB to a ".semanticdb" file.
4645
* We need to run this phase after the "CheckUnused.PostInlining" phase
4746
* so that we can extract the warnings generated by "-Wunused".
4847
*/
49-
class ExtractSemanticDB private (phaseMode: ExtractSemanticDB.PhaseMode, suffix: String, _key: Property.Key[TextDocument]) extends Phase:
48+
class ExtractSemanticDB private (phaseMode: ExtractSemanticDB.PhaseMode, suffix: String) extends Phase:
5049

5150
override val phaseName: String = ExtractSemanticDB.phaseNamePrefix + suffix
5251

@@ -65,15 +64,13 @@ class ExtractSemanticDB private (phaseMode: ExtractSemanticDB.PhaseMode, suffix:
6564
if (phaseMode == ExtractSemanticDB.PhaseMode.PostTyper)
6665
val extractor = ExtractSemanticDB.Extractor()
6766
extractor.extract(unit.tpdTree)
68-
unit.tpdTree.putAttachment(_key, extractor.toTextDocument(unit.source))
67+
ExtractSemanticDB.write(unit.source, extractor.occurrences.toList, extractor.symbolInfos.toList, extractor.synthetics.toList)
6968
else
70-
unit.tpdTree.getAttachment(_key) match
71-
case None =>
72-
case Some(doc) =>
73-
val warnings = ctx.reporter.allWarnings.collect {
74-
case w if w.pos.source == ctx.source => w.toSemanticDiagnostic
75-
}
76-
ExtractSemanticDB.write(unit.source, doc.copy(diagnostics = warnings))
69+
val warnings = ctx.reporter.allWarnings.collect {
70+
case w if w.pos.source == ctx.source => w.toSemanticDiagnostic
71+
}
72+
if (warnings.nonEmpty)
73+
ExtractSemanticDB.appendDiagnostics(unit.source, warnings)
7774
end ExtractSemanticDB
7875

7976
object ExtractSemanticDB:
@@ -88,15 +85,9 @@ object ExtractSemanticDB:
8885
case PostTyper
8986
case PostInlining
9087

91-
/**
92-
* The key used to retrieve the "unused entity" analysis metadata,
93-
* from the compilation `Context`
94-
*/
95-
private val _key = Property.StickyKey[TextDocument]
88+
class PostTyper extends ExtractSemanticDB(PhaseMode.PostTyper, "PostTyper")
9689

97-
class PostTyper extends ExtractSemanticDB(PhaseMode.PostTyper, "PostTyper", _key)
98-
99-
class PostInlining extends ExtractSemanticDB(PhaseMode.PostInlining, "PostInlining", _key)
90+
class PostInlining extends ExtractSemanticDB(PhaseMode.PostInlining, "PostInlining")
10091

10192
private def semanticdbTarget(using Context): Option[Path] =
10293
Option(ctx.settings.semanticdbTarget.value)
@@ -109,15 +100,22 @@ object ExtractSemanticDB:
109100

110101
private def write(
111102
source: SourceFile,
112-
doc: TextDocument
103+
occurrences: List[SymbolOccurrence],
104+
symbolInfos: List[SymbolInformation],
105+
synthetics: List[Synthetic],
113106
)(using Context): Unit =
114-
val relPath = SourceFile.relativePath(source, ctx.settings.sourceroot.value)
115-
val outpath = absolutePath(semanticdbTarget.getOrElse(outputDirectory.jpath))
116-
.resolve("META-INF")
117-
.resolve("semanticdb")
118-
.resolve(relPath)
119-
.resolveSibling(source.name + ".semanticdb")
107+
val outpath = semanticdbPath(source)
120108
Files.createDirectories(outpath.getParent())
109+
val doc: TextDocument = TextDocument(
110+
schema = Schema.SEMANTICDB4,
111+
language = Language.SCALA,
112+
uri = Tools.mkURIstring(Paths.get(relPath(source))),
113+
text = "",
114+
md5 = internal.MD5.compute(String(source.content)),
115+
symbols = symbolInfos,
116+
occurrences = occurrences,
117+
synthetics = synthetics,
118+
)
121119
val docs = TextDocuments(List(doc))
122120
val out = Files.newOutputStream(outpath)
123121
try
@@ -128,6 +126,34 @@ object ExtractSemanticDB:
128126
out.close()
129127
end write
130128

129+
private def appendDiagnostics(
130+
source: SourceFile,
131+
diagnostics: Seq[Diagnostic]
132+
)(using Context): Unit =
133+
val path = semanticdbPath(source)
134+
Using.Manager { use =>
135+
val in = use(Files.newInputStream(path))
136+
val sin = internal.SemanticdbInputStream.newInstance(in)
137+
val docs = TextDocuments.parseFrom(sin)
138+
139+
val out = use(Files.newOutputStream(path))
140+
val sout = internal.SemanticdbOutputStream.newInstance(out)
141+
TextDocuments(docs.documents.map(_.withDiagnostics(diagnostics))).writeTo(sout)
142+
sout.flush()
143+
} match
144+
case Failure(ex) => // failed somehow, should we say something?
145+
case Success(_) => // success to update semanticdb, say nothing
146+
end appendDiagnostics
147+
148+
private def relPath(source: SourceFile)(using ctx: Context) =
149+
SourceFile.relativePath(source, ctx.settings.sourceroot.value)
150+
151+
private def semanticdbPath(source: SourceFile)(using ctx: Context) =
152+
absolutePath(semanticdbTarget.getOrElse(outputDirectory.jpath))
153+
.resolve("META-INF")
154+
.resolve("semanticdb")
155+
.resolve(relPath(source))
156+
.resolveSibling(source.name + ".semanticdb")
131157

132158
/** Extractor of symbol occurrences from trees */
133159
private class Extractor extends TreeTraverser:
@@ -136,20 +162,6 @@ object ExtractSemanticDB:
136162
val synth = SyntheticsExtractor()
137163
given converter: s.TypeOps = s.TypeOps()
138164

139-
140-
def toTextDocument(source: SourceFile)(using Context): TextDocument =
141-
val relPath = SourceFile.relativePath(source, ctx.settings.sourceroot.value)
142-
TextDocument(
143-
schema = Schema.SEMANTICDB4,
144-
language = Language.SCALA,
145-
uri = Tools.mkURIstring(Paths.get(relPath)),
146-
text = "",
147-
md5 = internal.MD5.compute(String(source.content)),
148-
symbols = symbolInfos.toList,
149-
occurrences = occurrences.toList,
150-
synthetics = synthetics.toList,
151-
)
152-
153165
/** The bodies of synthetic locals */
154166
private val localBodies = mutable.HashMap[Symbol, Tree]()
155167

0 commit comments

Comments
 (0)