diff --git a/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/TextDiagnostic.kt b/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/TextDiagnostic.kt index c4e0cb96434..b1b4ff913cb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/TextDiagnostic.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/TextDiagnostic.kt @@ -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() }) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory.kt index dd78088ae71..d89b4b9123c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory.kt @@ -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 } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory0.kt b/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory0.kt index 1aa39893fa1..c17cd5967a2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory0.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory0.kt @@ -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, DebugInfoDiagnosticFactory { @@ -21,7 +24,10 @@ class DebugInfoDiagnosticFactory0 : DiagnosticFactory0, override fun createDiagnostic( expression: KtExpression, - bindingContext: BindingContext + bindingContext: BindingContext, + dataFlowValueFactory: DataFlowValueFactory?, + languageVersionSettings: LanguageVersionSettings?, + moduleDescriptor: ModuleDescriptorImpl? ): Diagnostic { return DebugInfoDiagnostic(expression, this) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory1.kt b/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory1.kt new file mode 100644 index 00000000000..c0e9b81ab35 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/checkers/diagnostics/factories/DebugInfoDiagnosticFactory1.kt @@ -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, + 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) + } + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/checkers/utils/CheckerTestUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/checkers/utils/CheckerTestUtil.kt index 04878f811d5..9952ab5f3a1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/checkers/utils/CheckerTestUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/checkers/utils/CheckerTestUtil.kt @@ -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, - withNewInference: Boolean + withNewInference: Boolean, + languageVersionSettings: LanguageVersionSettings, + dataFlowValueFactory: DataFlowValueFactory?, + moduleDescriptor: ModuleDescriptorImpl?, + diagnosedRanges: MutableMap>? = null ): List { 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, platform: String?, - withNewInference: Boolean + withNewInference: Boolean, + languageVersionSettings: LanguageVersionSettings?, + dataFlowValueFactory: DataFlowValueFactory?, + moduleDescriptor: ModuleDescriptorImpl?, + diagnosedRanges: MutableMap>? = null ): MutableList { val diagnostics: MutableList = 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, platform: String?, - withNewInference: Boolean + withNewInference: Boolean, + languageVersionSettings: LanguageVersionSettings?, + dataFlowValueFactory: DataFlowValueFactory?, + moduleDescriptor: ModuleDescriptorImpl?, + diagnosedRanges: MutableMap>? ): List { val debugAnnotations = mutableListOf() @@ -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): String { + fun parseDiagnosedRanges( + text: String, + ranges: MutableList, + rangesToDiagnosticNames: MutableMap>? = null + ): String { val matcher = rangeStartOrEndPattern.matcher(text) val opened = Stack() 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() } -} \ No newline at end of file + + fun getTypeInfo( + expression: PsiElement, + bindingContext: BindingContext, + dataFlowValueFactory: DataFlowValueFactory?, + languageVersionSettings: LanguageVersionSettings?, + moduleDescriptor: ModuleDescriptorImpl? + ): Pair?> { + 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) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DiagnosticFactoryToRendererMap.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DiagnosticFactoryToRendererMap.java index c8ec0d03734..91a71daada5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DiagnosticFactoryToRendererMap.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DiagnosticFactoryToRendererMap.java @@ -40,7 +40,6 @@ public final class DiagnosticFactoryToRendererMap { public String toString() { return "DiagnosticFactory#" + name; } - // private void checkMutability() { if (immutable) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt index 258e4c58a18..7b5103e9c02 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt @@ -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?): 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) diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt index 1497bcd3346..c1452d01ef1 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt @@ -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 ) } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt index a7857efa552..b55e6d294f7 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt @@ -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 ) { - private val diagnosedRanges: MutableList = ArrayList() - val actualDiagnostics: MutableList = ArrayList() + private val diagnosedRanges: MutableList = mutableListOf() + private val diagnosedRangesToDiagnosticNames: MutableMap> = mutableMapOf() + val actualDiagnostics: MutableList = mutableListOf() val expectedText: String val clearText: String private val createKtFile: Lazy @@ -144,7 +147,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava = ArrayList() + val dynamicCallDescriptors: MutableList = mutableListOf() val withNewInferenceDirective: Boolean val newInferenceEnabled: Boolean val renderDiagnosticMessages: Boolean @@ -167,7 +170,7 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava>, 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() 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 file.text }, uncheckedDiagnostics, diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CheckerTestUtilTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CheckerTestUtilTest.kt index 6bd8d980757..d86bd673f53 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CheckerTestUtilTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CheckerTestUtilTest.kt @@ -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() - 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) diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestCase.java b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestCase.java index 60be6272a13..ce77594f4de 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestCase.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestCase.java @@ -367,7 +367,8 @@ public abstract class CodegenTestCase extends KtUsefulTestCase { List 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)); } } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestFiles.java b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestFiles.java index 6f2813e937f..7be39816419 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestFiles.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestFiles.java @@ -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 ranges = AnalyzingUtils.getSyntaxErrorRanges(file); assert ranges.isEmpty() : "Syntax errors found in " + file + ": " + ranges; diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/internal/CopyAsDiagnosticTestAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/internal/CopyAsDiagnosticTestAction.kt index 5a75f1c923d..e96c6966463 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/internal/CopyAsDiagnosticTestAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/internal/CopyAsDiagnosticTestAction.kt @@ -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() diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt index 9e1b9768242..3c6ba656c32 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -102,7 +102,8 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() { val ktFiles = ArrayList(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}"))