FIR: Support DEBUG_INFO_CALL calls in tests
This commit is contained in:
@@ -54,8 +54,8 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
|
||||
import org.jetbrains.kotlin.test.Directives
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils.isDirectiveDefined
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.KotlinBaseTest
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
@@ -141,7 +141,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
|
||||
directives: Directives
|
||||
) : KotlinBaseTest.TestFile(fileName, textWithMarkers, directives) {
|
||||
val diagnosedRanges: MutableList<DiagnosedRange> = mutableListOf()
|
||||
private val diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>> = mutableMapOf()
|
||||
val diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>> = mutableMapOf()
|
||||
val actualDiagnostics: MutableList<ActualDiagnostic> = mutableListOf()
|
||||
val expectedText: String
|
||||
val clearText: String
|
||||
|
||||
@@ -5,21 +5,39 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory1
|
||||
import org.jetbrains.kotlin.checkers.utils.TypeOfCall
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.FirDiagnosticsCollector
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.CFGNode
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.EdgeKind
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.FirControlFlowGraphRenderVisitor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.io.File
|
||||
|
||||
/*
|
||||
@@ -84,7 +102,12 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
|
||||
for (testFile in testFiles) {
|
||||
val firFile = firFiles.firstOrNull { it.psi == testFile.ktFile }
|
||||
if (firFile != null) {
|
||||
testFile.getActualText(diagnostics.getValue(firFile), actualText)
|
||||
val debugInfoDiagnostics: List<FirDiagnostic<*>> =
|
||||
collectDebugInfoDiagnostics(firFile, testFile.diagnosedRangesToDiagnosticNames)
|
||||
testFile.getActualText(
|
||||
diagnostics.getValue(firFile) + debugInfoDiagnostics,
|
||||
actualText,
|
||||
)
|
||||
} else {
|
||||
actualText.append(testFile.expectedText)
|
||||
}
|
||||
@@ -92,6 +115,106 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
|
||||
KotlinTestUtils.assertEqualsToFile(file, actualText.toString())
|
||||
}
|
||||
|
||||
protected fun collectDebugInfoDiagnostics(
|
||||
firFile: FirFile,
|
||||
diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>>
|
||||
): List<FirDiagnostic<*>> {
|
||||
val result = mutableListOf<FirDiagnostic<*>>()
|
||||
|
||||
|
||||
object : FirDefaultVisitorVoid() {
|
||||
override fun visitElement(element: FirElement) {
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
|
||||
override fun visitFunctionCall(functionCall: FirFunctionCall) {
|
||||
result.addIfNotNull(
|
||||
createCallDiagnosticIfExpected(functionCall, functionCall.calleeReference, diagnosedRangesToDiagnosticNames)
|
||||
)
|
||||
|
||||
super.visitFunctionCall(functionCall)
|
||||
}
|
||||
}.let(firFile::accept)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun createCallDiagnosticIfExpected(
|
||||
element: FirElement,
|
||||
reference: FirNamedReference,
|
||||
diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>>
|
||||
): FirDiagnosticWithParameters1<FirSourceElement, String>? {
|
||||
val resolvedSymbol = (reference as? FirResolvedNamedReference)?.resolvedSymbol
|
||||
val sourceElement = element.source ?: return null
|
||||
|
||||
val factory = DebugInfoDiagnosticFactory1.CALL
|
||||
if (diagnosedRangesToDiagnosticNames[sourceElement.startOffset..sourceElement.endOffset]?.contains(factory.name) != true) return null
|
||||
|
||||
val fqName = resolvedSymbol?.fqNameUnsafe()
|
||||
|
||||
val argument = Renderers.renderCallInfo(fqName, getTypeOfCall(reference, resolvedSymbol))
|
||||
|
||||
return when (sourceElement) {
|
||||
is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters1(
|
||||
sourceElement,
|
||||
argument,
|
||||
factory.severity,
|
||||
FirDiagnosticFactory1(
|
||||
factory.name,
|
||||
factory.severity,
|
||||
factory
|
||||
)
|
||||
)
|
||||
is FirLightSourceElement -> FirLightDiagnosticWithParameters1(
|
||||
sourceElement,
|
||||
argument,
|
||||
factory.severity,
|
||||
FirDiagnosticFactory1<FirSourceElement, PsiElement, String>(
|
||||
factory.name,
|
||||
factory.severity,
|
||||
factory
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun AbstractFirBasedSymbol<*>.fqNameUnsafe(): FqNameUnsafe? = when (this) {
|
||||
is FirClassLikeSymbol<*> -> classId.asSingleFqName().toUnsafe()
|
||||
is FirCallableSymbol<*> -> callableId.asFqName().toUnsafe()
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun getTypeOfCall(
|
||||
reference: FirNamedReference,
|
||||
resolvedSymbol: AbstractFirBasedSymbol<*>?
|
||||
): String {
|
||||
if (resolvedSymbol == null) return TypeOfCall.UNRESOLVED.nameToRender
|
||||
|
||||
if ((resolvedSymbol as? FirFunctionSymbol)?.callableId?.callableName == OperatorNameConventions.INVOKE
|
||||
&& reference.name != OperatorNameConventions.INVOKE
|
||||
) {
|
||||
return TypeOfCall.VARIABLE_THROUGH_INVOKE.nameToRender
|
||||
}
|
||||
|
||||
return when (val fir = resolvedSymbol.fir) {
|
||||
is FirProperty -> {
|
||||
TypeOfCall.PROPERTY_GETTER.nameToRender
|
||||
}
|
||||
is FirFunction<*> -> buildString {
|
||||
if (fir is FirCallableMemberDeclaration<*>) {
|
||||
if (fir.status.isInline) append("inline ")
|
||||
if (fir.status.isInfix) append("infix ")
|
||||
if (fir.status.isOperator) append("operator ")
|
||||
if (fir.receiverTypeRef != null) append("extension ")
|
||||
}
|
||||
append(TypeOfCall.FUNCTION.nameToRender)
|
||||
}
|
||||
else -> TypeOfCall.OTHER.nameToRender
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected fun collectDiagnostics(firFiles: List<FirFile>): Map<FirFile, List<FirDiagnostic<*>>> {
|
||||
val collectors = mutableMapOf<FirSession, AbstractDiagnosticCollector>()
|
||||
val result = mutableMapOf<FirFile, List<FirDiagnostic<*>>>()
|
||||
@@ -165,4 +288,4 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-3
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirLightDiagnostic
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -33,7 +34,11 @@ abstract class AbstractFirDiagnosticsWithLightTreeTest : AbstractFirDiagnosticsT
|
||||
for (testFile in testFiles) {
|
||||
val firFile = firFiles.firstOrNull { it.name == testFile.name } ?: continue
|
||||
val ktFile = testFile.ktFile!!
|
||||
val diagnostics = fileToDiagnostics[firFile] ?: emptyList()
|
||||
val basicDiagnostics = fileToDiagnostics[firFile] ?: emptyList()
|
||||
val debugInfoDiagnostics: List<FirDiagnostic<*>> =
|
||||
collectDebugInfoDiagnostics(firFile, testFile.diagnosedRangesToDiagnosticNames)
|
||||
|
||||
val diagnostics = basicDiagnostics + debugInfoDiagnostics
|
||||
|
||||
val actualDiagnostics = diagnostics.groupBy {
|
||||
require(it is FirLightDiagnostic)
|
||||
@@ -42,7 +47,11 @@ abstract class AbstractFirDiagnosticsWithLightTreeTest : AbstractFirDiagnosticsT
|
||||
|
||||
val existingDiagnostics = testFile.diagnosedRanges.groupBy {
|
||||
it.start
|
||||
}.mapValues { (_, ranges) -> ranges.flatMap { it.getDiagnostics().map { it.name } }.countEntries() }
|
||||
}.mapValues { (_, ranges) ->
|
||||
ranges.flatMap { diagnosedRange ->
|
||||
diagnosedRange.getDiagnostics().filterNot { it.name.contains("DEBUG_INFO_") }.map { it.name }
|
||||
}.countEntries()
|
||||
}
|
||||
|
||||
for (startOffset in actualDiagnostics.keys + existingDiagnostics.keys) {
|
||||
val expected = existingDiagnostics[startOffset] ?: emptyMap()
|
||||
@@ -102,4 +111,4 @@ abstract class AbstractFirDiagnosticsWithLightTreeTest : AbstractFirDiagnosticsT
|
||||
IsActual
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user