Add lazy debug diagnostic DEBUG_INFO_EXPRESSION_TYPE

This commit is contained in:
victor.petukhov
2018-12-28 14:05:28 +03:00
parent f92232f015
commit b354518a41
14 changed files with 288 additions and 45 deletions
@@ -8,11 +8,14 @@ package org.jetbrains.kotlin.checkers.diagnostics
import com.intellij.openapi.util.text.StringUtil
import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory1
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil.INDIVIDUAL_PARAMETER_PATTERN
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil.SHOULD_BE_ESCAPED
import org.jetbrains.kotlin.diagnostics.rendering.AbstractDiagnosticWithParametersRenderer
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticWithParameters1Renderer
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.TO_STRING
import java.util.regex.Pattern
class TextDiagnostic(
@@ -141,9 +144,12 @@ class TextDiagnostic(
private fun asTextDiagnostic(actualDiagnostic: ActualDiagnostic): TextDiagnostic {
val diagnostic = actualDiagnostic.diagnostic
val renderer = DefaultErrorMessages.getRendererForDiagnostic(diagnostic)
val renderer = when (diagnostic.factory) {
is DebugInfoDiagnosticFactory1 -> DiagnosticWithParameters1Renderer("{0}", TO_STRING)
else -> DefaultErrorMessages.getRendererForDiagnostic(diagnostic)
}
val diagnosticName = actualDiagnostic.name
if (renderer is AbstractDiagnosticWithParametersRenderer) {
val renderParameters = renderer.renderParameters(diagnostic)
val parameters = ContainerUtil.map(renderParameters, { it.toString() })
@@ -5,15 +5,21 @@
package org.jetbrains.kotlin.checkers.diagnostics.factories
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
interface DebugInfoDiagnosticFactory {
val withExplicitDefinitionOnly: Boolean
fun createDiagnostic(
expression: KtExpression,
bindingContext: BindingContext
bindingContext: BindingContext,
dataFlowValueFactory: DataFlowValueFactory?,
languageVersionSettings: LanguageVersionSettings?,
moduleDescriptor: ModuleDescriptorImpl?
): Diagnostic
}
@@ -7,12 +7,15 @@ package org.jetbrains.kotlin.checkers.diagnostics.factories
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.checkers.diagnostics.DebugInfoDiagnostic
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
import org.jetbrains.kotlin.diagnostics.PositioningStrategies
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
class DebugInfoDiagnosticFactory0 : DiagnosticFactory0<PsiElement>,
DebugInfoDiagnosticFactory {
@@ -21,7 +24,10 @@ class DebugInfoDiagnosticFactory0 : DiagnosticFactory0<PsiElement>,
override fun createDiagnostic(
expression: KtExpression,
bindingContext: BindingContext
bindingContext: BindingContext,
dataFlowValueFactory: DataFlowValueFactory?,
languageVersionSettings: LanguageVersionSettings?,
moduleDescriptor: ModuleDescriptorImpl?
): Diagnostic {
return DebugInfoDiagnostic(expression, this)
}
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.checkers.diagnostics.factories
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
import org.jetbrains.kotlin.diagnostics.PositioningStrategies
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
class DebugInfoDiagnosticFactory1 : DiagnosticFactory1<PsiElement, String>,
DebugInfoDiagnosticFactory {
private val name: String
override fun getName(): String {
return "DEBUG_INFO_$name"
}
override val withExplicitDefinitionOnly: Boolean
override fun createDiagnostic(
expression: KtExpression,
bindingContext: BindingContext,
dataFlowValueFactory: DataFlowValueFactory?,
languageVersionSettings: LanguageVersionSettings?,
moduleDescriptor: ModuleDescriptorImpl?
) = when (name) {
"EXPRESSION_TYPE" -> {
val (type, dataFlowTypes) = CheckerTestUtil.getTypeInfo(
expression,
bindingContext,
dataFlowValueFactory,
languageVersionSettings,
moduleDescriptor
)
this.on(expression, Renderers.renderExpressionType(type, dataFlowTypes))
}
else -> throw NotImplementedError("Creation diagnostic '$name' isn't supported.")
}
protected constructor(name: String, severity: Severity) : super(severity, PositioningStrategies.DEFAULT) {
this.name = name
this.withExplicitDefinitionOnly = false
}
protected constructor(name: String, severity: Severity, withExplicitDefinitionOnly: Boolean) : super(
severity,
PositioningStrategies.DEFAULT
) {
this.name = name
this.withExplicitDefinitionOnly = withExplicitDefinitionOnly
}
companion object {
val EXPRESSION_TYPE = create(
"EXPRESSION_TYPE",
Severity.INFO,
true
)
fun create(name: String, severity: Severity): DebugInfoDiagnosticFactory1 {
return DebugInfoDiagnosticFactory1(name, severity)
}
fun create(name: String, severity: Severity, withExplicitDefinitionOnly: Boolean): DebugInfoDiagnosticFactory1 {
return DebugInfoDiagnosticFactory1(name, severity, withExplicitDefinitionOnly)
}
}
}
@@ -15,10 +15,24 @@ import org.jetbrains.kotlin.checkers.*
import org.jetbrains.kotlin.checkers.diagnostics.*
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory0
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory1
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.AnalyzingUtils
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
import java.util.*
import java.util.regex.Pattern
@@ -41,7 +55,11 @@ object CheckerTestUtil {
root: PsiElement,
markDynamicCalls: Boolean,
dynamicCallDescriptors: MutableList<DeclarationDescriptor>,
withNewInference: Boolean
withNewInference: Boolean,
languageVersionSettings: LanguageVersionSettings,
dataFlowValueFactory: DataFlowValueFactory?,
moduleDescriptor: ModuleDescriptorImpl?,
diagnosedRanges: MutableMap<IntRange, MutableSet<String>>? = null
): List<ActualDiagnostic> {
val result = getDiagnosticsIncludingSyntaxErrors(
bindingContext,
@@ -49,7 +67,11 @@ object CheckerTestUtil {
markDynamicCalls,
dynamicCallDescriptors,
null,
withNewInference
withNewInference,
languageVersionSettings,
dataFlowValueFactory,
moduleDescriptor,
diagnosedRanges
)
val sortedBindings = implementingModulesBindings.sortedBy { it.first }
@@ -63,7 +85,11 @@ object CheckerTestUtil {
markDynamicCalls,
dynamicCallDescriptors,
(platform as MultiTargetPlatform.Specific).platform,
withNewInference
withNewInference,
languageVersionSettings,
dataFlowValueFactory,
moduleDescriptor,
diagnosedRanges
)
)
}
@@ -77,7 +103,11 @@ object CheckerTestUtil {
markDynamicCalls: Boolean,
dynamicCallDescriptors: MutableList<DeclarationDescriptor>,
platform: String?,
withNewInference: Boolean
withNewInference: Boolean,
languageVersionSettings: LanguageVersionSettings?,
dataFlowValueFactory: DataFlowValueFactory?,
moduleDescriptor: ModuleDescriptorImpl?,
diagnosedRanges: MutableMap<IntRange, MutableSet<String>>? = null
): MutableList<ActualDiagnostic> {
val diagnostics: MutableList<ActualDiagnostic> = mutableListOf()
@@ -98,7 +128,11 @@ object CheckerTestUtil {
markDynamicCalls,
dynamicCallDescriptors,
platform,
withNewInference
withNewInference,
languageVersionSettings,
dataFlowValueFactory,
moduleDescriptor,
diagnosedRanges
)
)
@@ -111,7 +145,11 @@ object CheckerTestUtil {
markDynamicCalls: Boolean,
dynamicCallDescriptors: MutableList<DeclarationDescriptor>,
platform: String?,
withNewInference: Boolean
withNewInference: Boolean,
languageVersionSettings: LanguageVersionSettings?,
dataFlowValueFactory: DataFlowValueFactory?,
moduleDescriptor: ModuleDescriptorImpl?,
diagnosedRanges: MutableMap<IntRange, MutableSet<String>>?
): List<ActualDiagnostic> {
val debugAnnotations = mutableListOf<ActualDiagnostic>()
@@ -131,6 +169,7 @@ object CheckerTestUtil {
//noinspection unchecked
val factoryList = listOf(
BindingContext.EXPRESSION_TYPE_INFO to DebugInfoDiagnosticFactory1.EXPRESSION_TYPE,
BindingContext.SMARTCAST to DebugInfoDiagnosticFactory0.SMARTCAST,
BindingContext.IMPLICIT_RECEIVER_SMARTCAST to DebugInfoDiagnosticFactory0.IMPLICIT_RECEIVER_SMARTCAST,
BindingContext.SMARTCAST_NULL to DebugInfoDiagnosticFactory0.CONSTANT,
@@ -140,10 +179,16 @@ object CheckerTestUtil {
for ((context, factory) in factoryList) {
for ((expression, _) in bindingContext.getSliceContents(context)) {
if (PsiTreeUtil.isAncestor(root, expression, false)) {
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
bindingContext,
dataFlowValueFactory,
languageVersionSettings,
moduleDescriptor
)
debugAnnotations.add(ActualDiagnostic(diagnostic, platform, withNewInference))
}
@@ -323,8 +368,11 @@ object CheckerTestUtil {
return if (iterator.hasNext()) iterator.next() else null
}
fun parseDiagnosedRanges(text: String, result: MutableList<DiagnosedRange>): String {
fun parseDiagnosedRanges(
text: String,
ranges: MutableList<DiagnosedRange>,
rangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>>? = null
): String {
val matcher = rangeStartOrEndPattern.matcher(text)
val opened = Stack<DiagnosedRange>()
var offsetCompensation = 0
@@ -340,7 +388,7 @@ object CheckerTestUtil {
while (diagnosticTypeMatcher.find())
range.addDiagnostic(diagnosticTypeMatcher.group())
opened.push(range)
result.add(range)
ranges.add(range)
}
offsetCompensation += matchedText.length
}
@@ -349,6 +397,14 @@ object CheckerTestUtil {
matcher.reset()
if (rangesToDiagnosticNames != null) {
ranges.forEach {
val range = it.start..it.end
rangesToDiagnosticNames.putIfAbsent(range, mutableSetOf())
rangesToDiagnosticNames[range]!! += it.getDiagnostics().map { it.name }
}
}
return matcher.replaceAll("")
}
@@ -549,4 +605,42 @@ object CheckerTestUtil {
ActualDiagnosticDescriptor(range.startOffset, range.endOffset, abstractDiagnostics)
}.toMutableList()
}
}
fun getTypeInfo(
expression: PsiElement,
bindingContext: BindingContext,
dataFlowValueFactory: DataFlowValueFactory?,
languageVersionSettings: LanguageVersionSettings?,
moduleDescriptor: ModuleDescriptorImpl?
): Pair<KotlinType?, Set<KotlinType>?> {
if (expression is KtCallableDeclaration) {
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, expression] as? CallableDescriptor
if (descriptor != null) {
return Pair(descriptor.returnType, null)
}
}
val expressionTypeInfo =
bindingContext[BindingContext.EXPRESSION_TYPE_INFO, expression as KtExpression] ?: noTypeInfo(DataFlowInfo.EMPTY)
val expressionType = expression.getType(bindingContext)
val result = expressionType ?: return Pair(null, null)
if (dataFlowValueFactory == null || moduleDescriptor == null)
return Pair(expressionType, null)
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, expressionType, bindingContext, moduleDescriptor)
val types = expressionTypeInfo.dataFlowInfo.getStableTypes(dataFlowValue, languageVersionSettings!!)
if (!types.isNullOrEmpty())
return Pair(result, types)
val smartCast = bindingContext[BindingContext.SMARTCAST, expression]
if (smartCast != null && expression is KtReferenceExpression) {
val declaredType = (bindingContext[BindingContext.REFERENCE_TARGET, expression] as? CallableDescriptor)?.returnType
if (declaredType != null) {
return Pair(result, setOf(declaredType))
}
}
return Pair(result, null)
}
}
@@ -40,7 +40,6 @@ public final class DiagnosticFactoryToRendererMap {
public String toString() {
return "DiagnosticFactory#" + name;
}
//
private void checkMutability() {
if (immutable) {
@@ -24,19 +24,19 @@ import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cfg.WhenMissingCase
import org.jetbrains.kotlin.cfg.hasUnknown
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.newTable
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.newText
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRenderer.Companion.DEBUG_TEXT
import org.jetbrains.kotlin.renderer.PropertyAccessorRenderingPolicy
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.MemberComparator
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.calls.inference.*
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.Bound
import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND
@@ -45,9 +45,11 @@ import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.Constrain
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.*
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.getValidityConstraintForConstituentType
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.getMultiTargetPlatform
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.io.PrintWriter
import java.io.StringWriter
@@ -679,6 +681,18 @@ object Renderers {
receiverAfterName = false
propertyAccessorRenderingPolicy = PropertyAccessorRenderingPolicy.PRETTY
}.asRenderer()
fun renderExpressionType(type: KotlinType?, dataFlowTypes: Set<KotlinType>?): String {
if (type == null)
return "Type is unknown"
if (dataFlowTypes == null)
return DEBUG_TEXT.renderType(type)
val typesAsString = dataFlowTypes.map { DEBUG_TEXT.renderType(it) }.toMutableSet().apply { add(DEBUG_TEXT.renderType(type)) }
return typesAsString.sorted().joinToString(separator = " & ")
}
}
fun DescriptorRenderer.asRenderer() = SmartDescriptorRenderer(this)
@@ -175,9 +175,15 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
if (platform is MultiTargetPlatform.Specific) platform to moduleBindings[testModule]!!
else null
}
val moduleDescriptor = modules[module]!!
ok = ok and testFile.getActualText(
moduleBindings[module]!!, implementingModulesBindings, actualText,
shouldSkipJvmSignatureDiagnostics(groupedByModule) || isCommonModule
moduleBindings[module]!!,
implementingModulesBindings,
actualText,
shouldSkipJvmSignatureDiagnostics(groupedByModule) || isCommonModule,
languageVersionSettingsByModule[module]!!,
moduleDescriptor
)
}
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.load.java.InternalFlexibleTypeTransformer
import org.jetbrains.kotlin.name.FqName
@@ -45,6 +46,7 @@ import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.utils.addIfNotNull
import org.junit.Assert
@@ -132,8 +134,9 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
textWithMarkers: String,
val directives: Map<String, String>
) {
private val diagnosedRanges: MutableList<DiagnosedRange> = ArrayList()
val actualDiagnostics: MutableList<ActualDiagnostic> = ArrayList()
private val diagnosedRanges: MutableList<DiagnosedRange> = mutableListOf()
private val diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>> = mutableMapOf()
val actualDiagnostics: MutableList<ActualDiagnostic> = mutableListOf()
val expectedText: String
val clearText: String
private val createKtFile: Lazy<KtFile?>
@@ -144,7 +147,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
val declareFlexibleType: Boolean
val checkLazyLog: Boolean
private val markDynamicCalls: Boolean
val dynamicCallDescriptors: MutableList<DeclarationDescriptor> = ArrayList()
val dynamicCallDescriptors: MutableList<DeclarationDescriptor> = mutableListOf()
val withNewInferenceDirective: Boolean
val newInferenceEnabled: Boolean
val renderDiagnosticMessages: Boolean
@@ -167,7 +170,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
this.expectedText = this.clearText
} else {
this.expectedText = textWithMarkers
this.clearText = CheckerTestUtil.parseDiagnosedRanges(addExtras(expectedText), diagnosedRanges)
this.clearText = CheckerTestUtil.parseDiagnosedRanges(addExtras(expectedText), diagnosedRanges, diagnosedRangesToDiagnosticNames)
this.createKtFile = lazy { TestCheckerUtil.createCheckAndReturnPsiFile(fileName, clearText, project) }
}
this.renderDiagnosticMessages = RENDER_DIAGNOSTICS_MESSAGES in directives
@@ -223,7 +226,9 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
bindingContext: BindingContext,
implementingModulesBindings: List<Pair<MultiTargetPlatform, BindingContext>>,
actualText: StringBuilder,
skipJvmSignatureDiagnostics: Boolean
skipJvmSignatureDiagnostics: Boolean,
languageVersionSettings: LanguageVersionSettings,
moduleDescriptor: ModuleDescriptorImpl
): Boolean {
val ktFile = this.ktFile
if (ktFile == null) {
@@ -242,21 +247,31 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
val ok = booleanArrayOf(true)
val withNewInference = newInferenceEnabled && withNewInferenceDirective && !USE_OLD_INFERENCE_DIAGNOSTICS_FOR_NI
val diagnostics = ContainerUtil.filter(
CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(
bindingContext, implementingModulesBindings, ktFile, markDynamicCalls, dynamicCallDescriptors, newInferenceEnabled
) + jvmSignatureDiagnostics,
val diagnostics = CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(
bindingContext,
implementingModulesBindings,
ktFile,
markDynamicCalls,
dynamicCallDescriptors,
newInferenceEnabled,
languageVersionSettings,
DataFlowValueFactoryImpl(languageVersionSettings),
moduleDescriptor,
this.diagnosedRangesToDiagnosticNames
)
val filteredDiagnostics = ContainerUtil.filter(
diagnostics + jvmSignatureDiagnostics,
{ whatDiagnosticsToConsider.value(it.diagnostic) }
)
actualDiagnostics.addAll(diagnostics)
actualDiagnostics.addAll(filteredDiagnostics)
val uncheckedDiagnostics = mutableListOf<PositionalTextDiagnostic>()
val inferenceCompatibilityOfTest = asInferenceCompatibility(withNewInference)
val invertedInferenceCompatibilityOfTest = asInferenceCompatibility(!withNewInference)
val diagnosticToExpectedDiagnostic =
CheckerTestUtil.diagnosticsDiff(diagnosedRanges, diagnostics, object : DiagnosticDiffCallbacks {
CheckerTestUtil.diagnosticsDiff(diagnosedRanges, filteredDiagnostics, object : DiagnosticDiffCallbacks {
override fun missingDiagnostic(diagnostic: TextDiagnostic, expectedStart: Int, expectedEnd: Int) {
if (withNewInferenceDirective && diagnostic.inferenceCompatibility != inferenceCompatibilityOfTest) {
updateUncheckedDiagnostics(diagnostic, expectedStart, expectedEnd)
@@ -307,7 +322,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
actualText.append(
CheckerTestUtil.addDiagnosticMarkersToText(
ktFile,
diagnostics,
filteredDiagnostics,
diagnosticToExpectedDiagnostic,
{ file -> file.text },
uncheckedDiagnostics,
@@ -33,6 +33,10 @@ private data class DiagnosticData(
private abstract class Test(private vararg val expectedMessages: String) {
fun test(psiFile: PsiFile, environment: KotlinCoreEnvironment) {
val bindingContext = JvmResolveUtil.analyze(psiFile as KtFile, environment).bindingContext
val emptyModule = KotlinTestUtils.createEmptyModule()
val container = createContainerForTests(environment.project, emptyModule)
val dataFlowValueFactory = container.dataFlowValueFactory
val languageVersionSettings = container.expressionTypingServices.languageVersionSettings
val expectedText = CheckerTestUtil.addDiagnosticMarkersToText(
psiFile,
CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(
@@ -40,12 +44,15 @@ private abstract class Test(private vararg val expectedMessages: String) {
false,
mutableListOf(),
null,
false
false,
languageVersionSettings,
dataFlowValueFactory,
emptyModule
)
).toString()
val diagnosedRanges = Lists.newArrayList<DiagnosedRange>()
CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges)
CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges, mutableMapOf())
val actualDiagnostics = CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(
bindingContext,
@@ -53,7 +60,10 @@ private abstract class Test(private vararg val expectedMessages: String) {
false,
mutableListOf(),
null,
false
false,
languageVersionSettings,
dataFlowValueFactory,
emptyModule
)
makeTestData(actualDiagnostics, diagnosedRanges)
@@ -367,7 +367,8 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
List<KtFile> ktFiles = new ArrayList<>(files.size());
for (TestFile file : files) {
if (file.name.endsWith(".kt")) {
String content = CheckerTestUtil.INSTANCE.parseDiagnosedRanges(file.content, new ArrayList<>(0));
// `rangesToDiagnosticNames` parameter is not-null only for diagnostic tests, it's using for lazy diagnostics
String content = CheckerTestUtil.INSTANCE.parseDiagnosedRanges(file.content, new ArrayList<>(0), null);
ktFiles.add(KotlinTestUtils.createFile(file.name, content, project));
}
}
@@ -101,7 +101,8 @@ public class CodegenTestFiles {
@NotNull
public static CodegenTestFiles create(@NotNull String fileName, @NotNull String contentWithDiagnosticMarkup, @NotNull Project project) {
String content = CheckerTestUtil.INSTANCE.parseDiagnosedRanges(contentWithDiagnosticMarkup, new ArrayList<>());
// `rangesToDiagnosticNames` parameter is not-null only for diagnostic tests, it's using for lazy diagnostics
String content = CheckerTestUtil.INSTANCE.parseDiagnosedRanges(contentWithDiagnosticMarkup, new ArrayList<>(), null);
KtFile file = KotlinTestUtils.createFile(fileName, content, project);
List<PsiErrorElement> ranges = AnalyzingUtils.getSyntaxErrorRanges(file);
assert ranges.isEmpty() : "Syntax errors found in " + file + ": " + ranges;
@@ -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.config.LanguageVersionSettings
import org.jetbrains.kotlin.idea.caches.resolve.*
import org.jetbrains.kotlin.psi.KtFile
import java.awt.*
@@ -34,13 +35,17 @@ class CopyAsDiagnosticTestAction : AnAction() {
val bindingContext = (psiFile as KtFile).analyzeWithContent()
// Parameters `languageVersionSettings`, `dataFlowValueFactory` and `moduleDescriptor` are not-null only for compiler diagnostic tests
val diagnostics = CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(
bindingContext,
psiFile,
false,
mutableListOf(),
null,
false
false,
null,
null,
null
)
val result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, diagnostics).toString()
@@ -102,7 +102,8 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
val ktFiles = ArrayList<KtFile>(files.size)
for (file in files.sorted()) {
if (file.name.endsWith(".kt")) {
val content = CheckerTestUtil.parseDiagnosedRanges(file.content, ArrayList(0))
// `rangesToDiagnosticNames` parameter is not-null only for diagnostic tests, it's using for lazy diagnostics
val content = CheckerTestUtil.parseDiagnosedRanges(file.content, ArrayList(0), null)
val tmpKtFile = File(tmpDir, file.name).apply { writeText(content) }
val virtualFile = StandardFileSystems.local().findFileByPath(tmpKtFile.path) ?: error("Can't find ${file.name}")
ktFiles.add(psiManager.findFile(virtualFile) as? KtFile ?: error("Can't load ${file.name}"))