FE1.0 Analysis API: get smartcast if available with getKtExpressionType
The current implementation still does not work with multicast. In addition, it appears FE1.0 does not attempt smart cast if it's not used.
This commit is contained in:
+8
-1
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.MultipleSmartCasts
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SingleSmartCast
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getParameterForArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getType
|
||||
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.resolve.sam.SamConstructorDescriptor
|
||||
import org.jetbrains.kotlin.resolve.sam.getFunctionTypeForAbstractMethod
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
|
||||
class KtFe10ExpressionTypeProvider(
|
||||
@@ -54,7 +56,12 @@ class KtFe10ExpressionTypeProvider(
|
||||
}
|
||||
|
||||
val bindingContext = analysisContext.analyze(unwrapped, AnalysisMode.PARTIAL)
|
||||
val kotlinType = expression.getType(bindingContext) ?: analysisContext.builtIns.unitType
|
||||
val smartCastType = when (val smartCastType = bindingContext[BindingContext.SMARTCAST, expression]) {
|
||||
is SingleSmartCast -> smartCastType.type
|
||||
is MultipleSmartCasts -> intersectWrappedTypes(smartCastType.map.values)
|
||||
else -> null
|
||||
}
|
||||
val kotlinType = smartCastType ?: expression.getType(bindingContext) ?: analysisContext.builtIns.unitType
|
||||
return kotlinType.toKtType(analysisContext)
|
||||
}
|
||||
|
||||
|
||||
+24
@@ -156,6 +156,30 @@ public class KtFe10HLExpressionTypeTestGenerated extends AbstractKtFe10HLExpress
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/returnExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartcast_asCallArg.kt")
|
||||
public void testSmartcast_asCallArg() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartcast_asReceiver.kt")
|
||||
public void testSmartcast_asReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartcast_multi.kt")
|
||||
public void testSmartcast_multi() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartcast_unused.kt")
|
||||
public void testSmartcast_unused() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("stringLiteral.kt")
|
||||
public void testStringLiteral() throws Exception {
|
||||
|
||||
+24
@@ -156,6 +156,30 @@ public class FirHLExpressionTypeTestGenerated extends AbstractFirHLExpressionTyp
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/returnExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartcast_asCallArg.kt")
|
||||
public void testSmartcast_asCallArg() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asCallArg.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartcast_asReceiver.kt")
|
||||
public void testSmartcast_asReceiver() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_asReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartcast_multi.kt")
|
||||
public void testSmartcast_multi() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_multi.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartcast_unused.kt")
|
||||
public void testSmartcast_unused() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("stringLiteral.kt")
|
||||
public void testStringLiteral() throws Exception {
|
||||
|
||||
+7
-1
@@ -10,13 +10,19 @@ import org.jetbrains.kotlin.analysis.api.impl.barebone.test.expressionMarkerProv
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleFileTest
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.assertions
|
||||
|
||||
abstract class AbstractHLExpressionTypeTest(configurator: FrontendApiTestConfiguratorService) : AbstractHLApiSingleFileTest(configurator) {
|
||||
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
|
||||
val expression = testServices.expressionMarkerProvider.getSelectedElement(ktFile) as KtExpression
|
||||
val selected = testServices.expressionMarkerProvider.getSelectedElement(ktFile)
|
||||
val expression = when (selected) {
|
||||
is KtExpression -> selected
|
||||
is KtValueArgument -> selected.getArgumentExpression()
|
||||
else -> null
|
||||
} ?: error("expect an expression but got ${selected.text}")
|
||||
val type = executeOnPooledThreadInReadAction {
|
||||
analyseForTest(expression) { expression.getKtType()?.render() }
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fun test(a: Any) {
|
||||
if (a is String) {
|
||||
takeString(<expr>a</expr>)
|
||||
}
|
||||
}
|
||||
|
||||
fun takeString(s: String) {}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
expression: a
|
||||
type: kotlin.String
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
fun test(a: Any) {
|
||||
if (a is String) {
|
||||
<expr>a</expr>.length
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
expression: a
|
||||
type: kotlin.String
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
expression: a
|
||||
type: kotlin.Any
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
interface A
|
||||
interface B
|
||||
|
||||
fun <T> T.take() where T: A, T: B {}
|
||||
|
||||
fun test(a: Any) {
|
||||
if (a is A && a is B) {
|
||||
<expr>a</expr>.take()
|
||||
}
|
||||
}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
expression: a
|
||||
type: (A&B)
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
expression: a
|
||||
type: kotlin.Any
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
fun test(a: Any) {
|
||||
if (a is String) {
|
||||
<expr>a</expr>
|
||||
}
|
||||
}
|
||||
analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/smartcast_unused.txt
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
expression: a
|
||||
type: kotlin.String
|
||||
Reference in New Issue
Block a user