[Spec tests] Small clean-up CheckerTestUtil and around it

This commit is contained in:
Victor Petukhov
2020-03-27 16:55:06 +03:00
parent 90d1cdf2e1
commit a29385e758
8 changed files with 110 additions and 167 deletions
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.diagnostics.DiagnosticFactoryWithPsiElement
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.isCommon
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
@@ -47,6 +46,12 @@ import org.jetbrains.kotlin.util.slicedMap.WritableSlice
import java.util.*
import java.util.regex.Pattern
data class DiagnosticsRenderingConfiguration(
val platform: String?,
val withNewInference: Boolean,
val languageVersionSettings: LanguageVersionSettings?
)
object CheckerTestUtil {
const val NEW_INFERENCE_PREFIX = "NI"
const val OLD_INFERENCE_PREFIX = "OI"
@@ -63,8 +68,7 @@ object CheckerTestUtil {
root: PsiElement,
markDynamicCalls: Boolean,
dynamicCallDescriptors: MutableList<DeclarationDescriptor>,
withNewInference: Boolean,
languageVersionSettings: LanguageVersionSettings,
configuration: DiagnosticsRenderingConfiguration,
dataFlowValueFactory: DataFlowValueFactory?,
moduleDescriptor: ModuleDescriptorImpl?,
diagnosedRanges: MutableMap<IntRange, MutableSet<String>>? = null
@@ -74,9 +78,7 @@ object CheckerTestUtil {
root,
markDynamicCalls,
dynamicCallDescriptors,
null,
withNewInference,
languageVersionSettings,
configuration,
dataFlowValueFactory,
moduleDescriptor,
diagnosedRanges
@@ -93,9 +95,7 @@ object CheckerTestUtil {
root,
markDynamicCalls,
dynamicCallDescriptors,
platform.single().platformName,
withNewInference,
languageVersionSettings,
configuration.copy(platform = platform.single().platformName),
dataFlowValueFactory,
moduleDescriptor,
diagnosedRanges
@@ -111,9 +111,7 @@ object CheckerTestUtil {
root: PsiElement,
markDynamicCalls: Boolean,
dynamicCallDescriptors: MutableList<DeclarationDescriptor>,
platform: String?,
withNewInference: Boolean,
languageVersionSettings: LanguageVersionSettings?,
configuration: DiagnosticsRenderingConfiguration,
dataFlowValueFactory: DataFlowValueFactory?,
moduleDescriptor: ModuleDescriptorImpl?,
diagnosedRanges: MutableMap<IntRange, MutableSet<String>>? = null
@@ -122,12 +120,12 @@ object CheckerTestUtil {
bindingContext.diagnostics.forEach { diagnostic ->
if (PsiTreeUtil.isAncestor(root, diagnostic.psiElement, false)) {
diagnostics.add(ActualDiagnostic(diagnostic, platform, withNewInference))
diagnostics.add(ActualDiagnostic(diagnostic, configuration.platform, configuration.withNewInference))
}
}
for (errorElement in AnalyzingUtils.getSyntaxErrorRanges(root)) {
diagnostics.add(ActualDiagnostic(SyntaxErrorDiagnostic(errorElement), platform, withNewInference))
diagnostics.add(ActualDiagnostic(SyntaxErrorDiagnostic(errorElement), configuration.platform, configuration.withNewInference))
}
diagnostics.addAll(
@@ -136,9 +134,7 @@ object CheckerTestUtil {
bindingContext,
markDynamicCalls,
dynamicCallDescriptors,
platform,
withNewInference,
languageVersionSettings,
configuration,
dataFlowValueFactory,
moduleDescriptor,
diagnosedRanges
@@ -153,9 +149,7 @@ object CheckerTestUtil {
bindingContext: BindingContext,
markDynamicCalls: Boolean,
dynamicCallDescriptors: MutableList<DeclarationDescriptor>,
platform: String?,
withNewInference: Boolean,
languageVersionSettings: LanguageVersionSettings?,
configuration: DiagnosticsRenderingConfiguration,
dataFlowValueFactory: DataFlowValueFactory?,
moduleDescriptor: ModuleDescriptorImpl?,
diagnosedRanges: Map<IntRange, MutableSet<String>>?
@@ -169,15 +163,15 @@ object CheckerTestUtil {
dynamicCallDescriptors,
markDynamicCalls,
debugAnnotations,
withNewInference,
platform
configuration.withNewInference,
configuration.platform
)
)
// this code is used in tests and in internal action 'copy current file as diagnostic test'
//noinspection unchecked
val factoryList = listOf(
val factoryListForDiagnosticsOnExpression = listOf(
BindingContext.EXPRESSION_TYPE_INFO to DebugInfoDiagnosticFactory1.EXPRESSION_TYPE,
BindingContext.SMARTCAST to DebugInfoDiagnosticFactory0.SMARTCAST,
BindingContext.IMPLICIT_RECEIVER_SMARTCAST to DebugInfoDiagnosticFactory0.IMPLICIT_RECEIVER_SMARTCAST,
@@ -186,113 +180,69 @@ object CheckerTestUtil {
BindingContext.IMPLICIT_EXHAUSTIVE_WHEN to DebugInfoDiagnosticFactory0.IMPLICIT_EXHAUSTIVE
)
val kotlinSpecificInfo = KotlinSpecificInfo(
platform,
withNewInference,
languageVersionSettings,
)
/** for expressions*/
for ((context, factory) in factoryList) {
renderDiagnosticsForExpressions(
context,
factory,
root,
bindingContext,
kotlinSpecificInfo,
dataFlowValueFactory,
moduleDescriptor,
diagnosedRanges,
debugAnnotations
)
}
val factoryListForDiagnosticsOnCall = listOf(BindingContext.RESOLVED_CALL to DebugInfoDiagnosticFactory1.CALL)
/** for calls*/
renderDiagnosticsForCalls(
BindingContext.RESOLVED_CALL,
DebugInfoDiagnosticFactory1.CALL,
root,
bindingContext,
kotlinSpecificInfo,
dataFlowValueFactory,
moduleDescriptor,
diagnosedRanges,
debugAnnotations
renderDiagnosticsByFactoryList(
factoryListForDiagnosticsOnExpression, root, bindingContext, configuration,
dataFlowValueFactory, moduleDescriptor, diagnosedRanges, debugAnnotations
)
renderDiagnosticsByFactoryList(
factoryListForDiagnosticsOnCall, root, bindingContext, configuration,
dataFlowValueFactory, moduleDescriptor, diagnosedRanges, debugAnnotations
) { it.callElement as? KtExpression }
return debugAnnotations
}
private class KotlinSpecificInfo(
val platform: String?,
val withNewInference: Boolean,
val languageVersionSettings: LanguageVersionSettings?
)
private fun renderDiagnosticsForCalls(
context: WritableSlice<Call, ResolvedCall<*>>, callFactory: DebugInfoDiagnosticFactory1,
root: PsiElement, bindingContext: BindingContext, kotlinSpecificInfo: KotlinSpecificInfo,
dataFlowValueFactory: DataFlowValueFactory?,
moduleDescriptor: ModuleDescriptorImpl?,
diagnosedRanges: Map<IntRange, MutableSet<String>>?,
debugAnnotations: MutableList<ActualDiagnostic>
) {
for ((call, _) in bindingContext.getSliceContents(context)) {
val callElement = call.callElement as? KtExpression ?: continue
renderDiagnostics(
callFactory, callElement,
root, bindingContext, kotlinSpecificInfo, dataFlowValueFactory, moduleDescriptor, diagnosedRanges,
debugAnnotations
)
}
}
private fun renderDiagnosticsForExpressions(
context: WritableSlice<out KtExpression, out Any>, factory: DebugInfoDiagnosticFactory,
private fun <T, K> renderDiagnosticsByFactoryList(
factoryList: List<Pair<WritableSlice<out T, out K>, DebugInfoDiagnosticFactory>>,
root: PsiElement,
bindingContext: BindingContext,
kotlinSpecificInfo: KotlinSpecificInfo,
configuration: DiagnosticsRenderingConfiguration,
dataFlowValueFactory: DataFlowValueFactory?,
moduleDescriptor: ModuleDescriptorImpl?,
diagnosedRanges: Map<IntRange, MutableSet<String>>?,
debugAnnotations: MutableList<ActualDiagnostic>
debugAnnotations: MutableList<ActualDiagnostic>,
toExpression: (T) -> KtExpression? = { it as? KtExpression }
) {
for ((expression, _) in bindingContext.getSliceContents(context)) {
renderDiagnostics(
factory, expression,
root, bindingContext, kotlinSpecificInfo, dataFlowValueFactory, moduleDescriptor, diagnosedRanges,
debugAnnotations
)
for ((context, factory) in factoryList) {
for ((element, _) in bindingContext.getSliceContents(context)) {
renderDiagnostics(
factory,
toExpression(element) ?: continue,
root, bindingContext, configuration, dataFlowValueFactory, moduleDescriptor, diagnosedRanges,
debugAnnotations
)
}
}
}
private fun renderDiagnostics(
callFactory: DebugInfoDiagnosticFactory, callElement: KtExpression,
factory: DebugInfoDiagnosticFactory,
expression: KtExpression,
root: PsiElement,
bindingContext: BindingContext,
kotlinSpecificInfo: KotlinSpecificInfo,
configuration: DiagnosticsRenderingConfiguration,
dataFlowValueFactory: DataFlowValueFactory?,
moduleDescriptor: ModuleDescriptorImpl?,
diagnosedRanges: Map<IntRange, MutableSet<String>>?,
debugAnnotations: MutableList<ActualDiagnostic>
) {
(callFactory as DiagnosticFactoryWithPsiElement<*, *>)
val needRender = !callFactory.withExplicitDefinitionOnly
|| diagnosedRanges?.get(callElement.startOffset..callElement.endOffset)?.contains(callFactory.name) == true
if (PsiTreeUtil.isAncestor(root, callElement, false) && needRender) {
val diagnostic = callFactory.createDiagnostic(
callElement,
if (factory !is DiagnosticFactory<*>) return
val needRender = !factory.withExplicitDefinitionOnly
|| diagnosedRanges?.get(expression.startOffset..expression.endOffset)?.contains(factory.name) == true
if (PsiTreeUtil.isAncestor(root, expression, false) && needRender) {
val diagnostic = factory.createDiagnostic(
expression,
bindingContext,
dataFlowValueFactory,
kotlinSpecificInfo.languageVersionSettings,
configuration.languageVersionSettings,
moduleDescriptor
)
debugAnnotations.add(ActualDiagnostic(diagnostic, kotlinSpecificInfo.platform, kotlinSpecificInfo.withNewInference))
debugAnnotations.add(ActualDiagnostic(diagnostic, configuration.platform, configuration.withNewInference))
}
}
@@ -726,50 +676,43 @@ object CheckerTestUtil {
return Pair(result, null)
}
fun getCallDebugInfo(
expression: PsiElement,
bindingContext: BindingContext,
): Pair<FqNameUnsafe?, String?> {
val callToTypeOfCall =
when (expression) {
is KtCallableReferenceExpression -> {
expression.callableReference.getCall(bindingContext) to getTypeOfCall(expression, bindingContext)
}
is KtExpression -> {
expression.getCall(bindingContext) to getTypeOfCall(expression, bindingContext)
}
else -> null
}
val fqNameUnsafe = bindingContext[BindingContext.RESOLVED_CALL, callToTypeOfCall?.first]?.candidateDescriptor?.fqNameUnsafe
return fqNameUnsafe to callToTypeOfCall?.second
fun getCallDebugInfo(element: PsiElement, bindingContext: BindingContext): Pair<FqNameUnsafe?, String> {
if (element !is KtExpression)
return null to TypeOfCall.OTHER.nameToRender
val call = element.getCall(bindingContext)
val typeOfCall = getTypeOfCall(element, bindingContext)
val fqNameUnsafe = bindingContext[BindingContext.RESOLVED_CALL, call]?.candidateDescriptor?.fqNameUnsafe
return fqNameUnsafe to typeOfCall
}
/**
* if resolvedCall is VariableAsFunctionResolvedCall -- then typeOfCall is variable + invoke
* if resolvedCall.candidateDescriptor is PropertyDescriptor -- then typeOfCall is variable
* if resolvedCall.candidateDescriptor is FunctionDescriptor -- then typeOfCall is function
*/
fun getTypeOfCall(expression: KtExpression, bindingContext: BindingContext): String? {
val resolvedCall = expression.getResolvedCall(bindingContext) ?: return null
return if (resolvedCall is VariableAsFunctionResolvedCall) {
"variable&invoke"
} else {
when (val functionDescriptor = resolvedCall.candidateDescriptor) {
is PropertyDescriptor -> {
"variable"
}
is FunctionDescriptor -> {
return buildString {
if (functionDescriptor.isInline) append("inline ")
if (functionDescriptor.isInfix) append("infix ")
if (functionDescriptor.isOperator) append("operator ")
if (functionDescriptor.isExtension) append("extension ")
append("function")
}
}
else -> null
private fun getTypeOfCall(expression: KtExpression, bindingContext: BindingContext): String {
val resolvedCall = expression.getResolvedCall(bindingContext) ?: return TypeOfCall.UNRESOLVED.nameToRender
if (resolvedCall is VariableAsFunctionResolvedCall)
return TypeOfCall.VARIABLE_THROUGH_INVOKE.nameToRender
return when (val functionDescriptor = resolvedCall.candidateDescriptor) {
is PropertyDescriptor -> {
TypeOfCall.PROPERTY_GETTER.nameToRender
}
is FunctionDescriptor -> buildString {
if (functionDescriptor.isInline) append("inline ")
if (functionDescriptor.isInfix) append("infix ")
if (functionDescriptor.isOperator) append("operator ")
if (functionDescriptor.isExtension) append("extension ")
append(TypeOfCall.FUNCTION.nameToRender)
}
else -> TypeOfCall.OTHER.nameToRender
}
}
}
private enum class TypeOfCall(val nameToRender: String) {
VARIABLE_THROUGH_INVOKE("variable&invoke"),
PROPERTY_GETTER("variable"),
FUNCTION("function"),
UNRESOLVED("unresolved"),
OTHER("other")
}
@@ -740,12 +740,11 @@ object Renderers {
return typesAsString.sorted().joinToString(separator = " & ")
}
fun renderCallInfo(fqName: FqNameUnsafe?, typeCall: String?): String {
val info = java.lang.StringBuilder()
info.append("fqName: ${fqName?.asString() ?: "fqName is unknown"}; ")
info.append("typeCall: ${typeCall ?: "typeCall is unknown"}")
return info.toString()
}
fun renderCallInfo(fqName: FqNameUnsafe?, typeCall: String) =
buildString {
append("fqName: ${fqName?.asString() ?: "fqName is unknown"}; ")
append("typeCall: $typeCall")
}
}
fun DescriptorRenderer.asRenderer() = SmartDescriptorRenderer(this)
@@ -96,7 +96,6 @@ public interface BindingContext {
WritableSlice<KtTypeReference, KotlinType> TYPE = Slices.createSimpleSlice();
WritableSlice<KtTypeReference, KotlinType> ABBREVIATED_TYPE = Slices.createSimpleSlice();
WritableSlice<KtExpression, KotlinTypeInfo> EXPRESSION_TYPE_INFO = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<KtExpression, KotlinTypeInfo> FQ_NAME = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<KtExpression, DataFlowInfo> DATA_FLOW_INFO_BEFORE = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<KtExpression, KotlinType> EXPECTED_EXPRESSION_TYPE = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<KtElement, Computation> EXPRESSION_EFFECTS = Slices.createSimpleSlice();
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.checkers.diagnostics.TextDiagnostic
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory0
import org.jetbrains.kotlin.checkers.diagnostics.factories.SyntaxErrorDiagnosticFactory
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
import org.jetbrains.kotlin.checkers.utils.DiagnosticsRenderingConfiguration
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageFeature
@@ -260,8 +261,11 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
ktFile,
markDynamicCalls,
dynamicCallDescriptors,
newInferenceEnabled,
languageVersionSettings,
DiagnosticsRenderingConfiguration(
platform = null,
withNewInference,
languageVersionSettings,
),
DataFlowValueFactoryImpl(languageVersionSettings),
moduleDescriptor,
this.diagnosedRangesToDiagnosticNames
@@ -11,8 +11,8 @@ import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.checkers.diagnostics.ActualDiagnostic
import org.jetbrains.kotlin.checkers.diagnostics.TextDiagnostic
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
import org.jetbrains.kotlin.checkers.utils.DiagnosticsRenderingConfiguration
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
import org.jetbrains.kotlin.test.ConfigurationKind
@@ -43,9 +43,7 @@ private abstract class Test(private vararg val expectedMessages: String) {
bindingContext, psiFile,
false,
mutableListOf(),
null,
false,
languageVersionSettings,
DiagnosticsRenderingConfiguration(null, false, languageVersionSettings),
dataFlowValueFactory,
emptyModule
)
@@ -59,9 +57,7 @@ private abstract class Test(private vararg val expectedMessages: String) {
psiFile,
false,
mutableListOf(),
null,
false,
languageVersionSettings,
DiagnosticsRenderingConfiguration(null, false, languageVersionSettings),
dataFlowValueFactory,
emptyModule
)
@@ -92,7 +92,7 @@ class Case3() {
fun String?.orEmpty(): String = "my local inner extension for $this"
fun String?.funWithTrailingLambda( x : Any? = null, body : ()-> String = {""} ): String = body()
<!DEBUG_INFO_CALL("fqName: sentence3.Case3.case3.innerFirst.s; typeCall: typeCall is unknown")!>s<!>?.<!DEBUG_INFO_CALL("fqName: sentence3.Case3.case3.innerFirst.orEmpty; typeCall: extension function")!>orEmpty()<!>
<!DEBUG_INFO_CALL("fqName: sentence3.Case3.case3.innerFirst.s; typeCall: other")!>s<!>?.<!DEBUG_INFO_CALL("fqName: sentence3.Case3.case3.innerFirst.orEmpty; typeCall: extension function")!>orEmpty()<!>
//trailing lambda
s.<!DEBUG_INFO_CALL("fqName: sentence3.Case3.case3.innerFirst.funWithTrailingLambda; typeCall: extension function")!>funWithTrailingLambda { "ss" }<!>
s.<!DEBUG_INFO_CALL("fqName: sentence3.Case3.case3.innerFirst.funWithTrailingLambda; typeCall: extension function")!>funWithTrailingLambda (x= 1) { "ss" }<!>
@@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
import org.jetbrains.kotlin.checkers.utils.DiagnosticsRenderingConfiguration
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
import org.jetbrains.kotlin.psi.KtFile
import java.awt.Toolkit
@@ -40,9 +41,7 @@ class CopyAsDiagnosticTestAction : AnAction() {
psiFile,
false,
mutableListOf(),
null,
false,
null,
DiagnosticsRenderingConfiguration(null, false, null),
null,
null
)
@@ -12,6 +12,7 @@ import com.intellij.psi.PsiManager
import com.intellij.util.io.exists
import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
import org.jetbrains.kotlin.checkers.utils.DiagnosticsRenderingConfiguration
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.idea.multiplatform.setupMppProjectFromTextFile
import org.jetbrains.kotlin.idea.project.KotlinMultiplatformAnalysisModeComponent
@@ -81,9 +82,11 @@ abstract class AbstractMultiModuleIdeResolveTest : AbstractMultiModuleTest() {
file,
markDynamicCalls = false,
dynamicCallDescriptors = mutableListOf(),
platform = null, // we don't need to attach platform-description string to diagnostic here
withNewInference = false,
languageVersionSettings = resolutionFacade.frontendService(),
configuration = DiagnosticsRenderingConfiguration(
platform = null, // we don't need to attach platform-description string to diagnostic here
withNewInference = false,
languageVersionSettings = resolutionFacade.frontendService(),
),
dataFlowValueFactory = resolutionFacade.frontendService(),
moduleDescriptor = moduleDescriptor as ModuleDescriptorImpl
).filter { diagnosticsFilter.value(it.diagnostic) }