FIR IDE: resolve constructors to correct CallInfo

This commit is contained in:
Ilya Kirillov
2020-06-08 22:10:37 +03:00
parent 87a65c0e4b
commit 8ac0466ec2
2 changed files with 58 additions and 14 deletions
@@ -5,23 +5,30 @@
package org.jetbrains.kotlin.idea.frontend.api
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtConstructor
import org.jetbrains.kotlin.psi.KtNamedFunction
sealed class CallInfo {
abstract val isSuspendCall: Boolean
abstract val targetFunction: PsiElement?
abstract val isJavaFunctionCall: Boolean
}
data class VariableAsFunctionCallInfo(val target: PsiElement, override val isSuspendCall: Boolean) : CallInfo() {
override val targetFunction: PsiElement? = null
override val isJavaFunctionCall: Boolean = false
}
data class VariableAsFunctionLikeCallInfo(val target: PsiElement, val invokeFunction: KtNamedFunction) : CallInfo() {
override val isSuspendCall: Boolean get() = invokeFunction.hasModifier(KtTokens.SUSPEND_KEYWORD)
override val targetFunction: PsiElement? get() = invokeFunction
override val isJavaFunctionCall: Boolean = false
}
// SimpleFunctionCallInfo
@@ -32,23 +39,44 @@ sealed class SimpleFunctionCallInfo : CallInfo() {
data class SimpleKtFunctionCallInfo(override val targetFunction: KtNamedFunction) : SimpleFunctionCallInfo() {
override val isSuspendCall: Boolean get() = targetFunction.hasModifier(KtTokens.SUSPEND_KEYWORD)
override val isJavaFunctionCall: Boolean = true
}
data class SimpleJavaFunctionCallInfo(override val targetFunction: PsiMethod) : SimpleFunctionCallInfo() {
override val isSuspendCall: Boolean = false
override val isJavaFunctionCall: Boolean = false
}
// ConstructorCallInfo
//TODO
object ConstructorCallInfo : CallInfo() {
// abstract val targetConstructor: PsiElement?
sealed class ConstructorCallInfo : CallInfo() {
final override val isSuspendCall: Boolean = false
override val targetFunction: PsiElement? = null
abstract val isPrimary: Boolean
}
//data class SimpleKtConstructorCallInfo(override val targetConstructor: KtConstructor<*>) : ConstructorCallInfo()
data class KtExplicitConstructorCallInfo(
override val targetFunction: KtConstructor<*>,
override val isPrimary: Boolean
) : ConstructorCallInfo() {
override val isJavaFunctionCall: Boolean = false
}
//data class SimpleJavaConstructorCallInfo(override val targetConstructor: PsiMethod) : ConstructorCallInfo()
data class KtImplicitPrimaryConstructorCallInfo(val owner: KtClass) : ConstructorCallInfo() {
override val targetFunction: PsiElement? = null
override val isJavaFunctionCall: Boolean = false
override val isPrimary: Boolean = true
}
data class JavaExplicitConstructorCallInfo(
override val targetFunction: PsiMethod,
override val isPrimary: Boolean
) : ConstructorCallInfo() {
override val isJavaFunctionCall: Boolean = true
}
data class JavaImplicitPrimaryConstructorCallInfo(val owner: PsiClass) : ConstructorCallInfo() {
override val targetFunction: PsiElement? = null
override val isJavaFunctionCall: Boolean = true
override val isPrimary: Boolean = true
}
@@ -6,19 +6,17 @@
package org.jetbrains.kotlin.idea.frontend.api.fir
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
@@ -111,18 +109,36 @@ class FirAnalysisSession(
override fun resolveCall(call: KtCallExpression): CallInfo? {
assertIsValid()
val firCall = call.getOrBuildFirSafe<FirFunctionCall>() ?: return null
val firCall = when (val fir = call.getOrBuildFir()) {
is FirFunctionCall -> fir
is FirSafeCallExpression -> fir.regularQualifiedAccess as? FirFunctionCall
else -> null
} ?: return null
return resolveCall(firCall, call)
}
private fun resolveCall(firCall: FirFunctionCall, callExpression: KtExpression): CallInfo? {
assertIsValid()
val session = callExpression.session
val resolvedFunctionPsi = firCall.calleeReference.toTargetPsi(session)
val resolvedCalleeSymbol = (firCall.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol
return when {
resolvedCalleeSymbol is FirConstructorSymbol -> {
ConstructorCallInfo//todo use proper constructor info
val fir = resolvedCalleeSymbol.fir
when (resolvedFunctionPsi) {
is KtClass -> KtImplicitPrimaryConstructorCallInfo(resolvedFunctionPsi)
is PsiClass -> JavaImplicitPrimaryConstructorCallInfo(resolvedFunctionPsi)
is KtConstructor<*> -> KtExplicitConstructorCallInfo(resolvedFunctionPsi, fir.isPrimary)
is PsiMethod -> JavaExplicitConstructorCallInfo(resolvedFunctionPsi, fir.isPrimary)
else -> {
val classId = resolvedCalleeSymbol.callableId.classId
val firClass = classId?.let(session.firSymbolProvider::getClassLikeSymbolByFqName)
when (val psiClass = firClass?.fir?.findPsi(callExpression.project)) {
is PsiClass -> JavaImplicitPrimaryConstructorCallInfo(psiClass)
is KtClass -> KtImplicitPrimaryConstructorCallInfo(psiClass)
else -> null
}
}
}
}
firCall.dispatchReceiver is FirQualifiedAccessExpression && firCall.isImplicitFunctionCall() -> {
val target = with(FirReferenceResolveHelper) {