diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index ed391b545..f783d2d3a 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1880,16 +1880,13 @@ object Defaults extends BuildCommon { val compilers: Compilers = ci.compilers val i = ci.withCompilers(onArgs(compilers)) try { - val prev = i.previousResult - prev.analysis.toOption map { analysis => - i.setup.reporter match { - case r: BuildServerReporter => - r.resetPrevious(analysis) - case _ => () - } - } incCompiler.compile(i, s.log) - } finally x.close() // workaround for #937 + } finally { + i.setup.reporter match { + case r: BuildServerReporter => r.sendFinalReport() + } + x.close() // workaround for #937 + } } def compileIncSetupTask = Def.task { val converter = fileConverter.value @@ -1949,7 +1946,7 @@ object Defaults extends BuildCommon { maxErrors.value, streams.value.log, foldMappers(sourcePositionMappers.value), - fileConverter.value + sources.value ) }, compileInputs := { diff --git a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala index f6075109f..5c7a7152f 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala @@ -7,12 +7,13 @@ package sbt.internal.server +import java.io.File + import sbt.StandardMain import sbt.internal.bsp._ import sbt.internal.inc.ManagedLoggedReporter import sbt.internal.util.ManagedLogger -import xsbti.compile.CompileAnalysis -import xsbti.{ BasicVirtualFileRef, FileConverter, Problem, Severity, Position => XPosition } +import xsbti.{ Problem, Severity, Position => XPosition } import scala.collection.mutable @@ -28,97 +29,72 @@ class BuildServerReporter( maximumErrors: Int, logger: ManagedLogger, sourcePositionMapper: XPosition => XPosition = identity[XPosition], - converter: FileConverter + sources: Seq[File] ) extends ManagedLoggedReporter(maximumErrors, logger, sourcePositionMapper) { import sbt.internal.bsp.codec.JsonProtocol._ import sbt.internal.inc.JavaInterfaceUtil._ - import scala.collection.JavaConverters._ + private lazy val exchange = StandardMain.exchange + private val problemsByFile = mutable.Map[File, Vector[Diagnostic]]() - lazy val exchange = StandardMain.exchange - - private[sbt] lazy val problemsByFile = new mutable.HashMap[String, mutable.ListBuffer[Problem]] - - override def reset(): Unit = { - super.reset() - problemsByFile.clear() - } - - override def log(problem: Problem): Unit = { - val pos = problem.position - pos.sourcePath().toOption foreach { sourcePath => - problemsByFile.get(sourcePath) match { - case Some(xs: mutable.ListBuffer[Problem]) => problemsByFile(sourcePath) = xs :+ problem - case _ => problemsByFile(sourcePath) = mutable.ListBuffer(problem) - } - } - super.log(problem) - } - - override def logError(problem: Problem): Unit = { - aggregateProblems(problem) - - // console channel can keep using the xsbi.Problem - super.logError(problem) - } - - override def logWarning(problem: Problem): Unit = { - aggregateProblems(problem) - - // console channel can keep using the xsbi.Problem - super.logWarning(problem) - } - - override def logInfo(problem: Problem): Unit = { - aggregateProblems(problem) - - // console channel can keep using the xsbi.Problem - super.logInfo(problem) - } - - private[sbt] def resetPrevious(analysis: CompileAnalysis): Unit = { - val files = analysis.readSourceInfos.getAllSourceInfos.keySet.asScala - files foreach { file => + private[sbt] def sendFinalReport(): Unit = { + for (source <- sources) { + val diagnostics = problemsByFile.getOrElse(source, Vector()) val params = PublishDiagnosticsParams( - TextDocumentIdentifier(converter.toPath(file).toUri), + TextDocumentIdentifier(source.toURI), buildTarget, - None, - diagnostics = Vector(), + originId = None, + diagnostics, reset = true ) exchange.notifyEvent("build/publishDiagnostics", params) } } - private[sbt] def aggregateProblems(problem: Problem): Unit = { - val pos = problem.position - pos.sourcePath().toOption foreach { sourcePath: String => - problemsByFile.get(sourcePath) match { - case Some(xs: mutable.ListBuffer[Problem]) => - val diagnostics = toDiagnostics(xs) - val absolutePath = converter.toPath(new BasicVirtualFileRef(sourcePath) {}) - val params = PublishDiagnosticsParams( - TextDocumentIdentifier(absolutePath.toUri), - buildTarget, - originId = None, - diagnostics, - reset = true - ) - exchange.notifyEvent("build/publishDiagnostics", params) - case _ => - } + override def logError(problem: Problem): Unit = { + publishDiagnostic(problem) + + // console channel can keep using the xsbi.Problem + super.logError(problem) + } + + override def logWarning(problem: Problem): Unit = { + publishDiagnostic(problem) + + // console channel can keep using the xsbi.Problem + super.logWarning(problem) + } + + override def logInfo(problem: Problem): Unit = { + publishDiagnostic(problem) + + // console channel can keep using the xsbi.Problem + super.logInfo(problem) + } + + private def publishDiagnostic(problem: Problem): Unit = { + for { + source <- problem.position.sourceFile.toOption + diagnostic <- toDiagnostic(problem) + } { + problemsByFile(source) = problemsByFile.getOrElse(source, Vector()) :+ diagnostic + val params = PublishDiagnosticsParams( + TextDocumentIdentifier(source.toURI), + buildTarget, + originId = None, + Vector(diagnostic), + reset = false + ) + exchange.notifyEvent("build/publishDiagnostics", params) } } - private[sbt] def toDiagnostics(ps: Seq[Problem]): Vector[Diagnostic] = { + private def toDiagnostic(problem: Problem): Option[Diagnostic] = { + val pos = problem.position for { - problem <- ps.toVector - pos = problem.position - line0 <- pos.line.toOption.toVector - pointer0 <- pos.pointer.toOption.toVector + line <- pos.line.toOption.map(_.toLong - 1L) + pointer <- pos.pointer.toOption.map(_.toLong) } yield { - val line = line0.toLong - 1L - val pointer = pointer0.toLong val range = ( pos.startLine.toOption, pos.startColumn.toOption, @@ -130,6 +106,7 @@ class BuildServerReporter( case _ => Range(Position(line, pointer), Position(line, pointer + 1)) } + Diagnostic( range, Option(toDiagnosticSeverity(problem.severity)),