FIR IDE: get type of unresovled super

FIR does not provide any type for unresolved super so we manually
synthesize such types for completion to work.
This commit is contained in:
Tianyu Geng
2021-10-11 13:38:11 -07:00
committed by Ilya Kirillov
parent a487e91124
commit c10879be43
10 changed files with 103 additions and 15 deletions
@@ -6,21 +6,6 @@
package org.jetbrains.kotlin.analysis.api.fir.components
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirLabel
import org.jetbrains.kotlin.fir.FirPackageDirective
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.constructFunctionalType
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.components.KtExpressionTypeProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.utils.getReferencedElementType
@@ -29,6 +14,26 @@ import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.fir.FirLabel
import org.jetbrains.kotlin.fir.FirPackageDirective
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.resolve.constructFunctionalType
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.ConeIntersectionType
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -39,6 +44,21 @@ internal class KtFirExpressionTypeProvider(
override fun getKtExpressionType(expression: KtExpression): KtType? = withValidityAssertion {
when (val fir = expression.unwrap().getOrBuildFir(firResolveState)) {
is FirPropertyAccessExpression -> {
// For unresolved `super`, we manually create an intersection type so that IDE features like completion can work correctly.
val containingClass =
(fir.dispatchReceiver as? FirThisReceiverExpression)?.calleeReference?.boundSymbol as? FirClassSymbol<*>
if (fir.calleeReference is FirSuperReference && fir.typeRef is FirErrorTypeRef && containingClass != null) {
val superTypes = containingClass.superConeTypes
when (superTypes.size) {
0 -> analysisSession.builtinTypes.ANY
1 -> superTypes.single().asKtType()
else -> ConeIntersectionType(superTypes).asKtType()
}
} else {
fir.typeRef.coneType.asKtType()
}
}
is FirExpression -> fir.typeRef.coneType.asKtType()
is FirNamedReference -> fir.getReferencedElementType(firResolveState).asKtType()
is FirStatement -> with(analysisSession) { builtinTypes.UNIT }
@@ -90,6 +90,12 @@ public class HLExpressionTypeTestGenerated extends AbstractHLExpressionTypeTest
runTest("analysis/analysis-api/testData/components/expressionType/property.kt");
}
@Test
@TestMetadata("resolvedSuper.kt")
public void testResolvedSuper() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionType/resolvedSuper.kt");
}
@Test
@TestMetadata("returnExpression.kt")
public void testReturnExpression() throws Exception {
@@ -102,6 +108,24 @@ public class HLExpressionTypeTestGenerated extends AbstractHLExpressionTypeTest
runTest("analysis/analysis-api/testData/components/expressionType/stringLiteral.kt");
}
@Test
@TestMetadata("unresolvedSuper_multipleSuperTypes.kt")
public void testUnresolvedSuper_multipleSuperTypes() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionType/unresolvedSuper_multipleSuperTypes.kt");
}
@Test
@TestMetadata("unresolvedSuper_noSuperType.kt")
public void testUnresolvedSuper_noSuperType() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionType/unresolvedSuper_noSuperType.kt");
}
@Test
@TestMetadata("unresolvedSuper_singleSuperType.kt")
public void testUnresolvedSuper_singleSuperType() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionType/unresolvedSuper_singleSuperType.kt");
}
@Test
@TestMetadata("whileExpression.kt")
public void testWhileExpression() throws Exception {
@@ -0,0 +1,9 @@
interface A {
fun foo() {}
}
class B : A {
fun test() {
<expr>super</expr>.foo()
}
}
@@ -0,0 +1,2 @@
expression: super
type: A
@@ -0,0 +1,13 @@
interface A {
fun foo() {}
}
interface B {
fun bar() {}
}
class C : A, B {
fun test() {
<expr>super</expr>.unresolved()
}
}
@@ -0,0 +1,2 @@
expression: super
type: (A&B)
@@ -0,0 +1,5 @@
class Foo {
fun test() {
<expr>super</expr>.unresolved()
}
}
@@ -0,0 +1,2 @@
expression: super
type: kotlin.Any
@@ -0,0 +1,9 @@
interface A {
fun foo() {}
}
class B : A {
fun test() {
<expr>super</expr>.unresolved()
}
}
@@ -0,0 +1,2 @@
expression: super
type: A