AA: introduce eq checker to handle ambiguous PSI from binary module
This commit is contained in:
committed by
Ilya Kirillov
parent
3b63c1bf82
commit
ed92cc43c7
+15
-6
@@ -8,10 +8,12 @@ package org.jetbrains.kotlin.analysis.providers
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
|
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||||
|
import org.jetbrains.kotlin.analysis.providers.PsiDeclarationAndKtSymbolEqualityChecker.representsTheSameDeclaration
|
||||||
|
|
||||||
object DecompiledPsiDeclarationProvider {
|
object DecompiledPsiDeclarationProvider {
|
||||||
fun findPsi(ktSymbol: KtSymbol, project: Project): PsiElement? {
|
fun KtAnalysisSession.findPsi(ktSymbol: KtSymbol, project: Project): PsiElement? {
|
||||||
return when (ktSymbol) {
|
return when (ktSymbol) {
|
||||||
is KtConstructorSymbol -> providePsiForConstructor(ktSymbol, project)
|
is KtConstructorSymbol -> providePsiForConstructor(ktSymbol, project)
|
||||||
is KtFunctionLikeSymbol -> providePsiForFunction(ktSymbol, project)
|
is KtFunctionLikeSymbol -> providePsiForFunction(ktSymbol, project)
|
||||||
@@ -22,7 +24,7 @@ object DecompiledPsiDeclarationProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun providePsiForConstructor(
|
private fun KtAnalysisSession.providePsiForConstructor(
|
||||||
constructorSymbol: KtConstructorSymbol,
|
constructorSymbol: KtConstructorSymbol,
|
||||||
project: Project
|
project: Project
|
||||||
): PsiElement? {
|
): PsiElement? {
|
||||||
@@ -30,17 +32,24 @@ object DecompiledPsiDeclarationProvider {
|
|||||||
val psiClass = project.createPsiDeclarationProvider(constructorSymbol.scope(project))
|
val psiClass = project.createPsiDeclarationProvider(constructorSymbol.scope(project))
|
||||||
?.getClassesByClassId(classId)
|
?.getClassesByClassId(classId)
|
||||||
?.firstOrNull() ?: return null
|
?.firstOrNull() ?: return null
|
||||||
return psiClass.constructors.firstOrNull()
|
return psiClass.constructors.find { psiMethod ->
|
||||||
|
representsTheSameDeclaration(psiMethod, constructorSymbol)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun providePsiForFunction(
|
private fun KtAnalysisSession.providePsiForFunction(
|
||||||
functionLikeSymbol: KtFunctionLikeSymbol,
|
functionLikeSymbol: KtFunctionLikeSymbol,
|
||||||
project: Project
|
project: Project
|
||||||
): PsiElement? {
|
): PsiElement? {
|
||||||
return functionLikeSymbol.callableIdIfNonLocal?.let {
|
return functionLikeSymbol.callableIdIfNonLocal?.let {
|
||||||
project.createPsiDeclarationProvider(functionLikeSymbol.scope(project))
|
val candidates = project.createPsiDeclarationProvider(functionLikeSymbol.scope(project))
|
||||||
?.getFunctions(it)
|
?.getFunctions(it)
|
||||||
?.firstOrNull()
|
if (candidates?.size == 1)
|
||||||
|
candidates.single()
|
||||||
|
else
|
||||||
|
candidates?.find { psiMethod ->
|
||||||
|
representsTheSameDeclaration(psiMethod, functionLikeSymbol)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.analysis.providers
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
|
import com.intellij.psi.PsiType
|
||||||
|
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||||
|
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
|
||||||
|
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
|
||||||
|
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||||
|
|
||||||
|
// TODO replace with structural type comparison?
|
||||||
|
internal object PsiDeclarationAndKtSymbolEqualityChecker {
|
||||||
|
fun KtAnalysisSession.representsTheSameDeclaration(psi: PsiMethod, symbol: KtCallableSymbol): Boolean {
|
||||||
|
// TODO: receiver type comparison?
|
||||||
|
if (!returnTypesMatch(psi, symbol)) return false
|
||||||
|
if (!typeParametersMatch(psi, symbol)) return false
|
||||||
|
if (symbol is KtFunctionLikeSymbol && !valueParametersMatch(psi, symbol)) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtAnalysisSession.returnTypesMatch(psi: PsiMethod, symbol: KtCallableSymbol): Boolean {
|
||||||
|
if (symbol is KtConstructorSymbol) return true
|
||||||
|
return psi.returnType?.let { isTheSameTypes(psi, it, symbol.returnType, isVararg = false) }
|
||||||
|
?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun typeParametersMatch(psi: PsiMethod, symbol: KtCallableSymbol): Boolean {
|
||||||
|
if (psi.typeParameters.size != symbol.typeParameters.size) return false
|
||||||
|
psi.typeParameters.zip(symbol.typeParameters) { psiTypeParameter, typeParameterSymbol ->
|
||||||
|
if (psiTypeParameter.name != typeParameterSymbol.name.asString()) return false
|
||||||
|
// TODO: type parameter bounds comparison
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtAnalysisSession.valueParametersMatch(psi: PsiMethod, symbol: KtFunctionLikeSymbol): Boolean {
|
||||||
|
val valueParameterCount = if (symbol.isExtension) symbol.valueParameters.size + 1 else symbol.valueParameters.size
|
||||||
|
if (psi.parameterList.parametersCount != valueParameterCount) return false
|
||||||
|
if (symbol.isExtension) {
|
||||||
|
val psiParameter = psi.parameterList.parameters[0]
|
||||||
|
if (symbol.receiverType?.let { isTheSameTypes(psi, psiParameter.type, it, isVararg = false) } != true) return false
|
||||||
|
}
|
||||||
|
val offset = if (symbol.isExtension) 1 else 0
|
||||||
|
symbol.valueParameters.forEachIndexed { index, valueParameterSymbol ->
|
||||||
|
val psiParameter = psi.parameterList.parameters[index + offset]
|
||||||
|
if (valueParameterSymbol.name.asString() != psiParameter.name) return false
|
||||||
|
if (valueParameterSymbol.isVararg != psiParameter.isVarArgs) return false
|
||||||
|
if (!isTheSameTypes(psi, psiParameter.type, valueParameterSymbol.returnType, valueParameterSymbol.isVararg)) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtAnalysisSession.isTheSameTypes(
|
||||||
|
context: PsiMethod,
|
||||||
|
psi: PsiType,
|
||||||
|
ktType: KtType,
|
||||||
|
isVararg: Boolean = false
|
||||||
|
): Boolean {
|
||||||
|
// Shortcut: primitive void == Unit as a function return type
|
||||||
|
if (psi == PsiType.VOID && ktType.isUnit) return true
|
||||||
|
val ktTypeRendered = ktType.asPsiType(context) ?: return false
|
||||||
|
val rendered = if (isVararg) ktTypeRendered.createArrayType() else ktTypeRendered
|
||||||
|
return rendered == psi
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user