Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import scala.jdk.CollectionConverters.*
import scala.meta.pc.VirtualFileParams

class DiagnosticProvider(driver: InteractiveDriver, params: VirtualFileParams):

def diagnostics(): List[lsp4j.Diagnostic] =
if params.shouldReturnDiagnostics then
val diags = driver.run(params.uri().nn, params.text().nn)
Expand All @@ -25,9 +24,13 @@ class DiagnosticProvider(driver: InteractiveDriver, params: VirtualFileParams):

private def toLsp(diag: Diagnostic)(using Context): Option[lsp4j.Diagnostic] =
Option.when(diag.pos.exists):
val message =
if Diagnostic.shouldExplain(diag) then
diag.msg.message + "\n\n# Explanation (enabled by `-explain`)\n\n" + diag.msg.explanation
else diag.msg.message
val lspDiag = lsp4j.Diagnostic(
diag.pos.toLsp,
diag.msg.message,
message,
toDiagnosticSeverity(diag.level),
"presentation compiler",
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package dotty.tools.pc.base

import dotty.tools.pc.RawScalaPresentationCompiler
import dotty.tools.pc.base.TestResources
import dotty.tools.pc.utils.PcAssertions
import dotty.tools.pc.utils.TestExtensions.getOffset
import org.eclipse.lsp4j.Diagnostic
import org.eclipse.lsp4j.DiagnosticSeverity

import java.net.URI
import scala.meta.internal.jdk.CollectionConverters.*
import scala.meta.internal.metals.EmptyCancelToken
import scala.meta.pc.CancelToken
import scala.meta.pc.VirtualFileParams

class BaseDiagnosticsSuite extends PcAssertions:
case class TestDiagnostic(startIndex: Int, endIndex: Int, msg: String, severity: DiagnosticSeverity)

def options : List[String] = Nil

val pc = RawScalaPresentationCompiler().newInstance("", TestResources.classpath.asJava, options.asJava)

case class TestVirtualFileParams(uri: URI, text: String) extends VirtualFileParams {
override def shouldReturnDiagnostics: Boolean = true
override def token: CancelToken = EmptyCancelToken
}

def check(
text: String,
expected: List[TestDiagnostic],
additionalChecks: List[Diagnostic] => Unit = identity
): Unit =
val diagnostics = pc
.didChange(TestVirtualFileParams(URI.create("file:/Diagnostic.scala"), text))
.asScala

val actual = diagnostics.map(d => TestDiagnostic(d.getRange().getStart().getOffset(text), d.getRange().getEnd().getOffset(text), d.getMessage(), d.getSeverity()))
assertEquals(expected, actual, s"Expected [${expected.mkString(", ")}] but got [${actual.mkString(", ")}]")
additionalChecks(diagnostics.toList)
Original file line number Diff line number Diff line change
@@ -1,51 +1,23 @@
package dotty.tools.pc.tests

import java.net.URI
import scala.meta.internal.jdk.CollectionConverters.*
import scala.meta.internal.metals.EmptyCancelToken
import scala.meta.pc.VirtualFileParams
import scala.meta.pc.CancelToken

import org.junit.Test
import org.eclipse.lsp4j.DiagnosticSeverity
import dotty.tools.pc.utils.TestExtensions.getOffset
import dotty.tools.pc.base.TestResources
import java.nio.file.Path
import dotty.tools.pc.RawScalaPresentationCompiler
import dotty.tools.pc.utils.PcAssertions
import org.eclipse.lsp4j.Diagnostic
import dotty.tools.pc.base.BaseDiagnosticsSuite
import org.eclipse.lsp4j.CodeAction
import org.eclipse.lsp4j.Diagnostic
import org.eclipse.lsp4j.DiagnosticSeverity
import org.junit.Test

class DiagnosticProviderSuite extends PcAssertions {
case class TestDiagnostic(startIndex: Int, endIndex: Int, msg: String, severity: DiagnosticSeverity)

val pc = RawScalaPresentationCompiler().newInstance("", TestResources.classpath.asJava, Nil.asJava)

case class TestVirtualFileParams(uri: URI, text: String) extends VirtualFileParams {
override def shouldReturnDiagnostics: Boolean = true
override def token: CancelToken = EmptyCancelToken
}

def check(
text: String,
expected: List[TestDiagnostic],
additionalChecks: List[Diagnostic] => Unit = identity
): Unit =
val diagnostics = pc
.didChange(TestVirtualFileParams(URI.create("file:/Diagnostic.scala"), text))
.asScala
import java.net.URI
import scala.meta.internal.jdk.CollectionConverters.*

val actual = diagnostics.map(d => TestDiagnostic(d.getRange().getStart().getOffset(text), d.getRange().getEnd().getOffset(text), d.getMessage(), d.getSeverity()))
assertEquals(expected, actual, s"Expected [${expected.mkString(", ")}] but got [${actual.mkString(", ")}]")
additionalChecks(diagnostics.toList)
class DiagnosticProviderSuite extends BaseDiagnosticsSuite {

@Test def error =
check(
"""|object M:
| Int.maaxValue
|""".stripMargin,
List(TestDiagnostic(12,25, "value maaxValue is not a member of object Int - did you mean Int.MaxValue?", DiagnosticSeverity.Error))
)
)

@Test def warning =
check(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package dotty.tools.pc.tests

import dotty.tools.pc.base.BaseDiagnosticsSuite
import org.eclipse.lsp4j.CodeAction
import org.eclipse.lsp4j.Diagnostic
import org.eclipse.lsp4j.DiagnosticSeverity
import org.junit.Test

import java.net.URI
import scala.meta.internal.jdk.CollectionConverters.*

class ExplainDiagnosticProviderSuite extends BaseDiagnosticsSuite {

override def options : List[String] = List("-explain")

@Test def error1 =
check(
"""|object C:
| def m(x: Int) = 1
| object T extends K:
| val x = m(1) // error
|class K:
| def m(i: Int) = 2
|""".stripMargin,
List(
TestDiagnostic(
64,65,
"""|Reference to m is ambiguous.
|It is both defined in object C
|and inherited subsequently in object T
|
|# Explanation (enabled by `-explain`)
|
|The identifier m is ambiguous because a name binding of lower precedence
|in an inner scope cannot shadow a binding with higher precedence in
|an outer scope.
|
|The precedence of the different kinds of name bindings, from highest to lowest, is:
| - Definitions in an enclosing scope
| - Inherited definitions and top-level definitions in packages
| - Names introduced by import of a specific name
| - Names introduced by wildcard import
| - Definitions from packages in other files
|Note:
| - As a rule, definitions take precedence over imports.
| - Definitions in an enclosing scope take precedence over inherited definitions,
| which can result in ambiguities in nested classes.
| - When importing, you can avoid naming conflicts by renaming:
| import scala.{m => mTick}
|""".stripMargin,
DiagnosticSeverity.Error

)
)
)

}
Loading