[FIR] Add old FE-like diagnostic tests
This commit is contained in:
-5
@@ -1,5 +0,0 @@
|
|||||||
<INAPPLICABLE_INFIX_MODIFIER>: infix fun Int.foo(x: Int, y: Int) {}
|
|
||||||
|
|
||||||
<INAPPLICABLE_INFIX_MODIFIER>: infix fun Int.bar() {}
|
|
||||||
|
|
||||||
<INAPPLICABLE_INFIX_MODIFIER>: infix fun baz(x: Int, y: Int) {}
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
infix fun Int.good(x: Int) {}
|
infix fun Int.good(x: Int) {}
|
||||||
|
|
||||||
infix fun Int.foo(x: Int, y: Int) {}
|
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun Int.foo(x: Int, y: Int) {}<!>
|
||||||
|
|
||||||
infix fun Int.bar() {}
|
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun Int.bar() {}<!>
|
||||||
|
|
||||||
infix fun baz(x: Int, y: Int) {}
|
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun baz(x: Int, y: Int) {}<!>
|
||||||
|
|
||||||
infix class A
|
infix class A
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas
|
|||||||
return createEnvironmentWithMockJdk(configurationKind)
|
return createEnvironmentWithMockJdk(configurationKind)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doCreateAndProcessFir(ktFiles: List<KtFile>): List<FirFile> {
|
protected fun doCreateAndProcessFir(ktFiles: List<KtFile>): List<FirFile> {
|
||||||
|
|
||||||
val scope = GlobalSearchScope.filesScope(project, ktFiles.mapNotNull { it.virtualFile })
|
val scope = GlobalSearchScope.filesScope(project, ktFiles.mapNotNull { it.virtualFile })
|
||||||
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
|
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
|
||||||
val session = createSession(environment, scope)
|
val session = createSession(environment, scope)
|
||||||
@@ -48,26 +47,25 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun processInputFile(path: String): List<FirFile> {
|
protected fun generateKtFiles(path: String): List<KtFile> {
|
||||||
val file = File(path)
|
val file = File(path)
|
||||||
|
|
||||||
val allFiles = listOf(file) + file.parentFile.listFiles { sibling ->
|
val allFiles = listOf(file) + file.parentFile.listFiles { sibling ->
|
||||||
sibling.name.removePrefix(file.nameWithoutExtension).removeSuffix(file.extension).matches("\\.[0-9]+\\.".toRegex())
|
sibling.name.removePrefix(file.nameWithoutExtension).removeSuffix(file.extension).matches("\\.[0-9]+\\.".toRegex())
|
||||||
}
|
}
|
||||||
|
|
||||||
val ktFiles =
|
return allFiles.map {
|
||||||
allFiles.map {
|
val text = KotlinTestUtils.doLoadFile(it)
|
||||||
val text = KotlinTestUtils.doLoadFile(it)
|
it.name to text
|
||||||
it.name to text
|
}.sortedBy { (_, text) ->
|
||||||
}
|
KotlinTestUtils.parseDirectives(text)["analyzePriority"]?.toInt()
|
||||||
.sortedBy { (_, text) ->
|
}.map { (name, text) ->
|
||||||
KotlinTestUtils.parseDirectives(text)["analyzePriority"]?.toInt()
|
KotlinTestUtils.createFile(name, text, project)
|
||||||
}
|
}
|
||||||
.map { (name, text) ->
|
}
|
||||||
KotlinTestUtils.createFile(name, text, project)
|
|
||||||
}
|
|
||||||
|
|
||||||
return doCreateAndProcessFir(ktFiles)
|
protected fun processInputFile(path: String): List<FirFile> {
|
||||||
|
return doCreateAndProcessFir(generateKtFiles(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun doTest(path: String) {
|
open fun doTest(path: String) {
|
||||||
|
|||||||
+161
-17
@@ -5,40 +5,184 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import org.jetbrains.kotlin.checkers.DiagnosedRange
|
||||||
|
import org.jetbrains.kotlin.checkers.DiagnosticDiffCallbacks
|
||||||
|
import org.jetbrains.kotlin.checkers.TestCheckerUtil
|
||||||
|
import org.jetbrains.kotlin.checkers.diagnostics.ActualDiagnostic
|
||||||
|
import org.jetbrains.kotlin.checkers.diagnostics.PositionalTextDiagnostic
|
||||||
|
import org.jetbrains.kotlin.checkers.diagnostics.TextDiagnostic
|
||||||
|
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
|
||||||
|
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnostic
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.AbstractDiagnosticCollector
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.ParallelDiagnosticsCollector
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.ParallelDiagnosticsCollector
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.SimpleDiagnosticsCollector
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.components.DeclarationCheckersDiagnosticComponent
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.components.DeclarationCheckersDiagnosticComponent
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
|
import org.jetbrains.kotlin.test.TestFiles
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class AbstractFirResolveWithDiagnosticsTestCase : AbstractFirResolveTestCase() {
|
abstract class AbstractFirResolveWithDiagnosticsTestCase : AbstractFirResolveTestCase() {
|
||||||
override fun doTest(path: String) {
|
override fun doTest(path: String) {
|
||||||
val firFiles = processInputFile(path)
|
val file = File(path)
|
||||||
|
val expectedText = KotlinTestUtils.doLoadFile(file)
|
||||||
|
val testFiles = createTestFiles(file, expectedText)
|
||||||
|
val firFiles = doCreateAndProcessFir(testFiles.mapNotNull { it.ktFile })
|
||||||
checkFir(path, firFiles)
|
checkFir(path, firFiles)
|
||||||
checkDiagnostics(path, firFiles)
|
checkDiagnostics(file, testFiles, firFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkDiagnostics(path: String, firFiles: List<FirFile>) {
|
private fun createCollector(): AbstractDiagnosticCollector {
|
||||||
// val collector = SimpleDiagnosticsCollector()
|
// val collector = SimpleDiagnosticsCollector()
|
||||||
val collector = ParallelDiagnosticsCollector(4)
|
val collector = ParallelDiagnosticsCollector(4)
|
||||||
collector.initializeComponents(DeclarationCheckersDiagnosticComponent(collector))
|
collector.initializeComponents(DeclarationCheckersDiagnosticComponent(collector))
|
||||||
val diagnostics = mutableListOf<ConeDiagnostic>()
|
return collector
|
||||||
for (file in firFiles) {
|
}
|
||||||
diagnostics += collector.collectDiagnostics(file)
|
|
||||||
|
private fun checkDiagnostics(file: File, testFiles: List<TestFile>, firFiles: List<FirFile>) {
|
||||||
|
val collector = createCollector()
|
||||||
|
val actualText = StringBuilder()
|
||||||
|
for ((testFile, firFile) in testFiles zip firFiles) {
|
||||||
|
val coneDiagnostics = collector.collectDiagnostics(firFile)
|
||||||
|
testFile.getActualText(coneDiagnostics, actualText)
|
||||||
}
|
}
|
||||||
val expectedPath = path.replace(".kt", ".diagnostics.txt")
|
KotlinTestUtils.assertEqualsToFile(file, actualText.toString())
|
||||||
val expectedFile = File(expectedPath)
|
}
|
||||||
if (diagnostics.isEmpty()) {
|
|
||||||
assertFalse("There is no diagnostics but expected file exists", expectedFile.exists())
|
private fun createTestFiles(file: File, expectedText: String?): List<TestFile> {
|
||||||
return
|
return TestFiles.createTestFiles(file.name, expectedText, object : TestFiles.TestFileFactory<Nothing?, TestFile> {
|
||||||
|
override fun createFile(module: Nothing?, fileName: String, text: String, directives: MutableMap<String, String>): TestFile {
|
||||||
|
return TestFile(fileName, text, directives)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createModule(name: String, dependencies: MutableList<String>, friends: MutableList<String>): Nothing? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private inner class TestFile(
|
||||||
|
fileName: String,
|
||||||
|
textWithMarkers: String,
|
||||||
|
val directives: Map<String, String>
|
||||||
|
) {
|
||||||
|
private val diagnosedRanges: MutableList<DiagnosedRange> = mutableListOf()
|
||||||
|
private val diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>> = mutableMapOf()
|
||||||
|
val ktFile: KtFile? by lazy {
|
||||||
|
if (fileName.endsWith(".java")) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
TestCheckerUtil.createCheckAndReturnPsiFile(fileName, clearText, project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val actualDiagnostics: MutableList<ActualDiagnostic> = mutableListOf()
|
||||||
|
val clearText: String
|
||||||
|
val expectedText: String
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (fileName.endsWith(".java")) {
|
||||||
|
clearText = textWithMarkers
|
||||||
|
expectedText = clearText
|
||||||
|
} else {
|
||||||
|
expectedText = textWithMarkers
|
||||||
|
clearText = CheckerTestUtil.parseDiagnosedRanges(addExtracts(expectedText), diagnosedRanges, diagnosedRangesToDiagnosticNames)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val actual = diagnostics.joinToString("\n\n") {
|
fun addExtracts(text: String): String {
|
||||||
val text = (it.source as FirPsiSourceElement).psi.text
|
// TODO
|
||||||
"<${it.diagnostic.factory.name}>: $text"
|
return text
|
||||||
}
|
}
|
||||||
KotlinTestUtils.assertEqualsToFile(expectedFile, actual)
|
|
||||||
|
fun getActualText(
|
||||||
|
coneDiagnostics: Iterable<ConeDiagnostic>,
|
||||||
|
actualText: StringBuilder
|
||||||
|
): Boolean {
|
||||||
|
val ktFile = this.ktFile
|
||||||
|
if (ktFile == null) {
|
||||||
|
// TODO: check java files too
|
||||||
|
actualText.append(this.clearText)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ktFile.name.endsWith("CoroutineUtil.kt") && ktFile.packageFqName == FqName("helpers")) return true
|
||||||
|
|
||||||
|
// TODO: report JVM signature diagnostics also for implementing modules
|
||||||
|
|
||||||
|
val ok = booleanArrayOf(true)
|
||||||
|
val diagnostics = coneDiagnostics.toActualDiagnostic()
|
||||||
|
val filteredDiagnostics = diagnostics // TODO
|
||||||
|
|
||||||
|
actualDiagnostics.addAll(filteredDiagnostics)
|
||||||
|
|
||||||
|
val uncheckedDiagnostics = mutableListOf<PositionalTextDiagnostic>()
|
||||||
|
|
||||||
|
val diagnosticToExpectedDiagnostic =
|
||||||
|
CheckerTestUtil.diagnosticsDiff(diagnosedRanges, filteredDiagnostics, object : DiagnosticDiffCallbacks {
|
||||||
|
override fun missingDiagnostic(diagnostic: TextDiagnostic, expectedStart: Int, expectedEnd: Int) {
|
||||||
|
val message = "Missing " + diagnostic.description + PsiDiagnosticUtils.atLocation(
|
||||||
|
ktFile,
|
||||||
|
TextRange(expectedStart, expectedEnd)
|
||||||
|
)
|
||||||
|
System.err.println(message)
|
||||||
|
ok[0] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun wrongParametersDiagnostic(
|
||||||
|
expectedDiagnostic: TextDiagnostic,
|
||||||
|
actualDiagnostic: TextDiagnostic,
|
||||||
|
start: Int,
|
||||||
|
end: Int
|
||||||
|
) {
|
||||||
|
val message = "Parameters of diagnostic not equal at position " +
|
||||||
|
PsiDiagnosticUtils.atLocation(ktFile, TextRange(start, end)) +
|
||||||
|
". Expected: ${expectedDiagnostic.asString()}, actual: $actualDiagnostic"
|
||||||
|
System.err.println(message)
|
||||||
|
ok[0] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unexpectedDiagnostic(diagnostic: TextDiagnostic, actualStart: Int, actualEnd: Int) {
|
||||||
|
val message = "Unexpected ${diagnostic.description}${PsiDiagnosticUtils.atLocation(
|
||||||
|
ktFile,
|
||||||
|
TextRange(actualStart, actualEnd)
|
||||||
|
)}"
|
||||||
|
System.err.println(message)
|
||||||
|
ok[0] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateUncheckedDiagnostics(diagnostic: TextDiagnostic, start: Int, end: Int) {
|
||||||
|
uncheckedDiagnostics.add(PositionalTextDiagnostic(diagnostic, start, end))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
actualText.append(
|
||||||
|
CheckerTestUtil.addDiagnosticMarkersToText(
|
||||||
|
ktFile,
|
||||||
|
filteredDiagnostics,
|
||||||
|
diagnosticToExpectedDiagnostic,
|
||||||
|
{ file -> file.text },
|
||||||
|
uncheckedDiagnostics,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
stripExtras(actualText)
|
||||||
|
|
||||||
|
return ok[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stripExtras(text: StringBuilder): StringBuilder {
|
||||||
|
// TODO
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Iterable<ConeDiagnostic>.toActualDiagnostic(): Collection<ActualDiagnostic> {
|
||||||
|
return map { ActualDiagnostic(it.diagnostic, null, true) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ object CheckerTestUtil {
|
|||||||
languageVersionSettings: LanguageVersionSettings?,
|
languageVersionSettings: LanguageVersionSettings?,
|
||||||
dataFlowValueFactory: DataFlowValueFactory?,
|
dataFlowValueFactory: DataFlowValueFactory?,
|
||||||
moduleDescriptor: ModuleDescriptorImpl?,
|
moduleDescriptor: ModuleDescriptorImpl?,
|
||||||
diagnosedRanges: MutableMap<IntRange, MutableSet<String>>?
|
diagnosedRanges: Map<IntRange, MutableSet<String>>?
|
||||||
): List<ActualDiagnostic> {
|
): List<ActualDiagnostic> {
|
||||||
val debugAnnotations = mutableListOf<ActualDiagnostic>()
|
val debugAnnotations = mutableListOf<ActualDiagnostic>()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user