Re-implement BuildServerEvalReporter

This commit is contained in:
Adrien Piquerez 2024-03-11 16:41:48 +01:00
parent d6e1c63f3f
commit e62984846b
5 changed files with 82 additions and 82 deletions

View File

@ -7,7 +7,6 @@ import dotty.tools.dotc.CompilationUnit
import dotty.tools.dotc.core.Contexts.{ atPhase, Context }
import dotty.tools.dotc.core.{ Flags, Names, Phases, Symbols, Types }
import dotty.tools.dotc.Driver
import dotty.tools.dotc.reporting.Reporter
import dotty.tools.dotc.Run
import dotty.tools.dotc.util.SourceFile
import dotty.tools.io.{ PlainDirectory, Directory, VirtualDirectory, VirtualFile }
@ -31,7 +30,7 @@ class Eval(
nonCpOptions: Seq[String],
classpath: Seq[Path],
backingDir: Option[Path],
mkReporter: Option[() => Reporter]
mkReporter: Option[() => EvalReporter]
):
import Eval.*
@ -46,9 +45,9 @@ class Eval(
.map(_.toString)
.mkString(":")
private lazy val driver: EvalDriver = new EvalDriver
private lazy val reporter = mkReporter match
case Some(fn) => fn()
case None => EvalReporter.store
private lazy val reporter: EvalReporter = mkReporter match
case Some(f) => f()
case None => EvalReporter.store
final class EvalDriver extends Driver:
val compileCtx0 = initCtx.fresh
@ -83,6 +82,7 @@ class Eval(
line: Int
): EvalResult =
val ev = new EvalType[String]:
override def sourceName: String = srcName
override def makeSource(moduleName: String): SourceFile =
val returnType = tpeName match
case Some(tpe) => s": $tpe"
@ -148,6 +148,7 @@ class Eval(
require(definitions.nonEmpty, "definitions to evaluate cannot be empty.")
val extraHash0 = extraHash
val ev = new EvalType[Seq[String]]:
override def sourceName: String = srcName
override def makeSource(moduleName: String): SourceFile =
val header =
imports.strings.mkString("\n") +
@ -176,7 +177,6 @@ class Eval(
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING
)
override def extraHash: String = extraHash0
val inter = evalCommon[Seq[String]](definitions.map(_._1), imports, tpeName = Some(""), ev)
@ -203,13 +203,16 @@ class Eval(
val d = digester.digest()
val hash = Hash.toHex(d)
val moduleName = makeModuleName(hash)
val (extra, loader) = backingDir match
case Some(backing) if classExists(backing, moduleName) =>
val loader = (parent: ClassLoader) =>
(new URLClassLoader(Array(backing.toUri.toURL), parent): ClassLoader)
val extra = ev.read(cacheFile(backing, moduleName))
(extra, loader)
case _ => compileAndLoad(ev, moduleName)
val (extra, loader) =
try
backingDir match
case Some(backing) if classExists(backing, moduleName) =>
val loader = (parent: ClassLoader) =>
(new URLClassLoader(Array(backing.toUri.toURL), parent): ClassLoader)
val extra = ev.read(cacheFile(backing, moduleName))
(extra, loader)
case _ => compileAndLoad(ev, moduleName)
finally reporter.finalReport(ev.sourceName)
val generatedFiles = getGeneratedFiles(moduleName)
EvalIntermediate(
extra = extra,
@ -277,19 +280,19 @@ object Eval:
def apply(): Eval =
new Eval(Nil, currentClasspath, None, None)
def apply(mkReporter: () => Reporter): Eval =
def apply(mkReporter: () => EvalReporter): Eval =
new Eval(Nil, currentClasspath, None, Some(mkReporter))
def apply(
backingDir: Path,
mkReporter: () => Reporter,
mkReporter: () => EvalReporter,
): Eval =
new Eval(Nil, currentClasspath, Some(backingDir), Some(mkReporter))
def apply(
nonCpOptions: Seq[String],
backingDir: Path,
mkReporter: () => Reporter,
mkReporter: () => EvalReporter,
): Eval =
new Eval(nonCpOptions, currentClasspath, Some(backingDir), Some(mkReporter))
@ -326,6 +329,7 @@ object Eval:
end EvalSourceFile
trait EvalType[A]:
def sourceName: String
def makeSource(moduleName: String): SourceFile
/** Extracts additional information after the compilation unit is evaluated. */

View File

@ -7,7 +7,14 @@ import dotty.tools.dotc.reporting.Diagnostic
import dotty.tools.dotc.reporting.Reporter
import dotty.tools.dotc.reporting.StoreReporter
abstract class EvalReporter extends Reporter
abstract class EvalReporter extends Reporter:
/**
* Send a final report to clear out the outdated diagnostics.
* @param sourceName the source path of a build.sbt file
*/
def finalReport(sourceName: String): Unit
def log(msg: String): Unit = ()
object EvalReporter:
def console: EvalReporter = ForwardingReporter(ConsoleReporter())
@ -16,4 +23,6 @@ end EvalReporter
class ForwardingReporter(delegate: Reporter) extends EvalReporter:
def doReport(dia: Diagnostic)(using Context): Unit = delegate.doReport(dia)
def finalReport(sourceName: String): Unit = ()
end ForwardingReporter

View File

@ -26,6 +26,7 @@ import sbt.SlashSyntax0.*
import sbt.internal.parser.SbtParser
import sbt.io.IO
import scala.jdk.CollectionConverters.*
import xsbti.PathBasedFile
import xsbti.VirtualFile
import xsbti.VirtualFileRef
@ -151,7 +152,9 @@ private[sbt] object EvaluateConfigurations {
): LazyClassLoaded[LoadedSbtFile] = {
// TODO - Store the file on the LoadedSbtFile (or the parent dir) so we can accurately do
// detection for which project project manipulations should be applied.
val name = file.id
val name = file match
case file: PathBasedFile => file.toPath.toString
case file => file.id
val parsed = parseConfiguration(file, lines, imports, offset)
val (importDefs, definitions) =
if (parsed.definitions.isEmpty) (Nil, DefinedSbtValues.empty)

View File

@ -21,6 +21,7 @@ import sbt.internal.inc.{ MappedFileConverter, ScalaInstance, ZincLmUtil, ZincUt
import sbt.internal.util.Attributed.data
import sbt.internal.util.Types.const
import sbt.internal.util.{ Attributed, Settings }
import sbt.internal.server.BuildServerEvalReporter
import sbt.io.{ GlobFilter, IO, Path }
import sbt.librarymanagement.ivy.{ InlineIvyConfiguration, IvyDependencyResolution, IvyPaths }
import sbt.librarymanagement.{ Configuration, Configurations, Resolver }
@ -33,7 +34,6 @@ import java.net.URI
import java.nio.file.{ Path, Paths }
import scala.annotation.{ nowarn, tailrec }
import scala.collection.mutable
// import scala.tools.nsc.reporters.ConsoleReporter
private[sbt] object Load {
// note that there is State passed in but not pulled out
@ -469,7 +469,7 @@ private[sbt] object Load {
nonCpOptions = options,
classpath = classpath,
backingDir = Option(evalOutputDirectory(base).toPath()),
mkReporter = Option(() => (mkReporter(): dotty.tools.dotc.reporting.Reporter)),
mkReporter = Option(() => mkReporter()),
)
/**
@ -749,14 +749,10 @@ private[sbt] object Load {
// NOTE - because we create an eval here, we need a clean-eval later for this URI.
lazy val eval = timed("Load.loadUnit: mkEval", log) {
def mkReporter() = EvalReporter.console
// todo:
// def mkReporter(settings: scala.tools.nsc.Settings): EvalReporter =
// plugs.pluginData.buildTarget match {
// case None => EvalReporter.console // (settings)
// case Some(buildTarget) =>
// new BuildServerEvalReporter(buildTarget, new ConsoleReporter(settings))
// }
def mkReporter(): EvalReporter = plugs.pluginData.buildTarget match {
case None => EvalReporter.console
case Some(buildTarget) => new BuildServerEvalReporter(buildTarget, EvalReporter.console)
}
mkEval(
classpath = plugs.classpath.map(converter.toPath),
defDir,

View File

@ -8,35 +8,34 @@
package sbt.internal.server
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.reporting.{ Diagnostic => ScalaDiagnostic }
import dotty.tools.dotc.reporting.Reporter
// import sbt.StandardMain.exchange
import sbt.internal.ForwardingReporter
import dotty.tools.dotc.reporting.{ Diagnostic => ScalaDiagnostic }
import dotty.tools.dotc.util.SourcePosition
import sbt.StandardMain.exchange
import sbt.internal.EvalReporter
import sbt.internal.bsp
import sbt.internal.bsp.{
BuildTargetIdentifier,
Diagnostic,
// DiagnosticSeverity,
// PublishDiagnosticsParams,
// Range,
// TextDocumentIdentifier
}
import sbt.internal.bsp.BuildTargetIdentifier
import sbt.internal.bsp.Diagnostic
import sbt.internal.bsp.DiagnosticSeverity
import sbt.internal.bsp.PublishDiagnosticsParams
import sbt.internal.bsp.Range
import sbt.internal.bsp.TextDocumentIdentifier
import sbt.internal.bsp.codec.JsonProtocol._
import java.nio.file.Path
import java.nio.file.Paths
import scala.collection.mutable
class BuildServerEvalReporter(buildTarget: BuildTargetIdentifier, delegate: Reporter)
extends ForwardingReporter(delegate):
extends EvalReporter:
private val problemsByFile = mutable.Map[Path, Vector[Diagnostic]]()
override def doReport(dia: ScalaDiagnostic)(using Context): Unit = {
/*
for {
filePath <- if (pos.source.file.exists) Some(Paths.get(pos.source.file.path)) else None
range <- convertToRange(pos)
} {
val bspSeverity = convertToBsp(severity)
val diagnostic = Diagnostic(range, bspSeverity, None, Option("sbt"), msg)
if (dia.pos.exists) {
val filePath = Paths.get(dia.pos.source.file.path)
val range = convertToRange(dia.pos)
val bspSeverity = convertToBsp(dia.level)
val diagnostic = Diagnostic(range, bspSeverity, None, Option("sbt"), dia.msg.message)
problemsByFile(filePath) = problemsByFile.getOrElse(filePath, Vector()) :+ diagnostic
val params = PublishDiagnosticsParams(
TextDocumentIdentifier(filePath.toUri),
@ -46,51 +45,40 @@ class BuildServerEvalReporter(buildTarget: BuildTargetIdentifier, delegate: Repo
reset = false
)
exchange.notifyEvent("build/publishDiagnostics", params)
delegate.doReport(dia)
}
*/
super.doReport(dia)
}
/*
def finalReport(sourceName: String): Unit = {
override def finalReport(sourceName: String): Unit = {
val filePath = Paths.get(sourceName)
if (Files.exists(filePath)) {
val diagnostics = problemsByFile.getOrElse(filePath, Vector())
val params = PublishDiagnosticsParams(
textDocument = TextDocumentIdentifier(filePath.toUri),
buildTarget,
originId = None,
diagnostics,
reset = true
)
exchange.notifyEvent("build/publishDiagnostics", params)
}
val diagnostics = problemsByFile.getOrElse(filePath, Vector())
val params = PublishDiagnosticsParams(
textDocument = TextDocumentIdentifier(filePath.toUri),
buildTarget,
originId = None,
diagnostics,
reset = true
)
exchange.notifyEvent("build/publishDiagnostics", params)
}
private def convertToBsp(severity: Severity): Option[Long] = {
private def convertToBsp(severity: Int): Option[Long] = {
val result = severity match {
case Reporter.INFO => DiagnosticSeverity.Information
case Reporter.WARNING => DiagnosticSeverity.Warning
case Reporter.ERROR => DiagnosticSeverity.Error
case dotty.tools.dotc.interfaces.Diagnostic.INFO => DiagnosticSeverity.Information
case dotty.tools.dotc.interfaces.Diagnostic.WARNING => DiagnosticSeverity.Warning
case dotty.tools.dotc.interfaces.Diagnostic.ERROR => DiagnosticSeverity.Error
}
Some(result)
}
private def convertToRange(pos: Position): Option[Range] = {
pos match {
case _: DefinedPosition =>
val startLine = pos.source.offsetToLine(pos.start)
val startChar = pos.start - pos.source.lineToOffset(startLine)
val endLine = pos.source.offsetToLine(pos.end)
val endChar = pos.end - pos.source.lineToOffset(endLine)
Some(
Range(
bsp.Position(startLine.toLong, startChar.toLong),
bsp.Position(endLine.toLong, endChar.toLong)
)
)
case _ => None
}
private def convertToRange(pos: SourcePosition): Range = {
val startLine = pos.source.offsetToLine(pos.start)
val startChar = pos.start - pos.source.lineToOffset(startLine)
val endLine = pos.source.offsetToLine(pos.end)
val endChar = pos.end - pos.source.lineToOffset(endLine)
Range(
bsp.Position(startLine.toLong, startChar.toLong),
bsp.Position(endLine.toLong, endChar.toLong)
)
}
*/
end BuildServerEvalReporter