Skip to content

Commit

Permalink
ExtractSemanticDB.PostInlining now update the .semanticdb file on disk
Browse files Browse the repository at this point in the history
  • Loading branch information
tanishiking committed Jun 27, 2023
1 parent e1d0ec9 commit f17fb5f
Showing 1 changed file with 54 additions and 42 deletions.
96 changes: 54 additions & 42 deletions compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import dotty.tools.dotc.{semanticdb => s}
import dotty.tools.io.{AbstractFile, JarArchive}
import dotty.tools.dotc.util.Property
import dotty.tools.dotc.semanticdb.DiagnosticOps.*
import scala.util.{Using, Failure, Success}


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

override val phaseName: String = ExtractSemanticDB.phaseNamePrefix + suffix

Expand All @@ -65,15 +64,13 @@ class ExtractSemanticDB private (phaseMode: ExtractSemanticDB.PhaseMode, suffix:
if (phaseMode == ExtractSemanticDB.PhaseMode.PostTyper)
val extractor = ExtractSemanticDB.Extractor()
extractor.extract(unit.tpdTree)
unit.tpdTree.putAttachment(_key, extractor.toTextDocument(unit.source))
ExtractSemanticDB.write(unit.source, extractor.occurrences.toList, extractor.symbolInfos.toList, extractor.synthetics.toList)
else
unit.tpdTree.getAttachment(_key) match
case None =>
case Some(doc) =>
val warnings = ctx.reporter.allWarnings.collect {
case w if w.pos.source == ctx.source => w.toSemanticDiagnostic
}
ExtractSemanticDB.write(unit.source, doc.copy(diagnostics = warnings))
val warnings = ctx.reporter.allWarnings.collect {
case w if w.pos.source == ctx.source => w.toSemanticDiagnostic
}
if (warnings.nonEmpty)
ExtractSemanticDB.appendDiagnostics(unit.source, warnings)
end ExtractSemanticDB

object ExtractSemanticDB:
Expand All @@ -88,15 +85,9 @@ object ExtractSemanticDB:
case PostTyper
case PostInlining

/**
* The key used to retrieve the "unused entity" analysis metadata,
* from the compilation `Context`
*/
private val _key = Property.StickyKey[TextDocument]
class PostTyper extends ExtractSemanticDB(PhaseMode.PostTyper, "PostTyper")

class PostTyper extends ExtractSemanticDB(PhaseMode.PostTyper, "PostTyper", _key)

class PostInlining extends ExtractSemanticDB(PhaseMode.PostInlining, "PostInlining", _key)
class PostInlining extends ExtractSemanticDB(PhaseMode.PostInlining, "PostInlining")

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

private def write(
source: SourceFile,
doc: TextDocument
occurrences: List[SymbolOccurrence],
symbolInfos: List[SymbolInformation],
synthetics: List[Synthetic],
)(using Context): Unit =
val relPath = SourceFile.relativePath(source, ctx.settings.sourceroot.value)
val outpath = absolutePath(semanticdbTarget.getOrElse(outputDirectory.jpath))
.resolve("META-INF")
.resolve("semanticdb")
.resolve(relPath)
.resolveSibling(source.name + ".semanticdb")
val outpath = semanticdbPath(source)
Files.createDirectories(outpath.getParent())
val doc: TextDocument = TextDocument(
schema = Schema.SEMANTICDB4,
language = Language.SCALA,
uri = Tools.mkURIstring(Paths.get(relPath(source))),
text = "",
md5 = internal.MD5.compute(String(source.content)),
symbols = symbolInfos,
occurrences = occurrences,
synthetics = synthetics,
)
val docs = TextDocuments(List(doc))
val out = Files.newOutputStream(outpath)
try
Expand All @@ -128,6 +126,34 @@ object ExtractSemanticDB:
out.close()
end write

private def appendDiagnostics(
source: SourceFile,
diagnostics: Seq[Diagnostic]
)(using Context): Unit =
val path = semanticdbPath(source)
Using.Manager { use =>
val in = use(Files.newInputStream(path))
val sin = internal.SemanticdbInputStream.newInstance(in)
val docs = TextDocuments.parseFrom(sin)

val out = use(Files.newOutputStream(path))
val sout = internal.SemanticdbOutputStream.newInstance(out)
TextDocuments(docs.documents.map(_.withDiagnostics(diagnostics))).writeTo(sout)
sout.flush()
} match
case Failure(ex) => // failed somehow, should we say something?
case Success(_) => // success to update semanticdb, say nothing
end appendDiagnostics

private def relPath(source: SourceFile)(using ctx: Context) =
SourceFile.relativePath(source, ctx.settings.sourceroot.value)

private def semanticdbPath(source: SourceFile)(using ctx: Context) =
absolutePath(semanticdbTarget.getOrElse(outputDirectory.jpath))
.resolve("META-INF")
.resolve("semanticdb")
.resolve(relPath(source))
.resolveSibling(source.name + ".semanticdb")

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


def toTextDocument(source: SourceFile)(using Context): TextDocument =
val relPath = SourceFile.relativePath(source, ctx.settings.sourceroot.value)
TextDocument(
schema = Schema.SEMANTICDB4,
language = Language.SCALA,
uri = Tools.mkURIstring(Paths.get(relPath)),
text = "",
md5 = internal.MD5.compute(String(source.content)),
symbols = symbolInfos.toList,
occurrences = occurrences.toList,
synthetics = synthetics.toList,
)

/** The bodies of synthetic locals */
private val localBodies = mutable.HashMap[Symbol, Tree]()

Expand Down

0 comments on commit f17fb5f

Please sign in to comment.