Skip to content

Commit

Permalink
BSP: Send logMessage instead of diagnostics when textDocument is …
Browse files Browse the repository at this point in the history
…unknown (#2979)

Since some compiler messages do not belong to a single source file, they
are not actionable (in the sense of a BSP `build/publishDiagnostics`).
In such situation (no text document), we send `build/logMessage`
instead.

Fix #2926

Pull request: #2979
  • Loading branch information
lefou committed Jan 18, 2024
1 parent 9b657ad commit 2821d6f
Showing 1 changed file with 55 additions and 37 deletions.
92 changes: 55 additions & 37 deletions bsp/worker/src/mill/bsp/worker/BspCompileProblemReporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ch.epfl.scala.{bsp4j => bsp}
import mill.api.{CompileProblemReporter, Problem}

import scala.collection.mutable
import scala.util.chaining.scalaUtilChainingOps

/**
* Specialized reporter that sends compilation diagnostics
Expand Down Expand Up @@ -52,20 +53,33 @@ private class BspCompileProblemReporter(
// TODO: document that if the problem is a general information without a text document
// associated to it, then the document field of the diagnostic is set to the uri of the target
private def reportProblem(problem: Problem): Unit = {
val diagnostic = toDiagnostic(problem)
val sourceFile = problem.position.sourceFile
val textDocument = new TextDocumentIdentifier(
sourceFile match {
case None => targetId.getUri
case Some(f) =>
sourceFile match {
case None =>
// It seems, this isn't an actionable compile problem,
// instead of sending a `build/publishDiagnostics` we send a `build/logMessage`.
// see https://github.com/com-lihaoyi/mill/issues/2926
val messagesType = problem.severity match {
case mill.api.Error => MessageType.ERROR
case mill.api.Warn => MessageType.WARNING
case mill.api.Info => MessageType.INFO
}
val msgParam = new LogMessageParams(messagesType, problem.message).tap { it =>
it.setTask(taskId)
}
client.onBuildLogMessage(msgParam)

case Some(f) =>
val diagnostic = toDiagnostic(problem)
val textDocument = new TextDocumentIdentifier(
// The extra step invoking `toPath` results in a nicer URI starting with `file:///`
f.toPath.toUri.toString
}
)
diagnostics.add(textDocument, diagnostic)
val diagnosticList = new java.util.LinkedList[Diagnostic]()
diagnosticList.add(diagnostic)
sendBuildPublishDiagnostics(textDocument, diagnosticList, reset = false)
)
diagnostics.add(textDocument, diagnostic)
val diagnosticList = new java.util.LinkedList[Diagnostic]()
diagnosticList.add(diagnostic)
sendBuildPublishDiagnostics(textDocument, diagnosticList, reset = false)
}
}

// Computes the diagnostic related to the given Problem
Expand All @@ -83,24 +97,28 @@ private class BspCompileProblemReporter(
pos.endLine.map(correctLine).orElse(line).getOrElse[Int](start.getLine.intValue()),
pos.endColumn.orElse(pos.pointer).getOrElse[Int](start.getCharacter.intValue())
)
val diagnostic = new bsp.Diagnostic(new bsp.Range(start, end), problem.message)
diagnostic.setSource("mill")
diagnostic.setSeverity(
problem.severity match {
case mill.api.Info => bsp.DiagnosticSeverity.INFORMATION
case mill.api.Error => bsp.DiagnosticSeverity.ERROR
case mill.api.Warn => bsp.DiagnosticSeverity.WARNING
new bsp.Diagnostic(new bsp.Range(start, end), problem.message).tap { d =>
// TODO: review whether this is a proper source or if it should better
// something like "scala compiler" or "foo.bar.compile"
d.setSource("mill")
d.setSeverity(
problem.severity match {
case mill.api.Info => bsp.DiagnosticSeverity.INFORMATION
case mill.api.Error => bsp.DiagnosticSeverity.ERROR
case mill.api.Warn => bsp.DiagnosticSeverity.WARNING
}
)
problem.diagnosticCode.foreach { existingCode =>
d.setCode(existingCode.code)
}
)
problem.diagnosticCode.foreach { existingCode => diagnostic.setCode(existingCode.code) }
diagnostic
}
}

private def sendBuildPublishDiagnostics(
textDocument: TextDocumentIdentifier,
diagnosticList: java.util.List[Diagnostic],
reset: Boolean
) = {
): Unit = {
val params = new bsp.PublishDiagnosticsParams(
textDocument,
targetId,
Expand All @@ -127,26 +145,26 @@ private class BspCompileProblemReporter(
}

override def start(): Unit = {
val taskStartParams = new TaskStartParams(taskId)
taskStartParams.setEventTime(System.currentTimeMillis())
taskStartParams.setData(new CompileTask(targetId))
taskStartParams.setDataKind(TaskStartDataKind.COMPILE_TASK)
taskStartParams.setMessage(s"Compiling target ${targetDisplayName}")
val taskStartParams = new TaskStartParams(taskId).tap { it =>
it.setEventTime(System.currentTimeMillis())
it.setData(new CompileTask(targetId))
it.setDataKind(TaskStartDataKind.COMPILE_TASK)
it.setMessage(s"Compiling target ${targetDisplayName}")
}
client.onBuildTaskStart(taskStartParams)
}

override def finish(): Unit = {
val taskFinishParams =
new TaskFinishParams(taskId, if (errors > 0) StatusCode.ERROR else StatusCode.OK)
taskFinishParams.setEventTime(System.currentTimeMillis())
taskFinishParams.setMessage(s"Compiled ${targetDisplayName}")
taskFinishParams.setDataKind(TaskFinishDataKind.COMPILE_REPORT)
val compileReport = new CompileReport(targetId, errors, warnings)
compilationOriginId match {
case Some(id) => compileReport.setOriginId(id)
case None =>
}
taskFinishParams.setData(compileReport)
new TaskFinishParams(taskId, if (errors > 0) StatusCode.ERROR else StatusCode.OK).tap { it =>
it.setEventTime(System.currentTimeMillis())
it.setMessage(s"Compiled ${targetDisplayName}")
it.setDataKind(TaskFinishDataKind.COMPILE_REPORT)
val compileReport = new CompileReport(targetId, errors, warnings).tap { it =>
compilationOriginId.foreach(id => it.setOriginId(id))
}
it.setData(compileReport)
}
client.onBuildTaskFinish(taskFinishParams)
}

Expand Down

0 comments on commit 2821d6f

Please sign in to comment.