!RENDER_DIAGNOSTICS_FULL_TEXT directive

Compares diagnostics rendered as text with corresponding .diag.txt file
This commit is contained in:
Dmitry Petrov
2020-02-06 12:35:47 +03:00
parent 4e6c3b6b43
commit a1326d3ef5
6 changed files with 99 additions and 28 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.cli.common.messages;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.utils.fileUtils.FileUtilsKt;
@@ -69,6 +70,23 @@ public interface MessageRenderer {
}
};
MessageRenderer SYSTEM_INDEPENDENT_RELATIVE_PATHS = new PlainTextMessageRenderer() {
private final File cwd = new File(".").getAbsoluteFile();
@Nullable
@Override
protected String getPath(@NotNull CompilerMessageLocation location) {
return FileUtil.toSystemIndependentName(
FileUtilsKt.descendantRelativeTo(new File(location.getPath()), cwd).getPath()
);
}
@Override
public String getName() {
return "SystemIndependentRelativePath";
}
};
MessageRenderer GRADLE_STYLE = new GradleStyleMessageRenderer();
String renderPreamble();
@@ -0,0 +1,6 @@
/inlineCycle.kt:8:5: error: the 'inlineFun2' invocation is a part of inline cycle
inlineFun2(p)
^
/inlineCycle.kt:13:5: error: the 'inlineFun1' invocation is a part of inline cycle
inlineFun1(p)
^
@@ -1,3 +1,5 @@
// !RENDER_DIAGNOSTICS_FULL_TEXT
inline fun inlineFun1(p: () -> Unit) {
p()
<!INLINE_CALL_CYCLE, INLINE_CALL_CYCLE!>inlineFun2(p)<!>
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.TestsCompilerError
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.config.*
@@ -61,7 +62,9 @@ import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.RECURSIVE
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.RECURSIVE_ALL
import org.jetbrains.kotlin.utils.keysToMap
import org.junit.Assert
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import java.util.*
import java.util.function.Predicate
import java.util.regex.Pattern
@@ -169,6 +172,15 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
// main checks
var ok = true
val diagnosticsFullTextByteArrayStream = ByteArrayOutputStream()
val diagnosticsFullTextPrintStream = PrintStream(diagnosticsFullTextByteArrayStream)
var shouldCheckDiagnosticsFullText = false
val diagnosticsFullTextCollector =
GroupingMessageCollector(
PrintingMessageCollector(diagnosticsFullTextPrintStream, MessageRenderer.SYSTEM_INDEPENDENT_RELATIVE_PATHS, true),
false
)
val actualText = StringBuilder()
for (testFile in files) {
val module = testFile.module
@@ -183,14 +195,20 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
}
val moduleDescriptor = modules[module]!!
val moduleBindingContext = moduleBindings[module]!!
ok = ok and testFile.getActualText(
moduleBindings[module]!!,
moduleBindingContext,
implementingModulesBindings,
actualText,
shouldSkipJvmSignatureDiagnostics(groupedByModule) || isCommonModule,
languageVersionSettingsByModule[module]!!,
moduleDescriptor
)
if (testFile.renderDiagnosticsFullText) {
shouldCheckDiagnosticsFullText = true
AnalyzerWithCompilerReport.reportDiagnostics(moduleBindingContext.diagnostics, diagnosticsFullTextCollector)
}
}
var exceptionFromDynamicCallDescriptorsValidation: Throwable? = null
@@ -201,6 +219,15 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
exceptionFromDynamicCallDescriptorsValidation = e
}
if (shouldCheckDiagnosticsFullText) {
diagnosticsFullTextCollector.flush()
diagnosticsFullTextPrintStream.flush()
KotlinTestUtils.assertEqualsToFile(
File(FileUtil.getNameWithoutExtension(testDataFile.absolutePath) + ".diag.txt"),
String(diagnosticsFullTextByteArrayStream.toByteArray())
)
}
KotlinTestUtils.assertEqualsToFile(getExpectedDiagnosticsFile(testDataFile), actualText.cleanupInferenceDiagnostics()) { s ->
s.replace("COROUTINES_PACKAGE", coroutinesPackage)
}
@@ -218,6 +245,22 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
checkOriginalAndFirTestdataIdentity(testDataFile)
}
private class DiagnosticsFullTextMessageCollector : MessageCollector {
override fun clear() {
TODO("Not yet implemented")
}
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
TODO("Not yet implemented")
}
override fun hasErrors(): Boolean {
TODO("Not yet implemented")
}
}
private fun checkOriginalAndFirTestdataIdentity(testDataFile: File) {
val firTestDataFile = File(testDataFile.absolutePath.replace(".kt", ".fir.kt"))
if (!firTestDataFile.exists()) return
@@ -157,6 +157,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
val withNewInferenceDirective: Boolean
val newInferenceEnabled: Boolean
val renderDiagnosticMessages: Boolean
val renderDiagnosticsFullText: Boolean
init {
this.whatDiagnosticsToConsider = parseDiagnosticFilterDirective(directives, declareCheckType)
@@ -166,8 +167,8 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
this.declareFlexibleType = EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE in directives
this.markDynamicCalls = MARK_DYNAMIC_CALLS_DIRECTIVE in directives
this.withNewInferenceDirective = WITH_NEW_INFERENCE_DIRECTIVE in directives
this.newInferenceEnabled = customLanguageVersionSettings?.supportsFeature(LanguageFeature.NewInference) ?:
shouldUseNewInferenceForTests()
this.newInferenceEnabled =
customLanguageVersionSettings?.supportsFeature(LanguageFeature.NewInference) ?: shouldUseNewInferenceForTests()
if (fileName.endsWith(".java")) {
// TODO: check there are no syntax errors in .java sources
this.createKtFile = lazyOf(null)
@@ -175,10 +176,12 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
this.expectedText = this.clearText
} else {
this.expectedText = textWithMarkers
this.clearText = CheckerTestUtil.parseDiagnosedRanges(addExtras(expectedText), diagnosedRanges, diagnosedRangesToDiagnosticNames)
this.clearText =
CheckerTestUtil.parseDiagnosedRanges(addExtras(expectedText), diagnosedRanges, diagnosedRangesToDiagnosticNames)
this.createKtFile = lazy { TestCheckerUtil.createCheckAndReturnPsiFile(fileName, clearText, project) }
}
this.renderDiagnosticMessages = RENDER_DIAGNOSTICS_MESSAGES in directives
this.renderDiagnosticsFullText = RENDER_DIAGNOSTICS_FULL_TEXT in directives
}
val ktFile: KtFile? by createKtFile
@@ -210,14 +213,14 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
private fun addImports(text: String, imports: String): String {
var result = text
val pattern = Pattern.compile("^package [\\.\\w\\d]*\n", Pattern.MULTILINE)
val pattern = Pattern.compile("^package [.\\w\\d]*\n", Pattern.MULTILINE)
val matcher = pattern.matcher(result)
if (matcher.find()) {
result = if (matcher.find()) {
// add imports after the package directive
result = result.substring(0, matcher.end()) + imports + result.substring(matcher.end())
result.substring(0, matcher.end()) + imports + result.substring(matcher.end())
} else {
// add imports at the beginning
result = imports + result
imports + result
}
return result
}
@@ -264,10 +267,9 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
moduleDescriptor,
this.diagnosedRangesToDiagnosticNames
)
val filteredDiagnostics = ContainerUtil.filter(
diagnostics + jvmSignatureDiagnostics,
{ whatDiagnosticsToConsider.value(it.diagnostic) }
)
val filteredDiagnostics = ContainerUtil.filter(diagnostics + jvmSignatureDiagnostics) {
whatDiagnosticsToConsider.value(it.diagnostic)
}
actualDiagnostics.addAll(filteredDiagnostics)
@@ -320,11 +322,9 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
fun updateUncheckedDiagnostics(diagnostic: TextDiagnostic, start: Int, end: Int) {
diagnostic.enhanceInferenceCompatibility(invertedInferenceCompatibilityOfTest)
uncheckedDiagnostics.add(PositionalTextDiagnostic(diagnostic, start, end
)
)
}
})
uncheckedDiagnostics.add(PositionalTextDiagnostic(diagnostic, start, end))
}
})
actualText.append(
CheckerTestUtil.addDiagnosticMarkersToText(
@@ -370,7 +370,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
companion object {
private const val HELPERS_PATH = "./compiler/testData/diagnostics/helpers"
val DIAGNOSTICS_DIRECTIVE = "DIAGNOSTICS"
val DIAGNOSTICS_PATTERN: Pattern = Pattern.compile("([\\+\\-!])(\\w+)\\s*")
val DIAGNOSTICS_PATTERN: Pattern = Pattern.compile("([+\\-!])(\\w+)\\s*")
val DIAGNOSTICS_TO_INCLUDE_ANYWAY: Set<DiagnosticFactory<*>> = setOf(
Errors.UNRESOLVED_REFERENCE,
Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER,
@@ -406,6 +406,8 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
val RENDER_DIAGNOSTICS_MESSAGES = "RENDER_DIAGNOSTICS_MESSAGES"
val RENDER_DIAGNOSTICS_FULL_TEXT = "RENDER_DIAGNOSTICS_FULL_TEXT"
val DIAGNOSTIC_IN_TESTDATA_PATTERN = Regex("<!>|<!(.*?(\\(\".*?\"\\)|\\(\\))??)+(?<!<)!>")
fun parseDiagnosticFilterDirective(
@@ -435,12 +437,12 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
if (!matcher.find()) {
Assert.fail(
"Wrong syntax in the '// !$DIAGNOSTICS_DIRECTIVE: ...' directive:\n" +
"found: '$directives'\n" +
"Must be '([+-!]DIAGNOSTIC_FACTORY_NAME|ERROR|WARNING|INFO)+'\n" +
"where '+' means 'include'\n" +
" '-' means 'exclude'\n" +
" '!' means 'exclude everything but this'\n" +
"directives are applied in the order of appearance, i.e. !FOO +BAR means include only FOO and BAR"
"found: '$directives'\n" +
"Must be '([+-!]DIAGNOSTIC_FACTORY_NAME|ERROR|WARNING|INFO)+'\n" +
"where '+' means 'include'\n" +
" '-' means 'exclude'\n" +
" '!' means 'exclude everything but this'\n" +
"directives are applied in the order of appearance, i.e. !FOO +BAR means include only FOO and BAR"
)
}
@@ -461,7 +463,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
if (!first) {
Assert.fail(
"'$operation$name' appears in a position rather than the first one, " +
"which effectively cancels all the previous filters in this directive"
"which effectively cancels all the previous filters in this directive"
)
}
condition = newCondition
@@ -59,7 +59,7 @@ import org.jetbrains.kotlin.types.AbstractTypeBindingTest
import org.jetbrains.kotlin.visualizer.fir.AbstractFirVisualizer
import org.jetbrains.kotlin.visualizer.psi.AbstractPsiVisualizer
fun main(args: Array<String>) {
fun main() {
System.setProperty("java.awt.headless", "true")
val excludedFirTestdataPattern = "^(.+)\\.fir\\.kts?\$"
@@ -127,11 +127,11 @@ fun main(args: Array<String>) {
}
testClass<AbstractDiagnosticsTestWithOldJvmBackend> {
model("diagnostics/testsWithJvmBackend")
model("diagnostics/testsWithJvmBackend", targetBackend = TargetBackend.JVM)
}
testClass<AbstractDiagnosticsTestWithJvmIrBackend> {
model("diagnostics/testsWithJvmBackend")
model("diagnostics/testsWithJvmBackend", targetBackend = TargetBackend.JVM_IR)
}
testClass<AbstractMultiPlatformIntegrationTest> {