[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 {
@@ -79,26 +79,36 @@ internal interface KtFirAnalysisSessionComponent {
)
}
fun FirQualifiedAccessExpression.createSubstitutorFromTypeArguments(): KtSubstitutor? {
return createConeSubstitutorFromTypeArguments()?.toKtSubstitutor()
fun FirQualifiedAccessExpression.createSubstitutorFromTypeArguments(discardErrorTypes: Boolean = false): KtSubstitutor? {
return createConeSubstitutorFromTypeArguments(discardErrorTypes)?.toKtSubstitutor()
}
fun FirQualifiedAccessExpression.createSubstitutorFromTypeArguments(callableSymbol: FirCallableSymbol<*>): KtSubstitutor {
return createConeSubstitutorFromTypeArguments(callableSymbol).toKtSubstitutor()
fun FirQualifiedAccessExpression.createSubstitutorFromTypeArguments(
callableSymbol: FirCallableSymbol<*>,
discardErrorTypes: Boolean = false
): KtSubstitutor {
return createConeSubstitutorFromTypeArguments(callableSymbol, discardErrorTypes).toKtSubstitutor()
}
fun FirQualifiedAccessExpression.createConeSubstitutorFromTypeArguments(): ConeSubstitutor? {
fun FirQualifiedAccessExpression.createConeSubstitutorFromTypeArguments(discardErrorTypes: Boolean = false): ConeSubstitutor? {
val symbol = calleeReference.toResolvedCallableSymbol() ?: return null
return createConeSubstitutorFromTypeArguments(symbol)
return createConeSubstitutorFromTypeArguments(symbol, discardErrorTypes)
}
fun FirQualifiedAccessExpression.createConeSubstitutorFromTypeArguments(callableSymbol: FirCallableSymbol<*>): ConeSubstitutor {
/**
* @param discardErrorTypes if true, then type arguments with error types are not added in substitution map
*/
fun FirQualifiedAccessExpression.createConeSubstitutorFromTypeArguments(
callableSymbol: FirCallableSymbol<*>,
discardErrorTypes: Boolean = false
): ConeSubstitutor {
val typeArgumentMap = buildMap {
// Type arguments are ignored defensively if `callableSymbol` can't provide enough type parameters (and vice versa). For
// example, when call candidates are collected, the candidate's `callableSymbol` might have fewer type parameters than the
// inferred call's type arguments.
typeArguments.zip(callableSymbol.typeParameterSymbols).forEach { (typeArgument, typeParameterSymbol) ->
val type = typeArgument.safeAs<FirTypeProjectionWithVariance>()?.typeRef?.coneType ?: return@forEach
if (type is ConeErrorType && discardErrorTypes) return@forEach
put(typeParameterSymbol, type)
}
}
@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.utils.getReferencedElementType
import org.jetbrains.kotlin.analysis.api.fir.utils.unwrap
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.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
@@ -23,11 +25,13 @@ 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.constructFunctionType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@@ -92,8 +96,19 @@ internal class KtFirExpressionTypeProvider(
val assignment = expression.parent as? KtBinaryExpression ?: return null
if (assignment.operationToken !in KtTokens.ALL_ASSIGNMENTS) return null
if (assignment.left != expression) return null
val setTargetArgumentParameter = fir.resolvedArgumentMapping?.entries?.last()?.value ?: return null
return setTargetArgumentParameter.returnTypeRef.coneType.asKtType()
val setTargetParameterType = fir.argumentsToSubstitutedValueParameters()?.values?.last()?.substitutedType ?: return null
return setTargetParameterType.asKtType()
}
private data class SubstitutedValueParameter(val parameter: FirValueParameter, val substitutedType: ConeKotlinType)
private fun FirFunctionCall.argumentsToSubstitutedValueParameters(
substituteWithErrorTypes: Boolean = true
): LinkedHashMap<FirExpression, SubstitutedValueParameter>? {
val substitutor = createConeSubstitutorFromTypeArguments(discardErrorTypes = !substituteWithErrorTypes) ?: ConeSubstitutor.Empty
return resolvedArgumentMapping?.mapValuesTo(LinkedHashMap()) { (_, parameter) ->
SubstitutedValueParameter(parameter, substitutor.substituteOrSelf(parameter.returnTypeRef.coneType))
}
}
override fun getReturnTypeForKtDeclaration(declaration: KtDeclaration): KtType {
@@ -134,10 +149,17 @@ internal class KtFirExpressionTypeProvider(
?: getExpressionTypeByIfOrBooleanCondition(unwrapped)
?: getExpectedTypeByTypeCast(unwrapped)
?: getExpectedTypeOfFunctionParameter(unwrapped)
?: getExpectedTypeOfIndexingParameter(unwrapped)
?: getExpectedTypeOfInfixFunctionParameter(unwrapped)
?: getExpectedTypeByVariableAssignment(unwrapped)
?: getExpectedTypeByPropertyDeclaration(unwrapped)
?: getExpectedTypeByFunctionExpressionBody(unwrapped)
?: getExpectedTypeOfLastStatementInBlock(unwrapped)
?: getExpectedTypeByIfExpression(unwrapped)
?: getExpectedTypeOfWhenEntryExpression(unwrapped)
?: getExpectedTypeByTryExpression(unwrapped)
?: getExpectedTypeOfElvisOperand(unwrapped)
?: getExpectedTypeByWhenEntryValue(unwrapped)
return expectedType
}
@@ -158,9 +180,9 @@ internal class KtFirExpressionTypeProvider(
return (callee.fir as FirSimpleFunction).returnTypeRef.coneType.asKtType()
}
val arguments = firCall.resolvedArgumentMapping ?: return null
val firParameterForExpression =
arguments.entries.firstOrNull { (arg, _) ->
val argumentsToParameters = firCall.argumentsToSubstitutedValueParameters(substituteWithErrorTypes = false) ?: return null
val (firParameterForExpression, substitutedType) =
argumentsToParameters.entries.firstOrNull { (arg, _) ->
when (arg) {
// TODO: better to utilize. See `createArgumentMapping` in [KtFirCallResolver]
is FirLambdaArgumentExpression, is FirNamedArgumentExpression, is FirSpreadArgumentExpression ->
@@ -169,11 +191,29 @@ internal class KtFirExpressionTypeProvider(
arg.psi == argumentExpression
}
}?.value ?: return null
val coneType = firParameterForExpression.returnTypeRef.coneType
return if (firParameterForExpression.isVararg)
coneType.varargElementType().asKtType()
substitutedType.varargElementType().asKtType()
else
coneType.asKtType()
substitutedType.asKtType()
}
/**
* Expected type of the indexing parameter in array access, for example, in the following code:
* ```
* val map = mapOf<Int, String>()
* map[k] = v
* ```
* `k` is indexing parameter and its expected type is `Int`.
*/
private fun getExpectedTypeOfIndexingParameter(expression: PsiElement): KtType? {
val arrayAccessExpression = expression.unwrapQualified<KtArrayAccessExpression> { arrayAccessExpression, currentExpression ->
currentExpression in arrayAccessExpression.indexExpressions
} ?: return null
val firCall = arrayAccessExpression.getOrBuildFirSafe<FirFunctionCall>(firResolveSession) ?: return null
val firArgument = firCall.argumentList.arguments.firstOrNull { it.psi == expression } ?: return null
val argumentsToParameters = firCall.argumentsToSubstitutedValueParameters(substituteWithErrorTypes = false) ?: return null
return argumentsToParameters[firArgument]?.substitutedType?.asKtType()
}
private fun PsiElement.getFunctionCallAsWithThisAsParameter(): KtCallWithArgument? {
@@ -196,9 +236,8 @@ internal class KtFirExpressionTypeProvider(
val firCall = infixCallExpression.getOrBuildFirSafe<FirFunctionCall>(firResolveSession) ?: return null
// There is only one parameter for infix functions; get its type
val arguments = firCall.resolvedArgumentMapping ?: return null
val firParameterForExpression = arguments.values.singleOrNull() ?: return null
return firParameterForExpression.returnTypeRef.coneType.asKtType()
val argumentsToParameters = firCall.argumentsToSubstitutedValueParameters(substituteWithErrorTypes = false) ?: return null
return argumentsToParameters.values.singleOrNull()?.substitutedType?.asKtType() ?: return null
}
private fun getExpectedTypeByReturnExpression(expression: PsiElement): KtType? {
@@ -222,14 +261,14 @@ internal class KtFirExpressionTypeProvider(
expression.unwrapQualified<KtBinaryExpression> { binaryExpr, expr -> binaryExpr.right == expr && binaryExpr.operationToken == KtTokens.EQ }
?: return null
val variableExpression = assignmentExpression.left as? KtNameReferenceExpression ?: return null
return getKtExpressionType(variableExpression)
return getKtExpressionNonErrorType(variableExpression)
}
private fun getExpectedTypeByPropertyDeclaration(expression: PsiElement): KtType? {
// Given: `val x: T = expression`
// Expected type of `expression` is `T`
val property = expression.unwrapQualified<KtProperty> { property, expr -> property.initializer == expr } ?: return null
return getReturnTypeForKtDeclaration(property)
return getReturnTypeForKtDeclaration(property).nonErrorTypeOrNull()
}
private fun getExpectedTypeByFunctionExpressionBody(expression: PsiElement): KtType? {
@@ -241,9 +280,91 @@ internal class KtFirExpressionTypeProvider(
// which may raise an exception if we attempt to retrieve, e.g., callable declaration from it.
return null
}
return getReturnTypeForKtDeclaration(function)
return getReturnTypeForKtDeclaration(function).nonErrorTypeOrNull()
}
private fun getExpectedTypeOfLastStatementInBlock(expression: PsiElement): KtType? {
val blockExpression = expression.unwrapQualified<KtBlockExpression> { blockExpression, currentExpression ->
currentExpression == blockExpression.statements.lastOrNull()
} ?: return null
val functionLiteral = blockExpression.parent as? KtFunctionLiteral
return if (functionLiteral != null) {
val functionalType = getExpectedType(functionLiteral) as? KtFunctionalType
functionalType?.returnType
} else {
getExpectedType(blockExpression)
}
}
private fun getExpectedTypeByIfExpression(expression: PsiElement): KtType? {
val ifExpression = expression.unwrapQualified<KtIfExpression> { ifExpression, currentExpression ->
currentExpression == ifExpression.then || currentExpression == ifExpression.`else`
} ?: return null
getExpectedType(ifExpression)?.let { return it }
// if `KtIfExpression` doesn't have an expected type, get the expected type of the current branch from the other branch
val otherBranch = (if (expression == ifExpression.then) ifExpression.`else` else ifExpression.then) ?: return null
return getKtExpressionNonErrorType(otherBranch)
}
private fun getExpectedTypeOfWhenEntryExpression(expression: PsiElement): KtType? {
val whenEntry = expression.unwrapQualified<KtWhenEntry> { whenEntry, currentExpression ->
currentExpression == whenEntry.expression
} ?: return null
val whenExpression = whenEntry.parent as? KtWhenExpression ?: return null
getExpectedType(whenExpression)?.let { return it }
// if `KtWhenExpression` doesn't have an expected type, get the expected type of the current entry from the other entries
val entryExpressions = whenExpression.entries
.mapNotNull { it.expression }
.filter { entryExpression -> entryExpression != expression }
val types = entryExpressions.mapNotNull { getKtExpressionNonErrorType(it) }
return analysisSession.useSiteSession.typeContext.intersectTypesOrNull(types.map { it.coneType })?.asKtType()
}
private fun getExpectedTypeByTryExpression(expression: PsiElement): KtType? {
val tryExpression = expression.unwrapQualified<KtTryExpression> { tryExpression, currentExpression ->
currentExpression == tryExpression.tryBlock
} ?: return null
return getExpectedType(tryExpression)
}
private fun getExpectedTypeOfElvisOperand(expression: PsiElement): KtType? {
val binaryExpression = expression.unwrapQualified<KtBinaryExpression> { binaryExpression, operand ->
binaryExpression.operationToken == KtTokens.ELVIS && (operand == binaryExpression.left || operand == binaryExpression.right)
} ?: return null
if (expression !is KtExpression) return null
val type = getExpectedType(binaryExpression) ?: getElvisOperandExpectedTypeByOtherOperand(expression, binaryExpression)
return type?.applyIf(expression == binaryExpression.left) { withNullability(ConeNullability.NULLABLE) }
}
private fun getElvisOperandExpectedTypeByOtherOperand(operand: KtExpression, elvisExpression: KtBinaryExpression): KtType? {
val leftOperand = elvisExpression.left ?: return null
val rightOperand = elvisExpression.right ?: return null
return if (operand == leftOperand) {
getKtExpressionNonErrorType(rightOperand)
} else {
getKtExpressionNonErrorType(leftOperand)?.withNullability(ConeNullability.NOT_NULL)
}
}
private fun KtType.withNullability(nullability: ConeNullability): KtType =
coneType.withNullability(nullability, analysisSession.useSiteSession.typeContext).asKtType()
private fun getExpectedTypeByWhenEntryValue(expression: PsiElement): KtType? {
val condition = expression.parent as? KtWhenConditionWithExpression ?: return null
val whenExpression = (condition.parent as? KtWhenEntry)?.parent as? KtWhenExpression ?: return null
val subject = whenExpression.subjectExpression ?: return with(analysisSession) { builtinTypes.BOOLEAN }
return getKtExpressionNonErrorType(subject)
}
private fun getKtExpressionNonErrorType(expression: KtExpression): KtType? =
getKtExpressionType(expression)?.nonErrorTypeOrNull()
private fun KtType.nonErrorTypeOrNull(): KtType? = takeUnless { it is KtErrorType }
private fun PsiElement.isWhileLoopCondition() =
unwrapQualified<KtWhileExpressionBase> { whileExpr, cond -> whileExpr.condition == cond } != null
@@ -41,11 +41,77 @@ public class FirIdeDependentAnalysisSourceModuleExpectedExpressionTypeTestGenera
);
}
@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 FirIdeDependentAnalysisSourceModuleExpectedExpressionTypeTestGenera
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 FirIdeDependentAnalysisSourceModuleExpectedExpressionTypeTestGenera
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 FirIdeDependentAnalysisSourceModuleExpectedExpressionTypeTestGenera
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 FirIdeDependentAnalysisSourceModuleHLExpressionTypeTestGenerated ex
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 {
@@ -41,11 +41,77 @@ public class FirIdeNormalAnalysisSourceModuleExpectedExpressionTypeTestGenerated
);
}
@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 FirIdeNormalAnalysisSourceModuleExpectedExpressionTypeTestGenerated
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 FirIdeNormalAnalysisSourceModuleExpectedExpressionTypeTestGenerated
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 FirIdeNormalAnalysisSourceModuleExpectedExpressionTypeTestGenerated
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 FirIdeNormalAnalysisSourceModuleHLExpressionTypeTestGenerated exten
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 {
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiSingleFileTest
import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider
import org.jetbrains.kotlin.analysis.test.framework.utils.executeOnPooledThreadInReadAction
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
@@ -20,10 +21,11 @@ import org.jetbrains.kotlin.types.Variance
abstract class AbstractAnalysisApiGetSuperTypesTest : AbstractAnalysisApiSingleFileTest(){
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
val expression = testServices.expressionMarkerProvider.getSelectedElement(ktFile)
expression as? KtExpression ?: error("unexpected expression kind ${expression::class}")
val actual = executeOnPooledThreadInReadAction {
analyze(expression) {
val expectedType = expression.getExpectedType() ?: error("expect to get type of expression '${expression.text}'")
val expectedType = expression.getKtType() ?: error("expect to get type of expression '${expression.text}'")
val directSuperTypes = expectedType.getDirectSuperTypes()
val approximatedDirectSuperTypes = expectedType.getDirectSuperTypes(shouldApproximate = true)
val allSuperTypes = expectedType.getAllSuperTypes()
@@ -41,11 +41,77 @@ public class FirStandaloneNormalAnalysisSourceModuleExpectedExpressionTypeTestGe
);
}
@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 FirStandaloneNormalAnalysisSourceModuleExpectedExpressionTypeTestGe
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 FirStandaloneNormalAnalysisSourceModuleExpectedExpressionTypeTestGe
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 FirStandaloneNormalAnalysisSourceModuleExpectedExpressionTypeTestGe
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 FirStandaloneNormalAnalysisSourceModuleHLExpressionTypeTestGenerate
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 {
@@ -0,0 +1,3 @@
fun test() {
if (!a<caret>v)
}
@@ -0,0 +1,2 @@
expression: av
expected type: null
@@ -0,0 +1,7 @@
class A {
operator fun get(p1: Int) {}
operator fun set(p1: String, p2: Int, value: Int) {}
fun d() = this[a<caret>v]
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,8 @@
// IGNORE_FE10
class A {
operator fun <T> get(key: T) {}
}
fun test(a: A) {
a[a<caret>v]
}
@@ -0,0 +1,4 @@
expression: av
expected type: KtTypeParameterType:
annotationsList: []
type: T
@@ -0,0 +1,8 @@
class A {
operator fun get(p1: Int) {}
operator fun set(p1: String, p2: Int, value: Int) {}
fun d() {
this[a<caret>v, 2] = 1
}
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/String
@@ -0,0 +1,7 @@
class A {
operator fun <T> set(key: T, value: T) {}
}
fun test(a: A) {
a[a<caret>v] = 1
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,10 @@
enum class E {
A
B
}
fun foo(e: E) {
when(e) {
a<caret>v -> null
}
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: E
@@ -0,0 +1,5 @@
fun foo() {
when() {
a<caret>v -> null
}
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Boolean
@@ -0,0 +1,3 @@
fun foo() {
val result: Int = a<caret>v ?: 1
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int?
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int?
@@ -0,0 +1,3 @@
fun foo(i: Int?) {
val result: Int = i ?: a<caret>v
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -1,4 +0,0 @@
expression: av
expected type: KtTypeErrorType:
annotationsList: []
type: ERROR_TYPE
@@ -1,4 +1,2 @@
expression: av
expected type: KtClassErrorType:
annotationsList: []
type: ERROR_TYPE
expected type: null
@@ -0,0 +1,4 @@
expression: ab
expected type: KtTypeParameterType:
annotationsList: []
type: T
@@ -1,4 +1,5 @@
expression: ab
expected type: KtTypeParameterType:
expected type: KtUsualClassType:
annotationsList: []
type: T
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,5 @@
fun x() {
1 toCall a<caret>v
}
infix fun <T> T.toCall(y: T) {}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,2 @@
expression: av
expected type: null
@@ -0,0 +1,5 @@
// WITH_STDLIB
// IGNORE_FE10
fun foo(list: List<Int>) {
val result: List<String> = list.map { a<caret>v }
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/String
@@ -0,0 +1,4 @@
// WITH_STDLIB
fun foo(list: List<Int>) {
val result: List<Int> = list.map { mapOf(a<caret>v) }
}
@@ -0,0 +1,12 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: [
KtTypeParameterType:
annotationsList: []
type: K
KtTypeParameterType:
annotationsList: []
type: V
]
type: kotlin/Pair<K, V>
@@ -0,0 +1,4 @@
// WITH_STDLIB
fun foo(list: List<Int>) {
val result = list.map { a<caret>v }
}
@@ -0,0 +1,4 @@
expression: av
expected type: KtTypeParameterType:
annotationsList: []
type: R
@@ -0,0 +1,5 @@
fun foo() {
val result: Int = try {
a<caret>v
}
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,2 @@
expression: av
expected type: null
@@ -1,4 +0,0 @@
expression: av
expected type: KtTypeErrorType:
annotationsList: []
type: ERROR_TYPE
@@ -1,4 +1,2 @@
expression: av
expected type: KtClassErrorType:
annotationsList: []
type: ERROR_TYPE
expected type: null
@@ -0,0 +1,3 @@
fun foo() {
val result = if (true) 1 else a<caret>v
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,7 @@
fun foo() {
val result = if (true) {
1
} else {
a<caret>v
}
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,3 @@
fun foo() {
if (true) a<caret>v else 1
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,11 @@
enum class E {
A
B
}
fun foo(e: E) {
val result = when(e) {
E.A -> 1
E.B -> a<caret>v
}
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,11 @@
enum class E {
A
B
}
fun foo(e: E) {
val result = when(e) {
E.A -> { 1 }
E.B -> { a<caret>v }
}
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
@@ -0,0 +1,13 @@
enum class E {
A
B
C
D
}
fun foo(e: E) = when (e) {
E.A -> 1
E.B -> ""
E.C -> a<caret>v
E.D -> unresolved
}
@@ -0,0 +1,5 @@
expression: av
expected type: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Any
@@ -0,0 +1,8 @@
// IGNORE_FE10
class A {
operator fun <T> set(key: Int, value: T) {}
}
fun test(a: A) {
<expr>a[1]</expr> = ""
}
@@ -0,0 +1,3 @@
expression: xy
expected type: (T) -> R
functionClassKind: kotlin.FunctionN
@@ -1,3 +1,3 @@
expression: xy
expected type: (T) -> R
expected type: (kotlin.Int) -> R
functionClassKind: kotlin.FunctionN