Add info about the end of range in scripting REPL compiler messages
This commit is contained in:
committed by
Ilya Chernikov
parent
a70a128d9e
commit
af251cafa4
+20
-7
@@ -19,10 +19,12 @@ package org.jetbrains.kotlin.cli.common.messages
|
|||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
data class CompilerMessageLocation private constructor(
|
data class CompilerMessageLocation private constructor(
|
||||||
val path: String,
|
val path: String,
|
||||||
val line: Int,
|
val line: Int,
|
||||||
val column: Int,
|
val column: Int,
|
||||||
val lineContent: String?
|
val lineEnd: Int,
|
||||||
|
val columnEnd: Int,
|
||||||
|
val lineContent: String?
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
path + (if (line != -1 || column != -1) " ($line:$column)" else "")
|
path + (if (line != -1 || column != -1) " ($line:$column)" else "")
|
||||||
@@ -30,12 +32,23 @@ data class CompilerMessageLocation private constructor(
|
|||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun create(path: String?): CompilerMessageLocation? =
|
fun create(path: String?): CompilerMessageLocation? =
|
||||||
create(path, -1, -1, null)
|
create(path, -1, -1, null)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun create(path: String?, line: Int, column: Int, lineContent: String?): CompilerMessageLocation? =
|
fun create(path: String?, line: Int, column: Int, lineContent: String?): CompilerMessageLocation? =
|
||||||
if (path == null) null else CompilerMessageLocation(path, line, column, lineContent)
|
if (path == null) null else CompilerMessageLocation(path, line, column, -1, -1, lineContent)
|
||||||
|
|
||||||
private val serialVersionUID: Long = 8228357578L
|
@JvmStatic
|
||||||
|
fun create(
|
||||||
|
path: String?,
|
||||||
|
lineStart: Int,
|
||||||
|
columnStart: Int,
|
||||||
|
lineEnd: Int?,
|
||||||
|
columnEnd: Int?,
|
||||||
|
lineContent: String?
|
||||||
|
): CompilerMessageLocation? =
|
||||||
|
if (path == null) null else CompilerMessageLocation(path, lineStart, columnStart, lineEnd ?: -1, columnEnd ?: -1, lineContent)
|
||||||
|
|
||||||
|
private val serialVersionUID: Long = 8228357579L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -31,6 +31,6 @@ interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
|
|||||||
override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
|
override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
|
||||||
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
|
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
|
||||||
render,
|
render,
|
||||||
MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumn(diagnostic))
|
MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumnRange(diagnostic))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,18 +35,20 @@ public class MessageUtil {
|
|||||||
public static CompilerMessageLocation psiElementToMessageLocation(@Nullable PsiElement element) {
|
public static CompilerMessageLocation psiElementToMessageLocation(@Nullable PsiElement element) {
|
||||||
if (element == null) return null;
|
if (element == null) return null;
|
||||||
PsiFile file = element.getContainingFile();
|
PsiFile file = element.getContainingFile();
|
||||||
return psiFileToMessageLocation(file, "<no path>", DiagnosticUtils.getLineAndColumnInPsiFile(file, element.getTextRange()));
|
return psiFileToMessageLocation(file, "<no path>", DiagnosticUtils.getLineAndColumnRangeInPsiFile(file, element.getTextRange()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static CompilerMessageLocation psiFileToMessageLocation(
|
public static CompilerMessageLocation psiFileToMessageLocation(
|
||||||
@NotNull PsiFile file,
|
@NotNull PsiFile file,
|
||||||
@Nullable String defaultValue,
|
@Nullable String defaultValue,
|
||||||
@NotNull PsiDiagnosticUtils.LineAndColumn lineAndColumn
|
@NotNull PsiDiagnosticUtils.LineAndColumnRange range
|
||||||
) {
|
) {
|
||||||
VirtualFile virtualFile = file.getVirtualFile();
|
VirtualFile virtualFile = file.getVirtualFile();
|
||||||
String path = virtualFile != null ? virtualFileToPath(virtualFile) : defaultValue;
|
String path = virtualFile != null ? virtualFileToPath(virtualFile) : defaultValue;
|
||||||
return CompilerMessageLocation.create(path, lineAndColumn.getLine(), lineAndColumn.getColumn(), lineAndColumn.getLineContent());
|
PsiDiagnosticUtils.LineAndColumn start = range.getStart();
|
||||||
|
PsiDiagnosticUtils.LineAndColumn end = range.getEnd();
|
||||||
|
return CompilerMessageLocation.create(path, start.getLine(), start.getColumn(), end.getLine(), end.getColumn(), start.getLineContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -84,6 +84,24 @@ public class DiagnosticUtils {
|
|||||||
return PsiDiagnosticUtils.offsetToLineAndColumn(document, range.getStartOffset());
|
return PsiDiagnosticUtils.offsetToLineAndColumn(document, range.getStartOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static PsiDiagnosticUtils.LineAndColumnRange getLineAndColumnRange(@NotNull Diagnostic diagnostic) {
|
||||||
|
PsiFile file = diagnostic.getPsiFile();
|
||||||
|
List<TextRange> textRanges = diagnostic.getTextRanges();
|
||||||
|
if (textRanges.isEmpty()) return PsiDiagnosticUtils.LineAndColumnRange.NONE;
|
||||||
|
TextRange firstRange = firstRange(textRanges);
|
||||||
|
return getLineAndColumnRangeInPsiFile(file, firstRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static PsiDiagnosticUtils.LineAndColumnRange getLineAndColumnRangeInPsiFile(PsiFile file, TextRange range) {
|
||||||
|
Document document = file.getViewProvider().getDocument();
|
||||||
|
return new PsiDiagnosticUtils.LineAndColumnRange(
|
||||||
|
PsiDiagnosticUtils.offsetToLineAndColumn(document, range.getStartOffset()),
|
||||||
|
PsiDiagnosticUtils.offsetToLineAndColumn(document, range.getEndOffset())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static void throwIfRunningOnServer(Throwable e) {
|
public static void throwIfRunningOnServer(Throwable e) {
|
||||||
// This is needed for the Web Demo server to log the exceptions coming from the analyzer instead of showing them in the editor.
|
// This is needed for the Web Demo server to log the exceptions coming from the analyzer instead of showing them in the editor.
|
||||||
if (System.getProperty("kotlin.running.in.server.mode", "false").equals("true") || ApplicationManager.getApplication().isUnitTestMode()) {
|
if (System.getProperty("kotlin.running.in.server.mode", "false").equals("true") || ApplicationManager.getApplication().isUnitTestMode()) {
|
||||||
|
|||||||
@@ -116,4 +116,35 @@ public class PsiDiagnosticUtils {
|
|||||||
return "(" + line + "," + column + ")";
|
return "(" + line + "," + column + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class LineAndColumnRange {
|
||||||
|
|
||||||
|
public static final LineAndColumnRange NONE = new LineAndColumnRange(LineAndColumn.NONE, LineAndColumn.NONE);
|
||||||
|
|
||||||
|
private final LineAndColumn start;
|
||||||
|
private final LineAndColumn end;
|
||||||
|
|
||||||
|
public LineAndColumnRange(LineAndColumn start, LineAndColumn end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LineAndColumn getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LineAndColumn getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: This method is used for presenting positions to the user
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (start.line == end.line) {
|
||||||
|
return "(" + start.line + "," + start.column + "-" + end.column + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
return start.toString() + " - " + end.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-3
@@ -10,7 +10,6 @@ import kotlinx.coroutines.runBlocking
|
|||||||
import org.jetbrains.kotlin.cli.common.repl.BasicReplStageHistory
|
import org.jetbrains.kotlin.cli.common.repl.BasicReplStageHistory
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerImpl
|
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerImpl
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
@@ -96,6 +95,27 @@ class ReplTest : TestCase() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEvalWithErrorWithLocation() {
|
||||||
|
checkEvaluateInReplDiags(
|
||||||
|
sequenceOf(
|
||||||
|
"""
|
||||||
|
val foobar = 78
|
||||||
|
val foobaz = "dsdsda"
|
||||||
|
val ddd = ppp
|
||||||
|
val ooo = foobar
|
||||||
|
""".trimIndent()
|
||||||
|
),
|
||||||
|
sequenceOf(
|
||||||
|
makeFailureResult(
|
||||||
|
"Unresolved reference: ppp", location = SourceCode.Location(
|
||||||
|
SourceCode.Position(3, 11), SourceCode.Position(3, 14)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSyntaxErrors() {
|
fun testSyntaxErrors() {
|
||||||
checkEvaluateInReplDiags(
|
checkEvaluateInReplDiags(
|
||||||
@@ -152,7 +172,8 @@ fun evaluateInRepl(
|
|||||||
var currentEvalConfig = evaluationConfiguration ?: ScriptEvaluationConfiguration()
|
var currentEvalConfig = evaluationConfiguration ?: ScriptEvaluationConfiguration()
|
||||||
val snipetsLimited = if (limit == 0) snippets else snippets.take(limit)
|
val snipetsLimited = if (limit == 0) snippets else snippets.take(limit)
|
||||||
return snipetsLimited.mapIndexed { snippetNo, snippetText ->
|
return snipetsLimited.mapIndexed { snippetNo, snippetText ->
|
||||||
val snippetSource = snippetText.toScriptSource("Line_$snippetNo.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}")
|
val snippetSource =
|
||||||
|
snippetText.toScriptSource("Line_$snippetNo.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}")
|
||||||
val snippetId = ReplSnippetIdImpl(snippetNo, 0, snippetSource)
|
val snippetId = ReplSnippetIdImpl(snippetNo, 0, snippetSource)
|
||||||
replCompilerProxy.compileReplSnippet(compilationState, snippetSource, snippetId, compilationHistory)
|
replCompilerProxy.compileReplSnippet(compilationState, snippetSource, snippetId, compilationHistory)
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
@@ -188,9 +209,15 @@ fun checkEvaluateInReplDiags(
|
|||||||
when {
|
when {
|
||||||
res is ResultWithDiagnostics.Failure && expectedRes is ResultWithDiagnostics.Failure -> {
|
res is ResultWithDiagnostics.Failure && expectedRes is ResultWithDiagnostics.Failure -> {
|
||||||
Assert.assertTrue(
|
Assert.assertTrue(
|
||||||
"#$index: Expected $expectedRes, got $res",
|
"#$index: Expected $expectedRes, got $res. Messages are different",
|
||||||
res.reports.map { it.message } == expectedRes.reports.map { it.message }
|
res.reports.map { it.message } == expectedRes.reports.map { it.message }
|
||||||
)
|
)
|
||||||
|
Assert.assertTrue(
|
||||||
|
"#$index: Expected $expectedRes, got $res. Locations are different",
|
||||||
|
res.reports.map { it.location }.zip(expectedRes.reports.map { it.location }).all {
|
||||||
|
it.second == null || it.second == it.first
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
res is ResultWithDiagnostics.Success && expectedRes is ResultWithDiagnostics.Success -> {
|
res is ResultWithDiagnostics.Success && expectedRes is ResultWithDiagnostics.Success -> {
|
||||||
val expectedVal = expectedRes.value
|
val expectedVal = expectedRes.value
|
||||||
|
|||||||
+10
@@ -37,10 +37,20 @@ internal class ScriptDiagnosticsMessageCollector(private val parentMessageCollec
|
|||||||
if (mappedSeverity != null) {
|
if (mappedSeverity != null) {
|
||||||
val mappedLocation = location?.let {
|
val mappedLocation = location?.let {
|
||||||
if (it.line < 0 && it.column < 0) null // special location created by CompilerMessageLocation.create
|
if (it.line < 0 && it.column < 0) null // special location created by CompilerMessageLocation.create
|
||||||
|
else if (it.lineEnd < 0 && it.columnEnd < 0) SourceCode.Location(
|
||||||
|
SourceCode.Position(
|
||||||
|
it.line,
|
||||||
|
it.column
|
||||||
|
)
|
||||||
|
)
|
||||||
else SourceCode.Location(
|
else SourceCode.Location(
|
||||||
SourceCode.Position(
|
SourceCode.Position(
|
||||||
it.line,
|
it.line,
|
||||||
it.column
|
it.column
|
||||||
|
),
|
||||||
|
SourceCode.Position(
|
||||||
|
it.lineEnd,
|
||||||
|
it.columnEnd
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user