[Analysis API] Handle missed cases in PsiElement.getExpectedType()
^KTIJ-24256
This commit is contained in:
committed by
teamcity
parent
7dd438cb9e
commit
3d0bca5ca1
+79
-33
@@ -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 }
|
||||
}
|
||||
+144
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user