From 942e184e72066093e768185bc9b5f3aa9c5f3805 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Mon, 30 Jan 2023 17:54:44 +0100 Subject: [PATCH] Don't allow SemanticDB write to output directory JAR. Writing to outputDirectory when it is a JAR can lead to producing malformed file, it is using FileOutputStream which works somehow correct, but if we would open the same JAR again in later phase (eg. genBCode) header of the file would be malformed: the result file grows in size respectively to provided input, but we can read only files written by SemanticDB phase. --- .../dotc/semanticdb/ExtractSemanticDB.scala | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 071efb1fb91c..84bc1e77a1ef 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -24,6 +24,7 @@ import scala.annotation.{ threadUnsafe => tu, tailrec } import scala.PartialFunction.condOpt import dotty.tools.dotc.{semanticdb => s} +import dotty.tools.io.{AbstractFile, JarArchive} /** Extract symbol references and uses to semanticdb files. * See https://scalameta.org/docs/semanticdb/specification.html#symbol-1 @@ -38,7 +39,9 @@ class ExtractSemanticDB extends Phase: override val description: String = ExtractSemanticDB.description override def isRunnable(using Context) = - super.isRunnable && ctx.settings.Xsemanticdb.value + import ExtractSemanticDB.{semanticdbTarget, outputDirectory} + def writesToOutputJar = semanticdbTarget.isEmpty && outputDirectory.isInstanceOf[JarArchive] + super.isRunnable && ctx.settings.Xsemanticdb.value && !writesToOutputJar // Check not needed since it does not transform trees override def isCheckable: Boolean = false @@ -475,6 +478,13 @@ object ExtractSemanticDB: val name: String = "extractSemanticDB" val description: String = "extract info into .semanticdb files" + private def semanticdbTarget(using Context): Option[Path] = + Option(ctx.settings.semanticdbTarget.value) + .filterNot(_.isEmpty) + .map(Paths.get(_)) + + private def outputDirectory(using Context): AbstractFile = ctx.settings.outputDir.value + def write( source: SourceFile, occurrences: List[SymbolOccurrence], @@ -482,14 +492,8 @@ object ExtractSemanticDB: synthetics: List[Synthetic], )(using Context): Unit = def absolutePath(path: Path): Path = path.toAbsolutePath.normalize - val semanticdbTarget = - val semanticdbTargetSetting = ctx.settings.semanticdbTarget.value - absolutePath( - if semanticdbTargetSetting.isEmpty then ctx.settings.outputDir.value.jpath - else Paths.get(semanticdbTargetSetting) - ) val relPath = SourceFile.relativePath(source, ctx.settings.sourceroot.value) - val outpath = semanticdbTarget + val outpath = absolutePath(semanticdbTarget.getOrElse(outputDirectory.jpath)) .resolve("META-INF") .resolve("semanticdb") .resolve(relPath)