Add lazy debug diagnostic DEBUG_INFO_EXPRESSION_TYPE
This commit is contained in:
@@ -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() })
|
||||
|
||||
+7
-1
@@ -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
-1
@@ -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)
|
||||
}
|
||||
|
||||
+79
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -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)
|
||||
|
||||
+8
-2
@@ -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()
|
||||
|
||||
|
||||
+2
-1
@@ -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}"))
|
||||
|
||||
Reference in New Issue
Block a user