[Analysis API] Handle missed cases in PsiElement.getExpectedType()

^KTIJ-24256
This commit is contained in:
aleksandrina-streltsova
2023-01-19 21:48:30 +02:00
committed by teamcity
parent 7dd438cb9e
commit 3d0bca5ca1
70 changed files with 1112 additions and 72 deletions
@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.analysis.api.descriptors.components
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.components.KtExpressionTypeProvider
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade.AnalysisMode
import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession
import org.jetbrains.kotlin.analysis.api.descriptors.components.base.Fe10KtAnalysisSessionComponent
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtType
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.types.KtErrorType
import org.jetbrains.kotlin.analysis.api.types.KtFunctionalType
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
@@ -28,6 +31,7 @@ import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.util.getType
import org.jetbrains.kotlin.resolve.sam.SamConstructorDescriptor
import org.jetbrains.kotlin.resolve.sam.getFunctionTypeForAbstractMethod
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
import org.jetbrains.kotlin.types.error.ErrorTypeKind
@@ -181,44 +185,83 @@ class KtFe10ExpressionTypeProvider(
}
}
if (parentExpression is KtCallableDeclaration) {
if (expression is KtBlockExpression) {
return null
when (parentExpression) {
is KtCallableDeclaration -> {
if (expression is KtBlockExpression) {
return null
}
val bindingContext = analysisContext.analyze(parentExpression)
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, parentExpression]
if (descriptor is CallableDescriptor) {
return descriptor.returnType?.toKtNonErrorType(analysisContext)
}
}
val bindingContext = analysisContext.analyze(parentExpression)
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, parentExpression]
if (descriptor is CallableDescriptor) {
return descriptor.returnType?.toKtType(analysisContext)
}
} else if (parentExpression is KtBinaryExpressionWithTypeRHS && KtPsiUtil.isCast(parentExpression)) {
val typeReference = parentExpression.right
if (typeReference != null) {
val bindingContext = analysisContext.analyze(typeReference)
var kotlinType = bindingContext[BindingContext.TYPE, typeReference]
if (kotlinType != null && KtPsiUtil.isSafeCast(parentExpression)) {
kotlinType = kotlinType.makeNullable()
is KtBinaryExpressionWithTypeRHS -> {
val typeReference = parentExpression.right
if (KtPsiUtil.isCast(parentExpression) && typeReference != null) {
val bindingContext = analysisContext.analyze(typeReference)
var kotlinType = bindingContext[BindingContext.TYPE, typeReference]
if (kotlinType != null && KtPsiUtil.isSafeCast(parentExpression)) {
kotlinType = kotlinType.makeNullable()
}
return kotlinType?.toKtNonErrorType(analysisContext)
}
return kotlinType?.toKtType(analysisContext)
}
} else if (parentExpression is KtValueArgument) {
val callExpression = getContainingCallExpression(parentExpression)
if (callExpression != null) {
val bindingContext = analysisContext.analyze(callExpression)
val resolvedCall = callExpression.getResolvedCall(bindingContext)
if (resolvedCall != null) {
val parameterDescriptor = resolvedCall.getParameterForArgument(parentExpression)?.original
if (parameterDescriptor != null) {
val kotlinType = when (val originalCallableDescriptor = parameterDescriptor.containingDeclaration) {
is SamConstructorDescriptor -> originalCallableDescriptor.returnTypeOrNothing
else -> {
if (parameterDescriptor.isVararg)
parameterDescriptor.varargElementType
else
parameterDescriptor.type
is KtValueArgument -> {
val callExpression = getContainingCallExpression(parentExpression)
if (callExpression != null) {
val bindingContext = analysisContext.analyze(callExpression)
val resolvedCall = callExpression.getResolvedCall(bindingContext)
if (resolvedCall != null) {
val parameterDescriptor = resolvedCall.getParameterForArgument(parentExpression)?.original
if (parameterDescriptor != null) {
val kotlinType = when (val originalCallableDescriptor = parameterDescriptor.containingDeclaration) {
is SamConstructorDescriptor -> originalCallableDescriptor.returnTypeOrNothing
else -> {
if (parameterDescriptor.isVararg)
parameterDescriptor.varargElementType
else
parameterDescriptor.type
}
}
return kotlinType?.toKtNonErrorType(analysisContext)
}
return kotlinType?.toKtType(analysisContext)
}
}
}
is KtWhenConditionWithExpression -> {
val whenExpression = (parentExpression.parent as? KtWhenEntry)?.parent as? KtWhenExpression
if (whenExpression != null) {
val subject = whenExpression.subjectExpression ?: return with(analysisSession) { builtinTypes.BOOLEAN }
val kotlinType = analysisContext.analyze(subject).getType(subject)
return kotlinType?.toKtNonErrorType(analysisContext)
}
}
is KtBlockExpression -> {
if (expression == parentExpression.statements.lastOrNull()) {
val functionLiteral = parentExpression.parent as? KtFunctionLiteral
if (functionLiteral != null) {
val functionalType = getExpectedType(functionLiteral) as? KtFunctionalType
functionalType?.returnType?.let { return it }
}
}
}
is KtWhenEntry -> {
if (expression == parentExpression.expression) {
val whenExpression = parentExpression.parent as? KtWhenExpression
if (whenExpression != null) {
getExpectedType(whenExpression)?.let { return it }
val entries = whenExpression.entries
val entryExpressions = entries.mapNotNull { entry -> entry.expression?.takeUnless { expression == it } }
val kotlinTypes = entryExpressions.mapNotNull { analysisContext.analyze(it).getType(it) }
return intersectWrappedTypes(kotlinTypes).toKtNonErrorType(analysisContext)
}
}
}
@@ -226,7 +269,7 @@ class KtFe10ExpressionTypeProvider(
val bindingContext = analysisContext.analyze(ktExpression)
val kotlinType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, ktExpression]
return kotlinType?.toKtType(analysisContext)
return kotlinType?.toKtNonErrorType(analysisContext)
}
private fun getContainingCallExpression(argument: KtValueArgument): KtCallExpression? {
@@ -274,4 +317,7 @@ class KtFe10ExpressionTypeProvider(
val expressionType = expression.getType(bindingContext) ?: return false
return !TypeUtils.isNullableType(expressionType)
}
private fun KotlinType.toKtNonErrorType(analysisContext: Fe10AnalysisContext): KtType? =
this.toKtType(analysisContext).takeUnless { it is KtErrorType }
}
@@ -41,11 +41,77 @@ public class Fe10IdeNormalAnalysisSourceModuleExpectedExpressionTypeTestGenerate
);
}
@Test
@TestMetadata("afterExclOperand.kt")
public void testAfterExclOperand() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/afterExclOperand.kt");
}
@Test
public void testAllFilesPresentInExpectedExpressionType() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("arrayAccessExpressionGet.kt")
public void testArrayAccessExpressionGet() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/arrayAccessExpressionGet.kt");
}
@Test
@TestMetadata("arrayAccessExpressionGetWithTypeParameters.kt")
public void testArrayAccessExpressionGetWithTypeParameters() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/arrayAccessExpressionGetWithTypeParameters.kt");
}
@Test
@TestMetadata("arrayAccessExpressionSet.kt")
public void testArrayAccessExpressionSet() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/arrayAccessExpressionSet.kt");
}
@Test
@TestMetadata("arrayAccessExpressionSetWithTypeParameters.kt")
public void testArrayAccessExpressionSetWithTypeParameters() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/arrayAccessExpressionSetWithTypeParameters.kt");
}
@Test
@TestMetadata("conditionInWhenWithSubject.kt")
public void testConditionInWhenWithSubject() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/conditionInWhenWithSubject.kt");
}
@Test
@TestMetadata("conditionInWhenWithoutSubject.kt")
public void testConditionInWhenWithoutSubject() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/conditionInWhenWithoutSubject.kt");
}
@Test
@TestMetadata("elvisExpressionLeftOperand.kt")
public void testElvisExpressionLeftOperand() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/elvisExpressionLeftOperand.kt");
}
@Test
@TestMetadata("elvisExpressionLeftOperandWithoutExplicitType.kt")
public void testElvisExpressionLeftOperandWithoutExplicitType() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/elvisExpressionLeftOperandWithoutExplicitType.kt");
}
@Test
@TestMetadata("elvisExpressionRightOperand.kt")
public void testElvisExpressionRightOperand() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/elvisExpressionRightOperand.kt");
}
@Test
@TestMetadata("elvisExpressionRightOperandWithoutExplicitType.kt")
public void testElvisExpressionRightOperandWithoutExplicitType() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/elvisExpressionRightOperandWithoutExplicitType.kt");
}
@Test
@TestMetadata("functionExpressionBody.kt")
public void testFunctionExpressionBody() throws Exception {
@@ -136,6 +202,12 @@ public class Fe10IdeNormalAnalysisSourceModuleExpectedExpressionTypeTestGenerate
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/infixFunctionParamQualified.kt");
}
@Test
@TestMetadata("infixFunctionTypeParameter.kt")
public void testInfixFunctionTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/infixFunctionTypeParameter.kt");
}
@Test
@TestMetadata("lambdaWithExplicitTypeFromVariable.kt")
public void testLambdaWithExplicitTypeFromVariable() throws Exception {
@@ -148,6 +220,42 @@ public class Fe10IdeNormalAnalysisSourceModuleExpectedExpressionTypeTestGenerate
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/lambdaWithoutReturnNorExplicitType.kt");
}
@Test
@TestMetadata("lastStatementInFunctionBlockBody.kt")
public void testLastStatementInFunctionBlockBody() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/lastStatementInFunctionBlockBody.kt");
}
@Test
@TestMetadata("lastStatementInLambda.kt")
public void testLastStatementInLambda() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/lastStatementInLambda.kt");
}
@Test
@TestMetadata("lastStatementInLambdaWithTypeMismatch.kt")
public void testLastStatementInLambdaWithTypeMismatch() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/lastStatementInLambdaWithTypeMismatch.kt");
}
@Test
@TestMetadata("lastStatementInLambdaWithoutExplicitType.kt")
public void testLastStatementInLambdaWithoutExplicitType() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/lastStatementInLambdaWithoutExplicitType.kt");
}
@Test
@TestMetadata("lastStatementInTry.kt")
public void testLastStatementInTry() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/lastStatementInTry.kt");
}
@Test
@TestMetadata("lastStatementInTryWithoutExplicitType.kt")
public void testLastStatementInTryWithoutExplicitType() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/lastStatementInTryWithoutExplicitType.kt");
}
@Test
@TestMetadata("propertyDeclaration.kt")
public void testPropertyDeclaration() throws Exception {
@@ -274,6 +382,42 @@ public class Fe10IdeNormalAnalysisSourceModuleExpectedExpressionTypeTestGenerate
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/samWithTypeCast.kt");
}
@Test
@TestMetadata("statementInIf.kt")
public void testStatementInIf() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/statementInIf.kt");
}
@Test
@TestMetadata("statementInIfBlockExpression.kt")
public void testStatementInIfBlockExpression() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/statementInIfBlockExpression.kt");
}
@Test
@TestMetadata("statementInIfWithoutExplicitType.kt")
public void testStatementInIfWithoutExplicitType() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/statementInIfWithoutExplicitType.kt");
}
@Test
@TestMetadata("statementInWhen.kt")
public void testStatementInWhen() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/statementInWhen.kt");
}
@Test
@TestMetadata("statementInWhenBlockExpression.kt")
public void testStatementInWhenBlockExpression() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/statementInWhenBlockExpression.kt");
}
@Test
@TestMetadata("statementInWhenWithoutExplicitType.kt")
public void testStatementInWhenWithoutExplicitType() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expectedExpressionType/statementInWhenWithoutExplicitType.kt");
}
@Test
@TestMetadata("variableAssignment.kt")
public void testVariableAssignment() throws Exception {
@@ -277,6 +277,12 @@ public class Fe10IdeNormalAnalysisSourceModuleHLExpressionTypeTestGenerated exte
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetUnresovledSet.kt");
}
@Test
@TestMetadata("arrayAssignmentTargetWithTypeParameters.kt")
public void testArrayAssignmentTargetWithTypeParameters() throws Exception {
runTest("analysis/analysis-api/testData/components/expressionTypeProvider/expressionType/assignment/arrayAssignmentTargetWithTypeParameters.kt");
}
@Test
@TestMetadata("arrayCompoundAssignementTarget.kt")
public void testArrayCompoundAssignementTarget() throws Exception {