Analysis API: Return KtCallCandidateInfo instead of KtCallInfo in
KtCallResolver.collectAllCandidates().
This commit is contained in:
committed by
Ilya Kirillov
parent
b8cdfc5aad
commit
3f3873dc50
+6
-3
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test.components
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.calls.KtCallInfo
|
||||
import org.jetbrains.kotlin.analysis.api.calls.KtCallCandidateInfo
|
||||
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.expressionMarkerProvider
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleModuleTest
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -26,14 +26,17 @@ abstract class AbstractResolveCandidatesTest : AbstractHLApiSingleModuleTest() {
|
||||
if (candidates.isEmpty()) {
|
||||
"NO_CANDIDATES"
|
||||
} else {
|
||||
candidates.joinToString("\n\n") { stringRepresentation(it) }
|
||||
val sortedCandidates = candidates.sortedWith { candidate1, candidate2 ->
|
||||
compareCalls(candidate1.candidate, candidate2.candidate)
|
||||
}
|
||||
sortedCandidates.joinToString("\n\n") { stringRepresentation(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
testServices.assertions.assertEqualsToTestDataFileSibling(actual)
|
||||
}
|
||||
|
||||
private fun KtAnalysisSession.collectCallCandidates(element: PsiElement): List<KtCallInfo> = when (element) {
|
||||
private fun KtAnalysisSession.collectCallCandidates(element: PsiElement): List<KtCallCandidateInfo> = when (element) {
|
||||
is KtValueArgument -> this@collectCallCandidates.collectCallCandidates(element.getArgumentExpression()!!)
|
||||
is KtDeclarationModifierList -> {
|
||||
val annotationEntry = element.annotationEntries.singleOrNull()
|
||||
|
||||
+78
-82
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test.components
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.calls.KtCall
|
||||
import org.jetbrains.kotlin.analysis.api.calls.KtCallInfo
|
||||
import org.jetbrains.kotlin.analysis.api.calls.KtCallableMemberCall
|
||||
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnostic
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.KtMapBackedSubstitutor
|
||||
@@ -20,93 +19,90 @@ import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.KVisibility
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
internal fun KtAnalysisSession.stringRepresentation(call: KtCallInfo): String {
|
||||
fun Any.stringValue(): String {
|
||||
fun KtType.render() = asStringForDebugging().replace('/', '.')
|
||||
fun String.indented() = replace("\n", "\n ")
|
||||
return when (this) {
|
||||
is KtFunctionLikeSymbol -> buildString {
|
||||
append(
|
||||
when (this@stringValue) {
|
||||
is KtFunctionSymbol -> callableIdIfNonLocal ?: name
|
||||
is KtSamConstructorSymbol -> callableIdIfNonLocal ?: name
|
||||
is KtConstructorSymbol -> "<constructor>"
|
||||
is KtPropertyGetterSymbol -> callableIdIfNonLocal ?: "<getter>"
|
||||
is KtPropertySetterSymbol -> callableIdIfNonLocal ?: "<setter>"
|
||||
else -> error("unexpected symbol kind in KtCall: ${this@stringValue::class.java}")
|
||||
}
|
||||
)
|
||||
append("(")
|
||||
(this@stringValue as? KtFunctionSymbol)?.receiverType?.let { receiver ->
|
||||
append("<extension receiver>: ${receiver.render()}")
|
||||
if (valueParameters.isNotEmpty()) append(", ")
|
||||
internal fun KtAnalysisSession.stringRepresentation(any: Any): String = with(any) {
|
||||
fun KtType.render() = asStringForDebugging().replace('/', '.')
|
||||
fun String.indented() = replace("\n", "\n ")
|
||||
return when (this) {
|
||||
is KtFunctionLikeSymbol -> buildString {
|
||||
append(
|
||||
when (this@with) {
|
||||
is KtFunctionSymbol -> callableIdIfNonLocal ?: name
|
||||
is KtSamConstructorSymbol -> callableIdIfNonLocal ?: name
|
||||
is KtConstructorSymbol -> "<constructor>"
|
||||
is KtPropertyGetterSymbol -> callableIdIfNonLocal ?: "<getter>"
|
||||
is KtPropertySetterSymbol -> callableIdIfNonLocal ?: "<setter>"
|
||||
else -> error("unexpected symbol kind in KtCall: ${this@with::class.java}")
|
||||
}
|
||||
)
|
||||
append("(")
|
||||
(this@with as? KtFunctionSymbol)?.receiverType?.let { receiver ->
|
||||
append("<extension receiver>: ${receiver.render()}")
|
||||
if (valueParameters.isNotEmpty()) append(", ")
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
(this@stringValue as? KtCallableSymbol)?.getDispatchReceiverType()?.let { dispatchReceiverType ->
|
||||
append("<dispatch receiver>: ${dispatchReceiverType.render()}")
|
||||
if (valueParameters.isNotEmpty()) append(", ")
|
||||
}
|
||||
valueParameters.joinTo(this) { it.stringValue() }
|
||||
append(")")
|
||||
append(": ${returnType.render()}")
|
||||
@Suppress("DEPRECATION")
|
||||
(this@with as? KtCallableSymbol)?.getDispatchReceiverType()?.let { dispatchReceiverType ->
|
||||
append("<dispatch receiver>: ${dispatchReceiverType.render()}")
|
||||
if (valueParameters.isNotEmpty()) append(", ")
|
||||
}
|
||||
is KtValueParameterSymbol -> "${if (isVararg) "vararg " else ""}$name: ${returnType.render()}"
|
||||
is KtTypeParameterSymbol -> this.nameOrAnonymous.asString()
|
||||
is KtVariableSymbol -> "${if (isVal) "val" else "var"} $name: ${returnType.render()}"
|
||||
is KtSymbol -> DebugSymbolRenderer.render(this)
|
||||
is Boolean -> toString()
|
||||
is Map<*, *> -> if (isEmpty()) "{}" else entries.joinToString(
|
||||
separator = ",\n ",
|
||||
prefix = "{\n ",
|
||||
postfix = "\n}"
|
||||
) { (k, v) -> "${k?.stringValue()?.indented()} -> (${v?.stringValue()?.indented()})" }
|
||||
is Collection<*> -> if (isEmpty()) "[]" else joinToString(
|
||||
separator = ",\n ",
|
||||
prefix = "[\n ",
|
||||
postfix = "\n]"
|
||||
) {
|
||||
it?.stringValue()?.indented() ?: "null"
|
||||
}
|
||||
is PsiElement -> this.text
|
||||
is KtSubstitutor.Empty -> "<empty substitutor>"
|
||||
is KtMapBackedSubstitutor -> {
|
||||
val mappingText = getAsMap().entries
|
||||
.joinToString(prefix = "{", postfix = "}") { (k, v) -> k.stringValue() + " = " + v.asStringForDebugging() }
|
||||
"<map substitutor: $mappingText>"
|
||||
}
|
||||
is KtSubstitutor -> "<complex substitutor>"
|
||||
is KtDiagnostic -> "$severity<$factoryName: $defaultMessage>"
|
||||
is KtType -> render()
|
||||
is Enum<*> -> name
|
||||
is Name -> asString()
|
||||
else -> buildString {
|
||||
val clazz = this@stringValue::class
|
||||
val className = clazz.simpleName!!
|
||||
append(className)
|
||||
appendLine(":")
|
||||
clazz.memberProperties
|
||||
.filter { it.name != "token" && it.visibility == KVisibility.PUBLIC }
|
||||
.joinTo(this, separator = "\n ", prefix = " ") { property ->
|
||||
val name = property.name
|
||||
valueParameters.joinTo(this) { stringRepresentation(it) }
|
||||
append(")")
|
||||
append(": ${returnType.render()}")
|
||||
}
|
||||
is KtValueParameterSymbol -> "${if (isVararg) "vararg " else ""}$name: ${returnType.render()}"
|
||||
is KtTypeParameterSymbol -> this.nameOrAnonymous.asString()
|
||||
is KtVariableSymbol -> "${if (isVal) "val" else "var"} $name: ${returnType.render()}"
|
||||
is KtSymbol -> DebugSymbolRenderer.render(this)
|
||||
is Boolean -> toString()
|
||||
is Map<*, *> -> if (isEmpty()) "{}" else entries.joinToString(
|
||||
separator = ",\n ",
|
||||
prefix = "{\n ",
|
||||
postfix = "\n}"
|
||||
) { (k, v) -> "${k?.let { stringRepresentation(it).indented() }} -> (${v?.let { stringRepresentation(it).indented() }})" }
|
||||
is Collection<*> -> if (isEmpty()) "[]" else joinToString(
|
||||
separator = ",\n ",
|
||||
prefix = "[\n ",
|
||||
postfix = "\n]"
|
||||
) {
|
||||
it?.let { stringRepresentation(it).indented() } ?: "null"
|
||||
}
|
||||
is PsiElement -> this.text
|
||||
is KtSubstitutor.Empty -> "<empty substitutor>"
|
||||
is KtMapBackedSubstitutor -> {
|
||||
val mappingText = getAsMap().entries
|
||||
.joinToString(prefix = "{", postfix = "}") { (k, v) -> stringRepresentation(k) + " = " + v.asStringForDebugging() }
|
||||
"<map substitutor: $mappingText>"
|
||||
}
|
||||
is KtSubstitutor -> "<complex substitutor>"
|
||||
is KtDiagnostic -> "$severity<$factoryName: $defaultMessage>"
|
||||
is KtType -> render()
|
||||
is Enum<*> -> name
|
||||
is Name -> asString()
|
||||
else -> buildString {
|
||||
val clazz = this@with::class
|
||||
val className = clazz.simpleName!!
|
||||
append(className)
|
||||
appendLine(":")
|
||||
clazz.memberProperties
|
||||
.filter { it.name != "token" && it.visibility == KVisibility.PUBLIC }
|
||||
.joinTo(this, separator = "\n ", prefix = " ") { property ->
|
||||
val name = property.name
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val value = (property as KProperty1<Any, *>).get(this@stringValue)?.let {
|
||||
if (className == "KtErrorCallInfo" && name == "candidateCalls") {
|
||||
// The order of calls in KtErrorCallInfo.candidateCalls is non-deterministic. Sort by symbol string value.
|
||||
(it as Collection<KtCall>).sortedWith { call1, call2 ->
|
||||
if (call1 is KtCallableMemberCall<*, *> && call2 is KtCallableMemberCall<*, *>) {
|
||||
call1.partiallyAppliedSymbol.stringValue().compareTo(call2.partiallyAppliedSymbol.stringValue())
|
||||
} else 0
|
||||
}
|
||||
} else it
|
||||
}
|
||||
val valueAsString = value?.stringValue()?.indented()
|
||||
"$name = $valueAsString"
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val value = (property as KProperty1<Any, *>).get(this@with)?.let {
|
||||
if (className == "KtErrorCallInfo" && name == "candidateCalls") {
|
||||
(it as Collection<KtCall>).sortedWith { call1, call2 -> compareCalls(call1, call2) }
|
||||
} else it
|
||||
}
|
||||
}
|
||||
val valueAsString = value?.let { stringRepresentation(it).indented() }
|
||||
"$name = $valueAsString"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return call.stringValue()
|
||||
internal fun KtAnalysisSession.compareCalls(call1: KtCall, call2: KtCall): Int {
|
||||
// The order of candidate calls is non-deterministic. Sort by symbol string value.
|
||||
if (call1 !is KtCallableMemberCall<*, *> || call2 !is KtCallableMemberCall<*, *>) return 0
|
||||
return stringRepresentation(call1.partiallyAppliedSymbol).compareTo(stringRepresentation(call2.partiallyAppliedSymbol))
|
||||
}
|
||||
Reference in New Issue
Block a user