From 017448e3591b644cf389f59e0b5527e83cf69356 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 9 Aug 2021 11:18:03 +0200 Subject: [PATCH] FIR IDE: make KtExpression.getKtType() to return null for non-expressions --- .../api/components/KtExpressionTypeProvider.kt | 12 ++++++++++-- .../fir/components/KtFirExpressionTypeProvider.kt | 9 +++++++-- .../components/expressionType/nonExpression.kt | 1 + .../components/expressionType/nonExpression.txt | 2 ++ .../api/components/AbstractHLExpressionTypeTest.kt | 2 +- .../components/HLExpressionTypeTestGenerated.java | 6 ++++++ 6 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 idea/idea-frontend-fir/testData/components/expressionType/nonExpression.kt create mode 100644 idea/idea-frontend-fir/testData/components/expressionType/nonExpression.txt diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtExpressionTypeProvider.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtExpressionTypeProvider.kt index acf9b2aa252..ab81add3282 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtExpressionTypeProvider.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtExpressionTypeProvider.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFunction public abstract class KtExpressionTypeProvider : KtAnalysisSessionComponent() { - public abstract fun getKtExpressionType(expression: KtExpression): KtType + public abstract fun getKtExpressionType(expression: KtExpression): KtType? public abstract fun getReturnTypeForKtDeclaration(declaration: KtDeclaration): KtType public abstract fun getFunctionalTypeForKtFunction(declaration: KtFunction): KtType @@ -22,7 +22,15 @@ public abstract class KtExpressionTypeProvider : KtAnalysisSessionComponent() { } public interface KtExpressionTypeProviderMixIn : KtAnalysisSessionMixIn { - public fun KtExpression.getKtType(): KtType = + /** + * Get type of given expression. + * + * Return: + * - [KtExpression] type if given [KtExpression] is real expression; + * - `null` for [KtExpression] inside pacakges and import declarations; + * - `Unit` type for statements; + */ + public fun KtExpression.getKtType(): KtType? = analysisSession.expressionTypeProvider.getKtExpressionType(this) /** diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirExpressionTypeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirExpressionTypeProvider.kt index 43b049756aa..3bf85967177 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirExpressionTypeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirExpressionTypeProvider.kt @@ -6,14 +6,18 @@ package org.jetbrains.kotlin.idea.frontend.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.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirFunction +import org.jetbrains.kotlin.fir.declarations.FirImport 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.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.idea.fir.low.level.api.api.getOrBuildFir import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirOfType @@ -34,12 +38,13 @@ internal class KtFirExpressionTypeProvider( override val token: ValidityToken, ) : KtExpressionTypeProvider(), KtFirAnalysisSessionComponent { - override fun getKtExpressionType(expression: KtExpression): KtType = withValidityAssertion { + override fun getKtExpressionType(expression: KtExpression): KtType? = withValidityAssertion { when (val fir = expression.unwrap().getOrBuildFir(firResolveState)) { is FirExpression -> fir.typeRef.coneType.asKtType() is FirNamedReference -> fir.getReferencedElementType().asKtType() is FirStatement -> with(analysisSession) { builtinTypes.UNIT } - else -> error("Unexpected ${fir?.let { it::class }}") + is FirTypeRef, is FirImport, is FirPackageDirective, is FirLabel -> null + else -> error("Unexpected ${fir?.let { it::class }} for ${expression::class} with text `${expression.text}`") } } diff --git a/idea/idea-frontend-fir/testData/components/expressionType/nonExpression.kt b/idea/idea-frontend-fir/testData/components/expressionType/nonExpression.kt new file mode 100644 index 00000000000..eb530a7e28b --- /dev/null +++ b/idea/idea-frontend-fir/testData/components/expressionType/nonExpression.kt @@ -0,0 +1 @@ +import java.util.ArrayList \ No newline at end of file diff --git a/idea/idea-frontend-fir/testData/components/expressionType/nonExpression.txt b/idea/idea-frontend-fir/testData/components/expressionType/nonExpression.txt new file mode 100644 index 00000000000..7c4442f6688 --- /dev/null +++ b/idea/idea-frontend-fir/testData/components/expressionType/nonExpression.txt @@ -0,0 +1,2 @@ +expression: util +type: null diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/AbstractHLExpressionTypeTest.kt b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/AbstractHLExpressionTypeTest.kt index 47a1cd20c39..7a02b7d2899 100644 --- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/AbstractHLExpressionTypeTest.kt +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/AbstractHLExpressionTypeTest.kt @@ -21,7 +21,7 @@ abstract class AbstractHLExpressionTypeTest : AbstractHLApiSingleFileTest() { override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) { val expression = testServices.expressionMarkerProvider.getSelectedElement(ktFile) as KtExpression val type = executeOnPooledThreadInReadAction { - analyse(expression) { expression.getKtType().render() } + analyse(expression) { expression.getKtType()?.render() } } val actual = buildString { appendLine("expression: ${expression.text}") diff --git a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/HLExpressionTypeTestGenerated.java b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/HLExpressionTypeTestGenerated.java index 9d87769129d..1a506407477 100644 --- a/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/HLExpressionTypeTestGenerated.java +++ b/idea/idea-frontend-fir/tests/org/jetbrains/kotlin/idea/fir/frontend/api/components/HLExpressionTypeTestGenerated.java @@ -78,6 +78,12 @@ public class HLExpressionTypeTestGenerated extends AbstractHLExpressionTypeTest runTest("idea/idea-frontend-fir/testData/components/expressionType/intLiteral.kt"); } + @Test + @TestMetadata("nonExpression.kt") + public void testNonExpression() throws Exception { + runTest("idea/idea-frontend-fir/testData/components/expressionType/nonExpression.kt"); + } + @Test @TestMetadata("property.kt") public void testProperty() throws Exception {