Skip to content

Commit d065f38

Browse files
authored
Merge pull request sbt#6854 from eed3si9n/bport/6847
[1.7.x] Do not fire `build/publishDiagnostics` if there are (and were) no problems
2 parents 71f45ba + f5e9ab8 commit d065f38

File tree

4 files changed

+72
-16
lines changed

4 files changed

+72
-16
lines changed

main/src/main/scala/sbt/Defaults.scala

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,10 +2374,11 @@ object Defaults extends BuildCommon {
23742374
val ci = (compile / compileInputs).value
23752375
val ping = earlyOutputPing.value
23762376
val reporter = (compile / bspReporter).value
2377+
val prevAnalysis = previousCompile.value.analysis.toOption.getOrElse(Analysis.empty)
23772378
BspCompileTask.compute(bspTargetIdentifier.value, thisProjectRef.value, configuration.value) {
23782379
task =>
23792380
// TODO - Should readAnalysis + saveAnalysis be scoped by the compile task too?
2380-
compileIncrementalTaskImpl(task, s, ci, ping, reporter)
2381+
compileIncrementalTaskImpl(task, s, ci, ping, reporter, prevAnalysis)
23812382
}
23822383
}
23832384
private val incCompiler = ZincUtil.defaultIncrementalCompiler
@@ -2392,7 +2393,7 @@ object Defaults extends BuildCommon {
23922393
val result0 = incCompiler
23932394
.asInstanceOf[sbt.internal.inc.IncrementalCompilerImpl]
23942395
.compileAllJava(in, s.log)
2395-
reporter.sendSuccessReport(result0.analysis())
2396+
reporter.sendSuccessReport(result0.analysis(), Analysis.empty, false)
23962397
result0.withHasModified(result0.hasModified || r.hasModified)
23972398
} else r
23982399
} catch {
@@ -2406,7 +2407,8 @@ object Defaults extends BuildCommon {
24062407
s: TaskStreams,
24072408
ci: Inputs,
24082409
promise: PromiseWrap[Boolean],
2409-
reporter: BuildServerReporter
2410+
reporter: BuildServerReporter,
2411+
prev: CompileAnalysis
24102412
): CompileResult = {
24112413
lazy val x = s.text(ExportStream)
24122414
def onArgs(cs: Compilers) = {
@@ -2428,7 +2430,11 @@ object Defaults extends BuildCommon {
24282430
.withSetup(onProgress(setup))
24292431
try {
24302432
val result = incCompiler.compile(i, s.log)
2431-
reporter.sendSuccessReport(result.getAnalysis)
2433+
reporter.sendSuccessReport(
2434+
result.getAnalysis,
2435+
prev,
2436+
BuildServerProtocol.shouldReportAllPreviousProblems(task.targetId)
2437+
)
24322438
result
24332439
} catch {
24342440
case e: Throwable =>

main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,26 @@ import scala.collection.mutable
3939
import scala.util.control.NonFatal
4040
import scala.util.{ Failure, Success, Try }
4141
import scala.annotation.nowarn
42+
import scala.collection.concurrent.TrieMap
4243
import sbt.testing.Framework
4344

4445
object BuildServerProtocol {
4546
import sbt.internal.bsp.codec.JsonProtocol._
4647

48+
/**
49+
* Keep track of those projects that were compiled at least once so that we can
50+
* decide to enable fresh reporting for projects that are compiled for the first time.
51+
*
52+
* see: https://github.com/scalacenter/bloop/issues/726
53+
*/
54+
private val compiledTargetsAtLeastOnce = new TrieMap[bsp.BuildTargetIdentifier, Boolean]()
55+
def shouldReportAllPreviousProblems(id: bsp.BuildTargetIdentifier): Boolean = {
56+
compiledTargetsAtLeastOnce.putIfAbsent(id, true) match {
57+
case Some(_) => false
58+
case None => true
59+
}
60+
}
61+
4762
private val capabilities = BuildServerCapabilities(
4863
CompileProvider(BuildServerConnection.languages),
4964
TestProvider(BuildServerConnection.languages),
@@ -354,6 +369,7 @@ object BuildServerProtocol {
354369
case r if r.method == Method.Initialize =>
355370
val params = Converter.fromJson[InitializeBuildParams](json(r)).get
356371
checkMetalsCompatibility(semanticdbEnabled, semanticdbVersion, params, callback.log)
372+
compiledTargetsAtLeastOnce.clear()
357373

358374
val response = InitializeBuildResult(
359375
"sbt",

main/src/main/scala/sbt/internal/server/BuildServerReporter.scala

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ sealed trait BuildServerReporter extends Reporter {
3838

3939
protected def publishDiagnostic(problem: Problem): Unit
4040

41-
def sendSuccessReport(analysis: CompileAnalysis): Unit
41+
def sendSuccessReport(
42+
analysis: CompileAnalysis,
43+
prev: CompileAnalysis,
44+
reportAllPreviousProblems: Boolean
45+
): Unit
4246

4347
def sendFailureReport(sources: Array[VirtualFile]): Unit
4448

@@ -86,20 +90,31 @@ final class BuildServerReporterImpl(
8690
if (ref.id().contains("<")) None
8791
else Some(converter.toPath(ref))
8892

89-
override def sendSuccessReport(analysis: CompileAnalysis): Unit = {
93+
override def sendSuccessReport(
94+
analysis: CompileAnalysis,
95+
prev: CompileAnalysis,
96+
reportAllPreviousProblems: Boolean
97+
): Unit = {
98+
val prevInfos = prev.readSourceInfos().getAllSourceInfos().asScala
9099
for {
91100
(source, infos) <- analysis.readSourceInfos.getAllSourceInfos.asScala
92101
filePath <- toSafePath(source)
93102
} {
94-
val diagnostics = infos.getReportedProblems.toSeq.flatMap(toDiagnostic)
95-
val params = PublishDiagnosticsParams(
96-
textDocument = TextDocumentIdentifier(filePath.toUri),
97-
buildTarget,
98-
originId = None,
99-
diagnostics.toVector,
100-
reset = true
101-
)
102-
exchange.notifyEvent("build/publishDiagnostics", params)
103+
val prevProblems = prevInfos.get(source).map(_.getReportedProblems()).getOrElse(Array.empty)
104+
val dontPublish = prevProblems.length == 0 && infos.getReportedProblems().length == 0
105+
val shouldPublish = reportAllPreviousProblems || !dontPublish
106+
107+
if (shouldPublish) {
108+
val diagnostics = infos.getReportedProblems.toSeq.flatMap(toDiagnostic)
109+
val params = PublishDiagnosticsParams(
110+
textDocument = TextDocumentIdentifier(filePath.toUri),
111+
buildTarget,
112+
originId = None,
113+
diagnostics.toVector,
114+
reset = true
115+
)
116+
exchange.notifyEvent("build/publishDiagnostics", params)
117+
}
103118
}
104119
}
105120

@@ -179,7 +194,11 @@ final class BuildServerForwarder(
179194
protected override val underlying: Reporter
180195
) extends BuildServerReporter {
181196

182-
override def sendSuccessReport(analysis: CompileAnalysis): Unit = ()
197+
override def sendSuccessReport(
198+
analysis: CompileAnalysis,
199+
prev: CompileAnalysis,
200+
reportAllPreviousProblems: Boolean
201+
): Unit = ()
183202

184203
override def sendFailureReport(sources: Array[VirtualFile]): Unit = ()
185204

server-test/src/test/scala/testpkg/BuildServerTest.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,25 @@ object BuildServerTest extends AbstractServerTest {
125125
s.contains(""""message":"Compiling runAndTest (100%)"""")
126126
})
127127

128+
assert(svr.waitForString(60.seconds) { s =>
129+
s.contains("build/publishDiagnostics")
130+
s.contains(""""diagnostics":[]""")
131+
})
132+
128133
assert(svr.waitForString(60.seconds) { s =>
129134
s.contains("build/taskFinish") &&
130135
s.contains(""""message":"Compiled runAndTest"""")
131136
})
137+
138+
svr.sendJsonRpc(
139+
s"""{ "jsonrpc": "2.0", "id": "34", "method": "buildTarget/compile", "params": {
140+
| "targets": [{ "uri": "$buildTarget" }]
141+
|} }""".stripMargin
142+
)
143+
144+
assert(!svr.waitForString(30.seconds) { s =>
145+
s.contains("build/publishDiagnostics")
146+
}, "shouldn't send publishDiagnostics if there's no change in diagnostics")
132147
}
133148

134149
test("buildTarget/scalacOptions") { _ =>

0 commit comments

Comments
 (0)