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 package org.jetbrains.kotlin.idea.frontend.api
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.lexer.KtTokens 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 import org.jetbrains.kotlin.psi.KtNamedFunction
sealed class CallInfo { sealed class CallInfo {
abstract val isSuspendCall: Boolean abstract val isSuspendCall: Boolean
abstract val targetFunction: PsiElement? abstract val targetFunction: PsiElement?
abstract val isJavaFunctionCall: Boolean
} }
data class VariableAsFunctionCallInfo(val target: PsiElement, override val isSuspendCall: Boolean) : CallInfo() { data class VariableAsFunctionCallInfo(val target: PsiElement, override val isSuspendCall: Boolean) : CallInfo() {
override val targetFunction: PsiElement? = null override val targetFunction: PsiElement? = null
override val isJavaFunctionCall: Boolean = false
} }
data class VariableAsFunctionLikeCallInfo(val target: PsiElement, val invokeFunction: KtNamedFunction) : CallInfo() { data class VariableAsFunctionLikeCallInfo(val target: PsiElement, val invokeFunction: KtNamedFunction) : CallInfo() {
override val isSuspendCall: Boolean get() = invokeFunction.hasModifier(KtTokens.SUSPEND_KEYWORD) override val isSuspendCall: Boolean get() = invokeFunction.hasModifier(KtTokens.SUSPEND_KEYWORD)
override val targetFunction: PsiElement? get() = invokeFunction override val targetFunction: PsiElement? get() = invokeFunction
override val isJavaFunctionCall: Boolean = false
} }
// SimpleFunctionCallInfo // SimpleFunctionCallInfo
@@ -32,23 +39,44 @@ sealed class SimpleFunctionCallInfo : CallInfo() {
data class SimpleKtFunctionCallInfo(override val targetFunction: KtNamedFunction) : SimpleFunctionCallInfo() { data class SimpleKtFunctionCallInfo(override val targetFunction: KtNamedFunction) : SimpleFunctionCallInfo() {
override val isSuspendCall: Boolean get() = targetFunction.hasModifier(KtTokens.SUSPEND_KEYWORD) override val isSuspendCall: Boolean get() = targetFunction.hasModifier(KtTokens.SUSPEND_KEYWORD)
override val isJavaFunctionCall: Boolean = true
} }
data class SimpleJavaFunctionCallInfo(override val targetFunction: PsiMethod) : SimpleFunctionCallInfo() { data class SimpleJavaFunctionCallInfo(override val targetFunction: PsiMethod) : SimpleFunctionCallInfo() {
override val isSuspendCall: Boolean = false override val isSuspendCall: Boolean = false
override val isJavaFunctionCall: Boolean = false
} }
// ConstructorCallInfo // ConstructorCallInfo
//TODO sealed class ConstructorCallInfo : CallInfo() {
object ConstructorCallInfo : CallInfo() {
// abstract val targetConstructor: PsiElement?
final override val isSuspendCall: Boolean = false 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 package org.jetbrains.kotlin.idea.frontend.api.fir
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField import com.intellij.psi.PsiField
import com.intellij.psi.PsiMethod import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.*
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.references.FirResolvedNamedReference 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.resolve.transformers.firClassLike
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
@@ -111,18 +109,36 @@ class FirAnalysisSession(
override fun resolveCall(call: KtCallExpression): CallInfo? { override fun resolveCall(call: KtCallExpression): CallInfo? {
assertIsValid() 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) return resolveCall(firCall, call)
} }
private fun resolveCall(firCall: FirFunctionCall, callExpression: KtExpression): CallInfo? { private fun resolveCall(firCall: FirFunctionCall, callExpression: KtExpression): CallInfo? {
assertIsValid()
val session = callExpression.session val session = callExpression.session
val resolvedFunctionPsi = firCall.calleeReference.toTargetPsi(session) val resolvedFunctionPsi = firCall.calleeReference.toTargetPsi(session)
val resolvedCalleeSymbol = (firCall.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol val resolvedCalleeSymbol = (firCall.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol
return when { return when {
resolvedCalleeSymbol is FirConstructorSymbol -> { 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() -> { firCall.dispatchReceiver is FirQualifiedAccessExpression && firCall.isImplicitFunctionCall() -> {
val target = with(FirReferenceResolveHelper) { val target = with(FirReferenceResolveHelper) {