From b2397f033b8f11c6b5a2a25b36dea4e010163c6c Mon Sep 17 00:00:00 2001 From: Nikita Bobko Date: Fri, 4 Nov 2022 20:40:14 +0100 Subject: [PATCH] 1/2 analysis-api: Initial implementation for contracts Review: https://jetbrains.team/p/kt/reviews/7652 I need this API for KTIJ-22692 --- .../contracts/descriptorContractUtils.kt | 109 +++++++++++ .../KtFe10DescFunctionSymbol.kt | 12 +- .../psiBased/KtFe10PsiFunctionSymbol.kt | 12 ++ .../descriptors/types/KtFe10CapturedType.kt | 2 +- ...ourceModuleSingleSymbolByPsiGenerated.java | 112 ++++++++++++ .../api/fir/contracts/firContractUtils.kt | 124 +++++++++++++ .../api/fir/symbols/KtFirFunctionSymbol.kt | 10 + ...ourceModuleSingleSymbolByPsiGenerated.java | 112 ++++++++++++ ...ourceModuleSingleSymbolByPsiGenerated.java | 112 ++++++++++++ .../KtContractDescriptionElementRenderer.kt | 102 +++++++++++ .../api/contracts/description/KtEffects.kt | 91 ++++++++++ .../api/contracts/description/KtValues.kt | 41 +++++ .../booleans/KtContractBooleanExpression.kt | 47 +++++ .../booleans/KtLogicalCombinators.kt | 47 +++++ .../description/booleans/KtPredicates.kt | 49 +++++ .../api/symbols/DebugSymbolRenderer.kt | 5 + .../analysis/api/symbols/KtCallableSymbol.kt | 2 +- .../api/symbols/KtFunctionLikeSymbol.kt | 2 + .../api/symbols/KtVariableLikeSymbol.kt | 5 +- .../booleanConstReferenceInImplies.kt | 13 ++ .../booleanConstReferenceInImplies.pretty.txt | 2 + .../booleanConstReferenceInImplies.txt | 39 ++++ .../contracts/booleanExprContract.kt | 13 ++ .../contracts/booleanExprContract.pretty.txt | 2 + .../contracts/booleanExprContract.txt | 128 +++++++++++++ .../callsInPlaceAtLeastOnceContract.kt | 13 ++ ...callsInPlaceAtLeastOnceContract.pretty.txt | 2 + .../callsInPlaceAtLeastOnceContract.txt | 74 ++++++++ .../callsInPlaceAtMostOnceContract.kt | 13 ++ .../callsInPlaceAtMostOnceContract.pretty.txt | 2 + .../callsInPlaceAtMostOnceContract.txt | 74 ++++++++ .../callsInPlaceExactlyOnceContract.kt | 13 ++ ...callsInPlaceExactlyOnceContract.pretty.txt | 2 + .../callsInPlaceExactlyOnceContract.txt | 74 ++++++++ .../contracts/callsInPlaceUnknownContract.kt | 13 ++ .../callsInPlaceUnknownContract.pretty.txt | 2 + .../contracts/callsInPlaceUnknownContract.txt | 74 ++++++++ ...invalidContractParameterPassedToReturns.kt | 13 ++ ...ontractParameterPassedToReturns.pretty.txt | 2 + ...nvalidContractParameterPassedToReturns.txt | 68 +++++++ .../contracts/isInstancePredicateContract.kt | 17 ++ .../isInstancePredicateContract.pretty.txt | 2 + .../contracts/isInstancePredicateContract.txt | 80 ++++++++ .../contracts/logicalNotContract.kt | 15 ++ .../contracts/logicalNotContract.pretty.txt | 2 + .../contracts/logicalNotContract.txt | 77 ++++++++ .../referenceBooleanReceiverInContract.kt | 14 ++ ...erenceBooleanReceiverInContract.pretty.txt | 2 + .../referenceBooleanReceiverInContract.txt | 49 +++++ .../contracts/referenceReceiverInContract.kt | 13 ++ .../referenceReceiverInContract.pretty.txt | 2 + .../contracts/referenceReceiverInContract.txt | 48 +++++ .../contracts/returnsContract.kt | 15 ++ .../contracts/returnsContract.pretty.txt | 2 + .../contracts/returnsContract.txt | 75 ++++++++ .../contracts/returnsFalseContract.kt | 13 ++ .../contracts/returnsFalseContract.pretty.txt | 2 + .../contracts/returnsFalseContract.txt | 81 +++++++++ .../contracts/returnsNotNullContract.kt | 13 ++ .../returnsNotNullContract.pretty.txt | 2 + .../contracts/returnsNotNullContract.txt | 78 ++++++++ .../contracts/returnsNullContract.kt | 13 ++ .../contracts/returnsNullContract.pretty.txt | 2 + .../contracts/returnsNullContract.txt | 81 +++++++++ .../contracts/returnsTrueContract.kt | 13 ++ .../contracts/returnsTrueContract.pretty.txt | 2 + .../contracts/returnsTrueContract.txt | 81 +++++++++ .../contracts/twoContracts.kt | 15 ++ .../contracts/twoContracts.pretty.txt | 2 + .../contracts/twoContracts.txt | 171 ++++++++++++++++++ 70 files changed, 2610 insertions(+), 4 deletions(-) create mode 100644 analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/contracts/descriptorContractUtils.kt create mode 100644 analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/contracts/firContractUtils.kt create mode 100644 analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtContractDescriptionElementRenderer.kt create mode 100644 analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtEffects.kt create mode 100644 analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtValues.kt create mode 100644 analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtContractBooleanExpression.kt create mode 100644 analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtLogicalCombinators.kt create mode 100644 analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtPredicates.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.kt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.pretty.txt create mode 100644 analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.txt diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/contracts/descriptorContractUtils.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/contracts/descriptorContractUtils.kt new file mode 100644 index 00000000000..dbc4937001b --- /dev/null +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/contracts/descriptorContractUtils.kt @@ -0,0 +1,109 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.descriptors.contracts + +import org.jetbrains.kotlin.analysis.api.contracts.description.* +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractConstantValue.KtContractConstantType +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractReturnsContractEffectDeclaration.* +import org.jetbrains.kotlin.analysis.api.contracts.description.booleans.* +import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext +import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtSymbol +import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtType +import org.jetbrains.kotlin.analysis.api.symbols.KtParameterSymbol +import org.jetbrains.kotlin.contracts.description.* +import org.jetbrains.kotlin.contracts.description.expressions.* + +internal fun EffectDeclaration.effectDeclarationToAnalysisApi(analysisContext: Fe10AnalysisContext): KtContractEffectDeclaration = + accept(ContractDescriptionElementToAnalysisApi(analysisContext), Unit) as KtContractEffectDeclaration + +private class ContractDescriptionElementToAnalysisApi(val analysisContext: Fe10AnalysisContext) : + ContractDescriptionVisitor { + + override fun visitConditionalEffectDeclaration( + conditionalEffect: ConditionalEffectDeclaration, + data: Unit + ): Any = KtContractConditionalContractEffectDeclaration( + conditionalEffect.effect.accept(), + conditionalEffect.condition.accept(), + ) + + override fun visitReturnsEffectDeclaration( + returnsEffect: ReturnsEffectDeclaration, + data: Unit + ): KtContractReturnsContractEffectDeclaration = + when (val value = returnsEffect.value) { + ConstantReference.NULL -> + KtContractReturnsSpecificValueEffectDeclaration(KtContractConstantValue(KtContractConstantType.NULL, analysisContext.token)) + ConstantReference.NOT_NULL -> KtContractReturnsNotNullEffectDeclaration(analysisContext.token) + ConstantReference.WILDCARD -> KtContractReturnsSuccessfullyEffectDeclaration(analysisContext.token) + is BooleanConstantReference -> KtContractReturnsSpecificValueEffectDeclaration( + KtContractConstantValue( + when (value) { + BooleanConstantReference.TRUE -> KtContractConstantType.TRUE + BooleanConstantReference.FALSE -> KtContractConstantType.FALSE + else -> error("Can't convert $value to the Analysis API") + }, + analysisContext.token + ) + ) + else -> error("Can't convert $returnsEffect to the Analysis API") + } + + override fun visitCallsEffectDeclaration(callsEffect: CallsEffectDeclaration, data: Unit): Any = + KtContractCallsInPlaceContractEffectDeclaration(callsEffect.variableReference.accept(), callsEffect.kind) + + override fun visitLogicalOr(logicalOr: LogicalOr, data: Unit): Any = KtContractBinaryLogicExpression( + logicalOr.left.accept(), + logicalOr.right.accept(), + KtContractBinaryLogicExpression.KtLogicOperation.OR + ) + + override fun visitLogicalAnd(logicalAnd: LogicalAnd, data: Unit): Any = KtContractBinaryLogicExpression( + logicalAnd.left.accept(), + logicalAnd.right.accept(), + KtContractBinaryLogicExpression.KtLogicOperation.AND + ) + + override fun visitLogicalNot(logicalNot: LogicalNot, data: Unit): Any = + KtContractLogicalNotExpression(logicalNot.arg.accept()) + + override fun visitIsInstancePredicate(isInstancePredicate: IsInstancePredicate, data: Unit): Any = + KtContractIsInstancePredicateExpression( + isInstancePredicate.arg.accept(), + isInstancePredicate.type.toKtType(analysisContext), + isInstancePredicate.isNegated + ) + + override fun visitIsNullPredicate(isNullPredicate: IsNullPredicate, data: Unit): Any = + KtContractIsNullPredicateExpression(isNullPredicate.arg.accept(), isNullPredicate.isNegated) + + override fun visitBooleanConstantDescriptor( + booleanConstantDescriptor: BooleanConstantReference, + data: Unit + ): KtContractBooleanConstantExpression = + when (booleanConstantDescriptor) { + BooleanConstantReference.TRUE -> KtContractBooleanConstantExpression(true, analysisContext.token) + BooleanConstantReference.FALSE -> KtContractBooleanConstantExpression(false, analysisContext.token) + else -> error("Can't convert $booleanConstantDescriptor to Analysis API") + } + + override fun visitVariableReference(variableReference: VariableReference, data: Unit): Any = + visitVariableReference(variableReference, ::KtContractParameterValue) + + override fun visitBooleanVariableReference( + booleanVariableReference: BooleanVariableReference, + data: Unit + ): Any = visitVariableReference(booleanVariableReference, ::KtContractBooleanValueParameterExpression) + + private fun visitVariableReference( + variableReference: VariableReference, + constructor: (KtParameterSymbol) -> T + ): T = constructor(variableReference.descriptor.toKtSymbol(analysisContext) as KtParameterSymbol) + + // Util function to avoid hard coding names of the classes. Type inference will do a better job figuring out the best type to cast to. + // This visitor isn't type-safe anyway + private inline fun ContractDescriptionElement.accept() = accept(this@ContractDescriptionElementToAnalysisApi, Unit) as T +} diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescFunctionSymbol.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescFunctionSymbol.kt index e894f6eb87a..e04387e7f59 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescFunctionSymbol.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescFunctionSymbol.kt @@ -7,12 +7,15 @@ package org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.base.KtContextReceiver +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractEffectDeclaration import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext +import org.jetbrains.kotlin.analysis.api.descriptors.contracts.effectDeclarationToAnalysisApi import org.jetbrains.kotlin.analysis.api.descriptors.symbols.calculateHashCode import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.* import org.jetbrains.kotlin.analysis.api.descriptors.symbols.isEqualTo import org.jetbrains.kotlin.analysis.api.descriptors.symbols.pointers.KtFe10DescFunctionLikeSymbolPointer import org.jetbrains.kotlin.analysis.api.descriptors.symbols.pointers.KtFe10NeverRestoringSymbolPointer +import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached import org.jetbrains.kotlin.analysis.api.impl.base.util.kotlinFunctionInvokeCallableIds import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol @@ -23,6 +26,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.contracts.description.ContractProviderKey import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor import org.jetbrains.kotlin.name.CallableId @@ -38,6 +42,12 @@ internal class KtFe10DescFunctionSymbol private constructor( override val name: Name get() = withValidityAssertion { descriptor.name } + override val contractEffects: List by cached { + descriptor.getUserData(ContractProviderKey)?.getContractDescription()?.effects + ?.map { it.effectDeclarationToAnalysisApi(analysisContext) } + .orEmpty() + } + override val symbolKind: KtSymbolKind get() = withValidityAssertion { descriptor.ktSymbolKind } @@ -112,4 +122,4 @@ internal class KtFe10DescFunctionSymbol private constructor( return KtFe10DescFunctionSymbol(descriptor, analysisContext) } } -} \ No newline at end of file +} diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiFunctionSymbol.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiFunctionSymbol.kt index 751dd9d40f9..65da2011ad0 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiFunctionSymbol.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiFunctionSymbol.kt @@ -7,13 +7,16 @@ package org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.base.KtContextReceiver +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractEffectDeclaration import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade.AnalysisMode import org.jetbrains.kotlin.analysis.api.descriptors.symbols.calculateHashCode +import org.jetbrains.kotlin.analysis.api.descriptors.contracts.effectDeclarationToAnalysisApi import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.* import org.jetbrains.kotlin.analysis.api.descriptors.symbols.isEqualTo import org.jetbrains.kotlin.analysis.api.descriptors.symbols.pointers.KtFe10NeverRestoringSymbolPointer import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.* +import org.jetbrains.kotlin.analysis.api.descriptors.utils.ValidityAwareCachedValue import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached import org.jetbrains.kotlin.analysis.api.impl.base.util.kotlinFunctionInvokeCallableIds import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion @@ -25,6 +28,8 @@ import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.contracts.description.ContractProviderKey +import org.jetbrains.kotlin.contracts.description.EffectDeclaration import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities @@ -35,6 +40,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration import org.jetbrains.kotlin.resolve.BindingContext +import kotlin.reflect.KProperty internal class KtFe10PsiFunctionSymbol( override val psi: KtNamedFunction, @@ -45,6 +51,12 @@ internal class KtFe10PsiFunctionSymbol( bindingContext[BindingContext.FUNCTION, psi] } + override val contractEffects: List by cached { + descriptor?.getUserData(ContractProviderKey)?.getContractDescription()?.effects + ?.map { it.effectDeclarationToAnalysisApi(analysisContext) } + .orEmpty() + } + override val isSuspend: Boolean get() = withValidityAssertion { psi.hasModifier(KtTokens.SUSPEND_KEYWORD) } diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/types/KtFe10CapturedType.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/types/KtFe10CapturedType.kt index 728138ba0a4..3f628ee8425 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/types/KtFe10CapturedType.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/types/KtFe10CapturedType.kt @@ -9,11 +9,11 @@ import org.jetbrains.kotlin.analysis.api.KtTypeProjection import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.ktNullability import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtTypeProjection +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.descriptors.types.base.KtFe10Type import org.jetbrains.kotlin.analysis.api.descriptors.types.base.asStringForDebugging import org.jetbrains.kotlin.analysis.api.types.KtCapturedType import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability -import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.resolve.calls.inference.CapturedType internal class KtFe10CapturedType( diff --git a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java index cc97d6ff760..ea2cd337f7e 100644 --- a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java +++ b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java @@ -94,6 +94,118 @@ public class Fe10IdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated extends runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/setterWithAnnotations.kt"); } + @Nested + @TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts") + @TestDataPath("$PROJECT_ROOT") + public class Contracts { + @Test + public void testAllFilesPresentInContracts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("booleanConstReferenceInImplies.kt") + public void testBooleanConstReferenceInImplies() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.kt"); + } + + @Test + @TestMetadata("booleanExprContract.kt") + public void testBooleanExprContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceAtLeastOnceContract.kt") + public void testCallsInPlaceAtLeastOnceContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceAtMostOnceContract.kt") + public void testCallsInPlaceAtMostOnceContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceExactlyOnceContract.kt") + public void testCallsInPlaceExactlyOnceContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceUnknownContract.kt") + public void testCallsInPlaceUnknownContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.kt"); + } + + @Test + @TestMetadata("invalidContractParameterPassedToReturns.kt") + public void testInvalidContractParameterPassedToReturns() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.kt"); + } + + @Test + @TestMetadata("isInstancePredicateContract.kt") + public void testIsInstancePredicateContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.kt"); + } + + @Test + @TestMetadata("logicalNotContract.kt") + public void testLogicalNotContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.kt"); + } + + @Test + @TestMetadata("referenceBooleanReceiverInContract.kt") + public void testReferenceBooleanReceiverInContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.kt"); + } + + @Test + @TestMetadata("referenceReceiverInContract.kt") + public void testReferenceReceiverInContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.kt"); + } + + @Test + @TestMetadata("returnsContract.kt") + public void testReturnsContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.kt"); + } + + @Test + @TestMetadata("returnsFalseContract.kt") + public void testReturnsFalseContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.kt"); + } + + @Test + @TestMetadata("returnsNotNullContract.kt") + public void testReturnsNotNullContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.kt"); + } + + @Test + @TestMetadata("returnsNullContract.kt") + public void testReturnsNullContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.kt"); + } + + @Test + @TestMetadata("returnsTrueContract.kt") + public void testReturnsTrueContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.kt"); + } + + @Test + @TestMetadata("twoContracts.kt") + public void testTwoContracts() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.kt"); + } + } + @Nested @TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/contracts/firContractUtils.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/contracts/firContractUtils.kt new file mode 100644 index 00000000000..c06e58fb10a --- /dev/null +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/contracts/firContractUtils.kt @@ -0,0 +1,124 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.fir.contracts + +import org.jetbrains.kotlin.analysis.api.contracts.description.* +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractConstantValue.KtContractConstantType +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractReturnsContractEffectDeclaration.* +import org.jetbrains.kotlin.analysis.api.contracts.description.booleans.* +import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder +import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFunctionSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtParameterSymbol +import org.jetbrains.kotlin.fir.contracts.description.* +import org.jetbrains.kotlin.fir.expressions.LogicOperationKind + +internal fun ConeEffectDeclaration.coneEffectDeclarationToAnalysisApi( + builder: KtSymbolByFirBuilder, + firFunctionSymbol: KtFirFunctionSymbol +): KtContractEffectDeclaration = + accept(ConeContractDescriptionElementToAnalysisApi(builder, firFunctionSymbol), Unit) as KtContractEffectDeclaration + +private class ConeContractDescriptionElementToAnalysisApi( + private val builder: KtSymbolByFirBuilder, + private val firFunctionSymbol: KtFirFunctionSymbol +) : ConeContractDescriptionVisitor() { + + override fun visitConditionalEffectDeclaration( + conditionalEffect: ConeConditionalEffectDeclaration, + data: Unit + ): KtContractConditionalContractEffectDeclaration = KtContractConditionalContractEffectDeclaration( + conditionalEffect.effect.accept(), + conditionalEffect.condition.accept() + ) + + override fun visitReturnsEffectDeclaration( + returnsEffect: ConeReturnsEffectDeclaration, + data: Unit + ): KtContractReturnsContractEffectDeclaration = + when (val value = returnsEffect.value) { + ConeConstantReference.NULL -> + KtContractReturnsSpecificValueEffectDeclaration(KtContractConstantValue(KtContractConstantType.NULL, builder.token)) + ConeConstantReference.NOT_NULL -> KtContractReturnsNotNullEffectDeclaration(builder.token) + ConeConstantReference.WILDCARD -> KtContractReturnsSuccessfullyEffectDeclaration(builder.token) + is ConeBooleanConstantReference -> KtContractReturnsSpecificValueEffectDeclaration( + KtContractConstantValue( + when (value) { + ConeBooleanConstantReference.TRUE -> KtContractConstantType.TRUE + ConeBooleanConstantReference.FALSE -> KtContractConstantType.FALSE + else -> error("Can't convert $value to the Analysis API") + }, + builder.token + ) + ) + else -> error("Can't convert $returnsEffect to the Analysis API") + } + + override fun visitCallsEffectDeclaration(callsEffect: ConeCallsEffectDeclaration, data: Unit): KtContractCallsInPlaceContractEffectDeclaration = + KtContractCallsInPlaceContractEffectDeclaration( + callsEffect.valueParameterReference.accept(), + callsEffect.kind + ) + + override fun visitLogicalBinaryOperationContractExpression( + binaryLogicExpression: ConeBinaryLogicExpression, + data: Unit + ): KtContractBinaryLogicExpression = KtContractBinaryLogicExpression( + binaryLogicExpression.left.accept(), + binaryLogicExpression.right.accept(), + when (binaryLogicExpression.kind) { + LogicOperationKind.AND -> KtContractBinaryLogicExpression.KtLogicOperation.AND + LogicOperationKind.OR -> KtContractBinaryLogicExpression.KtLogicOperation.OR + } + ) + + override fun visitLogicalNot(logicalNot: ConeLogicalNot, data: Unit): KtContractLogicalNotExpression = + KtContractLogicalNotExpression(logicalNot.arg.accept()) + + override fun visitIsInstancePredicate(isInstancePredicate: ConeIsInstancePredicate, data: Unit): KtContractIsInstancePredicateExpression = + KtContractIsInstancePredicateExpression( + isInstancePredicate.arg.accept(), + builder.typeBuilder.buildKtType(isInstancePredicate.type), + isInstancePredicate.isNegated + ) + + override fun visitIsNullPredicate(isNullPredicate: ConeIsNullPredicate, data: Unit): KtContractIsNullPredicateExpression = + KtContractIsNullPredicateExpression(isNullPredicate.arg.accept(), isNullPredicate.isNegated) + + override fun visitBooleanConstantDescriptor( + booleanConstantDescriptor: ConeBooleanConstantReference, + data: Unit + ): KtContractBooleanConstantExpression = + when (booleanConstantDescriptor) { + ConeBooleanConstantReference.TRUE -> KtContractBooleanConstantExpression(true, builder.token) + ConeBooleanConstantReference.FALSE -> KtContractBooleanConstantExpression(false, builder.token) + else -> error("Can't convert $booleanConstantDescriptor to Analysis API") + } + + override fun visitValueParameterReference( + valueParameterReference: ConeValueParameterReference, + data: Unit + ): Any = visitValueParameterReference(valueParameterReference, ::KtContractParameterValue) + + override fun visitBooleanValueParameterReference( + booleanValueParameterReference: ConeBooleanValueParameterReference, + data: Unit + ): Any = + visitValueParameterReference(booleanValueParameterReference, ::KtContractBooleanValueParameterExpression) + + private fun visitValueParameterReference( + valueParameterReference: ConeValueParameterReference, + constructor: (KtParameterSymbol) -> T + ): T = constructor( + if (valueParameterReference.parameterIndex == -1) firFunctionSymbol.receiverParameter + ?: error("$firFunctionSymbol should contain a receiver") + else firFunctionSymbol.valueParameters[valueParameterReference.parameterIndex] + ) + + // Util function to avoid hard coding names of the classes. Type inference will do a better job figuring out the best type to cast to. + // This visitor isn't type-safe anyway + private inline fun ConeContractDescriptionElement.accept() = + accept(this@ConeContractDescriptionElementToAnalysisApi, Unit) as T +} diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirFunctionSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirFunctionSymbol.kt index a660918b5df..97891cb0890 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirFunctionSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirFunctionSymbol.kt @@ -8,8 +8,10 @@ package org.jetbrains.kotlin.analysis.api.fir.symbols import com.intellij.psi.PsiElement import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.base.KtContextReceiver +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractEffectDeclaration import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder import org.jetbrains.kotlin.analysis.api.fir.annotations.KtFirAnnotationListForDeclaration +import org.jetbrains.kotlin.analysis.api.fir.contracts.coneEffectDeclarationToAnalysisApi import org.jetbrains.kotlin.analysis.api.fir.findPsi import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.FirCallableSignature import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirMemberFunctionSymbolPointer @@ -32,6 +34,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.containingClassLookupTag +import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol @@ -51,6 +54,13 @@ internal class KtFirFunctionSymbol( override val isBuiltinFunctionInvoke: Boolean get() = withValidityAssertion { callableIdIfNonLocal in kotlinFunctionInvokeCallableIds } + override val contractEffects: List by cached { + firSymbol.resolvedContractDescription?.effects + ?.map(FirEffectDeclaration::effect) + ?.map { it.coneEffectDeclarationToAnalysisApi(builder, this) } + .orEmpty() + } + override val returnType: KtType get() = withValidityAssertion { firSymbol.returnType(builder) } override val receiverParameter: KtReceiverParameterSymbol? get() = withValidityAssertion { firSymbol.receiver(builder) } override val contextReceivers: List by cached { firSymbol.createContextReceivers(builder) } diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java index 3cbeb901f6e..f35652f92ad 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java @@ -94,6 +94,118 @@ public class FirIdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated extends runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/setterWithAnnotations.kt"); } + @Nested + @TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts") + @TestDataPath("$PROJECT_ROOT") + public class Contracts { + @Test + public void testAllFilesPresentInContracts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("booleanConstReferenceInImplies.kt") + public void testBooleanConstReferenceInImplies() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.kt"); + } + + @Test + @TestMetadata("booleanExprContract.kt") + public void testBooleanExprContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceAtLeastOnceContract.kt") + public void testCallsInPlaceAtLeastOnceContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceAtMostOnceContract.kt") + public void testCallsInPlaceAtMostOnceContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceExactlyOnceContract.kt") + public void testCallsInPlaceExactlyOnceContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceUnknownContract.kt") + public void testCallsInPlaceUnknownContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.kt"); + } + + @Test + @TestMetadata("invalidContractParameterPassedToReturns.kt") + public void testInvalidContractParameterPassedToReturns() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.kt"); + } + + @Test + @TestMetadata("isInstancePredicateContract.kt") + public void testIsInstancePredicateContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.kt"); + } + + @Test + @TestMetadata("logicalNotContract.kt") + public void testLogicalNotContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.kt"); + } + + @Test + @TestMetadata("referenceBooleanReceiverInContract.kt") + public void testReferenceBooleanReceiverInContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.kt"); + } + + @Test + @TestMetadata("referenceReceiverInContract.kt") + public void testReferenceReceiverInContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.kt"); + } + + @Test + @TestMetadata("returnsContract.kt") + public void testReturnsContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.kt"); + } + + @Test + @TestMetadata("returnsFalseContract.kt") + public void testReturnsFalseContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.kt"); + } + + @Test + @TestMetadata("returnsNotNullContract.kt") + public void testReturnsNotNullContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.kt"); + } + + @Test + @TestMetadata("returnsNullContract.kt") + public void testReturnsNullContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.kt"); + } + + @Test + @TestMetadata("returnsTrueContract.kt") + public void testReturnsTrueContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.kt"); + } + + @Test + @TestMetadata("twoContracts.kt") + public void testTwoContracts() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.kt"); + } + } + @Nested @TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java index 88d74a9df38..c3bf5cee993 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSingleSymbolByPsiGenerated.java @@ -94,6 +94,118 @@ public class FirStandaloneNormalAnalysisSourceModuleSingleSymbolByPsiGenerated e runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/setterWithAnnotations.kt"); } + @Nested + @TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts") + @TestDataPath("$PROJECT_ROOT") + public class Contracts { + @Test + public void testAllFilesPresentInContracts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("booleanConstReferenceInImplies.kt") + public void testBooleanConstReferenceInImplies() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.kt"); + } + + @Test + @TestMetadata("booleanExprContract.kt") + public void testBooleanExprContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceAtLeastOnceContract.kt") + public void testCallsInPlaceAtLeastOnceContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceAtMostOnceContract.kt") + public void testCallsInPlaceAtMostOnceContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceExactlyOnceContract.kt") + public void testCallsInPlaceExactlyOnceContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.kt"); + } + + @Test + @TestMetadata("callsInPlaceUnknownContract.kt") + public void testCallsInPlaceUnknownContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.kt"); + } + + @Test + @TestMetadata("invalidContractParameterPassedToReturns.kt") + public void testInvalidContractParameterPassedToReturns() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.kt"); + } + + @Test + @TestMetadata("isInstancePredicateContract.kt") + public void testIsInstancePredicateContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.kt"); + } + + @Test + @TestMetadata("logicalNotContract.kt") + public void testLogicalNotContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.kt"); + } + + @Test + @TestMetadata("referenceBooleanReceiverInContract.kt") + public void testReferenceBooleanReceiverInContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.kt"); + } + + @Test + @TestMetadata("referenceReceiverInContract.kt") + public void testReferenceReceiverInContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.kt"); + } + + @Test + @TestMetadata("returnsContract.kt") + public void testReturnsContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.kt"); + } + + @Test + @TestMetadata("returnsFalseContract.kt") + public void testReturnsFalseContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.kt"); + } + + @Test + @TestMetadata("returnsNotNullContract.kt") + public void testReturnsNotNullContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.kt"); + } + + @Test + @TestMetadata("returnsNullContract.kt") + public void testReturnsNullContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.kt"); + } + + @Test + @TestMetadata("returnsTrueContract.kt") + public void testReturnsTrueContract() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.kt"); + } + + @Test + @TestMetadata("twoContracts.kt") + public void testTwoContracts() throws Exception { + runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.kt"); + } + } + @Nested @TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtContractDescriptionElementRenderer.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtContractDescriptionElementRenderer.kt new file mode 100644 index 00000000000..31e369e7fd1 --- /dev/null +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtContractDescriptionElementRenderer.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.contracts.description + +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractReturnsContractEffectDeclaration.* +import org.jetbrains.kotlin.analysis.api.contracts.description.booleans.* +import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer +import org.jetbrains.kotlin.analysis.api.symbols.KtParameterSymbol +import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter +import kotlin.reflect.KClass +import kotlin.reflect.KProperty + +internal fun Context.renderKtContractEffectDeclaration(value: KtContractEffectDeclaration, endWithNewLine: Boolean = true): Unit = + printer.appendHeader(value::class) { + when (value) { + is KtContractCallsInPlaceContractEffectDeclaration -> { + appendProperty(value::valueParameterReference, ::renderKtContractParameterValue) + appendSimpleProperty(value::occurrencesRange, endWithNewLine) + } + is KtContractConditionalContractEffectDeclaration -> { + appendProperty(value::effect, ::renderKtContractEffectDeclaration) + appendProperty(value::condition, ::renderKtContractBooleanExpression, endWithNewLine) + } + is KtContractReturnsContractEffectDeclaration -> { + when (value) { + is KtContractReturnsNotNullEffectDeclaration, is KtContractReturnsSuccessfullyEffectDeclaration -> Unit + is KtContractReturnsSpecificValueEffectDeclaration -> + appendProperty(value::value, ::renderKtContractConstantValue, endWithNewLine) + } + } + } + } + +private fun Context.renderKtContractConstantValue(value: KtContractConstantValue, endWithNewLine: Boolean = true): Unit = + printer.appendHeader(value::class) { + appendSimpleProperty(value::constantType, endWithNewLine) + } + +private fun Context.renderKtContractParameterValue(value: KtContractParameterValue, endWithNewLine: Boolean = true): Unit = + printer.appendHeader(value::class) { + appendProperty(value::parameterSymbol, ::renderKtParameterSymbol, endWithNewLine) + } + +private fun Context.renderKtContractBooleanExpression(value: KtContractBooleanExpression, endWithNewLine: Boolean = true): Unit = + printer.appendHeader(value::class) { + when (value) { + is KtContractLogicalNotExpression -> appendProperty(value::argument, ::renderKtContractBooleanExpression, endWithNewLine) + is KtContractBooleanConstantExpression -> appendSimpleProperty(value::booleanConstant, endWithNewLine) + is KtContractBinaryLogicExpression -> { + appendProperty(value::left, ::renderKtContractBooleanExpression) + appendProperty(value::right, ::renderKtContractBooleanExpression) + appendSimpleProperty(value::operation, endWithNewLine) + } + is KtContractIsInstancePredicateExpression -> { + appendProperty(value::argument, ::renderKtContractParameterValue) + appendProperty(value::type, renderer = { type, _ -> + appendLine(with(session) { symbolRenderer.renderType(type) }) + }) + appendSimpleProperty(value::isNegated, endWithNewLine) + } + is KtContractIsNullPredicateExpression -> { + appendProperty(value::argument, ::renderKtContractParameterValue) + appendSimpleProperty(value::isNegated, endWithNewLine) + } + is KtContractBooleanValueParameterExpression -> { + appendProperty(value::parameterSymbol, ::renderKtParameterSymbol, endWithNewLine) + } + } + } + +private fun Context.renderKtParameterSymbol(value: KtParameterSymbol, endWithNewLine: Boolean = true) { + val renderedValue = with(session) { symbolRenderer.render(value) } + if (endWithNewLine) printer.appendLine(renderedValue) else printer.append(renderedValue) +} + +internal data class Context(val session: KtAnalysisSession, val printer: PrettyPrinter, val symbolRenderer: DebugSymbolRenderer) + +private fun PrettyPrinter.appendHeader(clazz: KClass<*>, body: PrettyPrinter.() -> Unit) { + appendLine(clazz.simpleName + ":") + withIndent { body() } +} + +private fun PrettyPrinter.appendProperty( + prop: KProperty, + renderer: (T, Boolean) -> Unit, + endWithNewLine: Boolean = true +) { + appendLine(prop.name + ":") + withIndent { + renderer(prop.call(), endWithNewLine) + } +} + +private fun PrettyPrinter.appendSimpleProperty(prop: KProperty, endWithNewLine: Boolean = true) { + append(prop.name + ": ") + append(prop.call().toString()) + if (endWithNewLine) appendLine() +} diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtEffects.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtEffects.kt new file mode 100644 index 00000000000..304d696e294 --- /dev/null +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtEffects.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.contracts.description + +import com.google.common.base.Objects +import org.jetbrains.kotlin.analysis.api.contracts.description.booleans.KtContractBooleanExpression +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeOwner +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange + +/** + * Represents [kotlin.contracts.Effect]. + */ +public sealed interface KtContractEffectDeclaration : KtLifetimeOwner + +/** + * Represents [kotlin.contracts.ContractBuilder.callsInPlace]. + */ +public class KtContractCallsInPlaceContractEffectDeclaration( + private val _valueParameterReference: KtContractParameterValue, + private val _occurrencesRange: EventOccurrencesRange, +) : KtContractEffectDeclaration { + override val token: KtLifetimeToken get() = _valueParameterReference.token + + public val valueParameterReference: KtContractParameterValue get() = withValidityAssertion { _valueParameterReference } + public val occurrencesRange: EventOccurrencesRange get() = withValidityAssertion { _occurrencesRange } + + override fun hashCode(): Int = Objects.hashCode(_valueParameterReference, _occurrencesRange) + override fun equals(other: Any?): Boolean = + other is KtContractCallsInPlaceContractEffectDeclaration && other._valueParameterReference == _valueParameterReference && + other._occurrencesRange == _occurrencesRange +} + +/** + * Represents [kotlin.contracts.SimpleEffect.implies]. + */ +public class KtContractConditionalContractEffectDeclaration( + private val _effect: KtContractEffectDeclaration, + private val _condition: KtContractBooleanExpression +) : KtContractEffectDeclaration { + override val token: KtLifetimeToken get() = _effect.token + + public val effect: KtContractEffectDeclaration get() = withValidityAssertion { _effect } + public val condition: KtContractBooleanExpression get() = withValidityAssertion { _condition } + + override fun hashCode(): Int = Objects.hashCode(_effect, _condition) + override fun equals(other: Any?): Boolean = + other is KtContractConditionalContractEffectDeclaration && other._effect == _effect && other._condition == _condition +} + +/** + * Represents [kotlin.contracts.ContractBuilder.returnsNotNull] & [kotlin.contracts.ContractBuilder.returns]. + */ +public sealed class KtContractReturnsContractEffectDeclaration : KtContractEffectDeclaration { + /** + * Represent [kotlin.contracts.ContractBuilder.returnsNotNull]. + */ + public class KtContractReturnsNotNullEffectDeclaration( + override val token: KtLifetimeToken + ) : KtContractReturnsContractEffectDeclaration() { + override fun equals(other: Any?): Boolean = other is KtContractReturnsNotNullEffectDeclaration + override fun hashCode(): Int = javaClass.hashCode() + } + + /** + * Represents [kotlin.contracts.ContractBuilder.returns] with a `value` argument. + */ + public class KtContractReturnsSpecificValueEffectDeclaration( + private val _value: KtContractConstantValue + ) : KtContractReturnsContractEffectDeclaration() { + override val token: KtLifetimeToken get() = _value.token + public val value: KtContractConstantValue get() = withValidityAssertion { _value } + + override fun equals(other: Any?): Boolean = other is KtContractReturnsSpecificValueEffectDeclaration && other._value == _value + override fun hashCode(): Int = _value.hashCode() + } + + /** + * Represents [kotlin.contracts.ContractBuilder.returns] without arguments. + */ + public class KtContractReturnsSuccessfullyEffectDeclaration( + override val token: KtLifetimeToken + ) : KtContractReturnsContractEffectDeclaration() { + override fun equals(other: Any?): Boolean = other is KtContractReturnsSuccessfullyEffectDeclaration + override fun hashCode(): Int = javaClass.hashCode() + } +} diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtValues.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtValues.kt new file mode 100644 index 00000000000..21e72fed765 --- /dev/null +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/KtValues.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.contracts.description + +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeOwner +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.analysis.api.symbols.KtParameterSymbol + +/** + * Represents constant reference that can be passed to `value` argument of [kotlin.contracts.ContractBuilder.returns]. + * + * See: [org.jetbrains.kotlin.analysis.api.contracts.description.KtContractReturnsContractEffectDeclaration.KtContractReturnsSpecificValueEffectDeclaration.value] + */ +public class KtContractConstantValue( + private val _constantType: KtContractConstantType, + override val token: KtLifetimeToken, +) : KtLifetimeOwner { + public enum class KtContractConstantType { + NULL, TRUE, FALSE; + } + + public val constantType: KtContractConstantType get() = withValidityAssertion { _constantType } + + override fun equals(other: Any?): Boolean = other is KtContractConstantValue && other._constantType == _constantType + override fun hashCode(): Int = _constantType.hashCode() +} + +/** + * Represents parameter that can be passed to `value` argument of [kotlin.contracts.ContractBuilder.callsInPlace]. + */ +public class KtContractParameterValue(private val _parameterSymbol: KtParameterSymbol) : KtLifetimeOwner { + override val token: KtLifetimeToken get() = _parameterSymbol.token + public val parameterSymbol: KtParameterSymbol get() = withValidityAssertion { _parameterSymbol } + + override fun hashCode(): Int = _parameterSymbol.hashCode() + override fun equals(other: Any?): Boolean = other is KtContractParameterValue && other._parameterSymbol == _parameterSymbol +} diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtContractBooleanExpression.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtContractBooleanExpression.kt new file mode 100644 index 00000000000..93664c784dc --- /dev/null +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtContractBooleanExpression.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.contracts.description.booleans + +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeOwner +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.analysis.api.symbols.KtParameterSymbol + +/** + * Represents `booleanExpression` argument of [kotlin.contracts.SimpleEffect.implies]. + * + * `booleanExpression` forms a boolean condition for + * [org.jetbrains.kotlin.analysis.api.contracts.description.KtContractConditionalContractEffectDeclaration]. See + * [org.jetbrains.kotlin.analysis.api.contracts.description.KtContractConditionalContractEffectDeclaration.condition] + */ +public sealed interface KtContractBooleanExpression : KtLifetimeOwner + +/** + * Represents boolean parameter reference passed to `booleanExpression` argument of [kotlin.contracts.SimpleEffect.implies]. + */ +public class KtContractBooleanValueParameterExpression( + private val _parameterSymbol: KtParameterSymbol +) : KtContractBooleanExpression { + override val token: KtLifetimeToken get() = _parameterSymbol.token + public val parameterSymbol: KtParameterSymbol get() = withValidityAssertion { _parameterSymbol } + override fun hashCode(): Int = _parameterSymbol.hashCode() + override fun equals(other: Any?): Boolean = + other is KtContractBooleanValueParameterExpression && other._parameterSymbol == _parameterSymbol +} + +/** + * Represents boolean constant reference. The boolean constant can be passed to `booleanExpression` argument of + * [kotlin.contracts.SimpleEffect.implies]. + */ +public class KtContractBooleanConstantExpression( + private val _booleanConstant: Boolean, + override val token: KtLifetimeToken +) : KtContractBooleanExpression { + public val booleanConstant: Boolean get() = withValidityAssertion { _booleanConstant } + + override fun equals(other: Any?): Boolean = other is KtContractBooleanConstantExpression && other._booleanConstant == _booleanConstant + override fun hashCode(): Int = _booleanConstant.hashCode() +} diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtLogicalCombinators.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtLogicalCombinators.kt new file mode 100644 index 00000000000..bda0a7b09a2 --- /dev/null +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtLogicalCombinators.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.contracts.description.booleans + +import com.google.common.base.Objects +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion + +/** + * See: [KtContractBooleanExpression]. + */ +public class KtContractBinaryLogicExpression( + private val _left: KtContractBooleanExpression, + private val _right: KtContractBooleanExpression, + private val _operation: KtLogicOperation +) : KtContractBooleanExpression { + init { + check(left.token === right.token) { "$left and $right should have the same lifetime token" } + } + + override val token: KtLifetimeToken get() = _left.token + public val left: KtContractBooleanExpression get() = withValidityAssertion { _left } + public val right: KtContractBooleanExpression get() = withValidityAssertion { _right } + public val operation: KtLogicOperation get() = withValidityAssertion { _operation } + + override fun hashCode(): Int = Objects.hashCode(_left, _right, _operation) + override fun equals(other: Any?): Boolean = + other is KtContractBinaryLogicExpression && other._left == _left && other._right == _right && other._operation == _operation + + public enum class KtLogicOperation { + AND, OR + } +} + +/** + * See: [KtContractBooleanExpression]. + */ +public class KtContractLogicalNotExpression(private val _argument: KtContractBooleanExpression) : KtContractBooleanExpression { + override val token: KtLifetimeToken get() = _argument.token + public val argument: KtContractBooleanExpression get() = withValidityAssertion { _argument } + + override fun equals(other: Any?): Boolean = other is KtContractLogicalNotExpression && other._argument == _argument + override fun hashCode(): Int = _argument.hashCode() +} diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtPredicates.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtPredicates.kt new file mode 100644 index 00000000000..0907a4a52ba --- /dev/null +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/contracts/description/booleans/KtPredicates.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.api.contracts.description.booleans + +import com.google.common.base.Objects +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractParameterValue +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.analysis.api.types.KtType + +/** + * See: [KtContractBooleanExpression]. + */ +public class KtContractIsInstancePredicateExpression( + private val _argument: KtContractParameterValue, + private val _type: KtType, + private val _isNegated: Boolean +) : KtContractBooleanExpression { + override val token: KtLifetimeToken get() = _type.token + public val argument: KtContractParameterValue get() = withValidityAssertion { _argument } + public val type: KtType get() = withValidityAssertion { _type } + public val isNegated: Boolean get() = withValidityAssertion { _isNegated } + public fun negated(): KtContractIsInstancePredicateExpression = KtContractIsInstancePredicateExpression(argument, type, !isNegated) + + override fun hashCode(): Int = Objects.hashCode(_argument, _type, _isNegated) + override fun equals(other: Any?): Boolean = + other is KtContractIsInstancePredicateExpression && other._argument == _argument && other._type == _type && other._isNegated + && _isNegated +} + +/** + * See: [KtContractBooleanExpression]. + */ +public class KtContractIsNullPredicateExpression( + private val _argument: KtContractParameterValue, + private val _isNegated: Boolean +) : KtContractBooleanExpression { + override val token: KtLifetimeToken get() = _argument.token + public val argument: KtContractParameterValue get() = withValidityAssertion { _argument } + public val isNegated: Boolean get() = withValidityAssertion { _isNegated } + public fun negated(): KtContractIsNullPredicateExpression = KtContractIsNullPredicateExpression(argument, !isNegated) + + override fun hashCode(): Int = Objects.hashCode(_argument, _isNegated) + override fun equals(other: Any?): Boolean = + other is KtContractIsNullPredicateExpression && other._argument == _argument && other._isNegated == _isNegated +} diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/DebugSymbolRenderer.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/DebugSymbolRenderer.kt index 601cf7e8033..370dfcc1569 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/DebugSymbolRenderer.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/DebugSymbolRenderer.kt @@ -11,6 +11,9 @@ import org.jetbrains.kotlin.analysis.api.annotations.* import org.jetbrains.kotlin.analysis.api.base.KtContextReceiver import org.jetbrains.kotlin.analysis.api.components.KtSymbolContainingDeclarationProviderMixIn import org.jetbrains.kotlin.analysis.api.components.KtSymbolInfoProviderMixIn +import org.jetbrains.kotlin.analysis.api.contracts.description.Context +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractEffectDeclaration +import org.jetbrains.kotlin.analysis.api.contracts.description.renderKtContractEffectDeclaration import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossiblyNamedSymbol import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType @@ -227,6 +230,8 @@ public class DebugSymbolRenderer( is KtSymbol -> renderSymbolTag(value, renderSymbolsFully) is KtType -> renderType(value) is KtAnnotationValue -> renderAnnotationValue(value) + is KtContractEffectDeclaration -> Context(this@KtAnalysisSession, this@renderValue, this@DebugSymbolRenderer) + .renderKtContractEffectDeclaration(value, endWithNewLine = false) is KtNamedAnnotationValue -> renderNamedConstantValue(value) is KtInitializerValue -> renderKtInitializerValue(value) is KtContextReceiver -> rendeContextReceiver(value) diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtCallableSymbol.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtCallableSymbol.kt index 120796faceb..07db0857d0b 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtCallableSymbol.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtCallableSymbol.kt @@ -32,7 +32,7 @@ public val KtCallableSymbol.receiverType: KtType? * Symbol for a receiver parameter of a function or property. For example, consider code `fun String.foo() {...}`, the declaration of * `String` receiver parameter is such a symbol. */ -public abstract class KtReceiverParameterSymbol : KtAnnotatedSymbol { +public abstract class KtReceiverParameterSymbol : KtAnnotatedSymbol, KtParameterSymbol { public abstract val type: KtType /** diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtFunctionLikeSymbol.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtFunctionLikeSymbol.kt index 234fb2d2a74..9cc865e946f 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtFunctionLikeSymbol.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtFunctionLikeSymbol.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.api.symbols import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.base.KtContextReceiver +import org.jetbrains.kotlin.analysis.api.contracts.description.KtContractEffectDeclaration import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.markers.* import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer @@ -58,6 +59,7 @@ public abstract class KtFunctionSymbol : KtFunctionLikeSymbol(), public abstract val isOverride: Boolean public abstract val isInfix: Boolean public abstract val isStatic: Boolean + public abstract val contractEffects: List /** * Whether this symbol is the `invoke` method defined on the Kotlin builtin functional type. diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt index 0bbed677b36..4f2c96adb95 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt @@ -176,7 +176,10 @@ public abstract class KtLocalVariableSymbol : KtVariableSymbol(), KtSymbolWithKi abstract override fun createPointer(): KtSymbolPointer } -public abstract class KtValueParameterSymbol : KtVariableLikeSymbol(), KtSymbolWithKind, KtAnnotatedSymbol { +// TODO design common ancestor of parameter and receiver KTIJ-23745 +public sealed interface KtParameterSymbol : KtAnnotatedSymbol + +public abstract class KtValueParameterSymbol : KtVariableLikeSymbol(), KtParameterSymbol, KtSymbolWithKind, KtAnnotatedSymbol { final override val symbolKind: KtSymbolKind get() = withValidityAssertion { KtSymbolKind.LOCAL } final override val callableIdIfNonLocal: CallableId? get() = withValidityAssertion { null } final override val isExtension: Boolean get() = withValidityAssertion { false } diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.kt new file mode 100644 index 00000000000..97069f2da64 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun booleanConstReferenceInImplies(): Boolean { + contract { + returns(true) implies true + } + return true +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.pretty.txt new file mode 100644 index 00000000000..5f2a65eb4b8 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun booleanConstReferenceInImplies(): kotlin.Boolean \ No newline at end of file diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.txt new file mode 100644 index 00000000000..0be56fa69c1 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanConstReferenceInImplies.txt @@ -0,0 +1,39 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /booleanConstReferenceInImplies + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSpecificValueEffectDeclaration: + value: + KtContractConstantValue: + constantType: TRUE + condition: + KtContractBooleanConstantExpression: + booleanConstant: true + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: booleanConstReferenceInImplies + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.kt new file mode 100644 index 00000000000..e71756b0f26 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun boolenExprContract(foo: Any?, bar: Any?): Boolean { + contract { + returns(true) implies (foo == null && bar != null) + } + return foo == null && bar != null +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.pretty.txt new file mode 100644 index 00000000000..29ab9668a5c --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun boolenExprContract(foo: kotlin.Any?, bar: kotlin.Any?): kotlin.Boolean diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.txt new file mode 100644 index 00000000000..c72f0a491f5 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/booleanExprContract.txt @@ -0,0 +1,128 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /boolenExprContract + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSpecificValueEffectDeclaration: + value: + KtContractConstantValue: + constantType: TRUE + condition: + KtContractBinaryLogicExpression: + left: + KtContractIsNullPredicateExpression: + argument: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + isNegated: false + right: + KtContractIsNullPredicateExpression: + argument: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: bar + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + isNegated: true + operation: AND + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: boolenExprContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: bar + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.kt new file mode 100644 index 00000000000..99ab434bac9 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun atLeastOnceContract(block: () -> Unit) { + contract { + callsInPlace(block, InvocationKind.AT_LEAST_ONCE) + } + block() +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.pretty.txt new file mode 100644 index 00000000000..a57c1ffd2a3 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun atLeastOnceContract(block: () -> kotlin.Unit) diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.txt new file mode 100644 index 00000000000..695b7be9135 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtLeastOnceContract.txt @@ -0,0 +1,74 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /atLeastOnceContract + contextReceivers: [] + contractEffects: [ + KtContractCallsInPlaceContractEffectDeclaration: + valueParameterReference: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + occurrencesRange: AT_LEAST_ONCE + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: atLeastOnceContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.kt new file mode 100644 index 00000000000..f31ad8132b0 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun atMostOnceContract(block: () -> Unit) { + contract { + callsInPlace(block, InvocationKind.AT_MOST_ONCE) + } + block() +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.pretty.txt new file mode 100644 index 00000000000..40ba1986f76 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun atMostOnceContract(block: () -> kotlin.Unit) diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.txt new file mode 100644 index 00000000000..5e3095eaa70 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceAtMostOnceContract.txt @@ -0,0 +1,74 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /atMostOnceContract + contextReceivers: [] + contractEffects: [ + KtContractCallsInPlaceContractEffectDeclaration: + valueParameterReference: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + occurrencesRange: AT_MOST_ONCE + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: atMostOnceContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.kt new file mode 100644 index 00000000000..f753f083281 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun exactlyOnceContract(block: () -> Unit) { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.pretty.txt new file mode 100644 index 00000000000..c7bbf8f3e18 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun exactlyOnceContract(block: () -> kotlin.Unit) diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.txt new file mode 100644 index 00000000000..f802c8ef788 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceExactlyOnceContract.txt @@ -0,0 +1,74 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /exactlyOnceContract + contextReceivers: [] + contractEffects: [ + KtContractCallsInPlaceContractEffectDeclaration: + valueParameterReference: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + occurrencesRange: EXACTLY_ONCE + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: exactlyOnceContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.kt new file mode 100644 index 00000000000..de3f6e5838b --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun unknownContract(block: () -> Unit) { + contract { + callsInPlace(block, InvocationKind.UNKNOWN) + } + block() +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.pretty.txt new file mode 100644 index 00000000000..f748e577f34 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun unknownContract(block: () -> kotlin.Unit) diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.txt new file mode 100644 index 00000000000..dce2460b0e2 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/callsInPlaceUnknownContract.txt @@ -0,0 +1,74 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /unknownContract + contextReceivers: [] + contractEffects: [ + KtContractCallsInPlaceContractEffectDeclaration: + valueParameterReference: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + occurrencesRange: UNKNOWN + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: unknownContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.kt new file mode 100644 index 00000000000..f27fd689097 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun invalidContract(foo: Any, bar: Boolean) { + contract { + returns(foo) implies bar + } + return if (bar) foo else null +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.pretty.txt new file mode 100644 index 00000000000..bb3a22e5b2e --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun invalidContract(foo: kotlin.Any, bar: kotlin.Boolean) diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.txt new file mode 100644 index 00000000000..f7a5b36cd2c --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/invalidContractParameterPassedToReturns.txt @@ -0,0 +1,68 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /invalidContract + contextReceivers: [] + contractEffects: [] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: invalidContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: bar + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.kt new file mode 100644 index 00000000000..9aaa4597fbd --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.kt @@ -0,0 +1,17 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +class Foo + +@OptIn(ExperimentalContracts::class) +fun isInstancePredicateContract(value: Any) { + contract { + returns() implies (value is Foo) + } + if (value !is Foo) { + throw IllegalStateException() + } +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.pretty.txt new file mode 100644 index 00000000000..d36304ff5a1 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun isInstancePredicateContract(value: kotlin.Any) \ No newline at end of file diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.txt new file mode 100644 index 00000000000..d88afd15362 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/isInstancePredicateContract.txt @@ -0,0 +1,80 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /isInstancePredicateContract + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSuccessfullyEffectDeclaration: + condition: + KtContractIsInstancePredicateExpression: + argument: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: value + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + type: + Foo + isNegated: false + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: isInstancePredicateContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: value + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.kt new file mode 100644 index 00000000000..e8e82b22705 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.kt @@ -0,0 +1,15 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun logicalNotContract(value: Boolean) { + contract { + returns() implies !value + } + if (value) { + throw IllegalStateException() + } +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.pretty.txt new file mode 100644 index 00000000000..67163c8060e --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun logicalNotContract(value: kotlin.Boolean) diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.txt new file mode 100644 index 00000000000..02c58b20b60 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/logicalNotContract.txt @@ -0,0 +1,77 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /logicalNotContract + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSuccessfullyEffectDeclaration: + condition: + KtContractLogicalNotExpression: + argument: + KtContractBooleanValueParameterExpression: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: value + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: logicalNotContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: value + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.kt new file mode 100644 index 00000000000..c92464b78dd --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.kt @@ -0,0 +1,14 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import java.lang.IllegalStateException +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun Boolean.referenceReceiverInContract() { + contract { + returns() implies this@referenceReceiverInContract + } + if (!this) throw IllegalStateException() +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.pretty.txt new file mode 100644 index 00000000000..2ec14fa5f80 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun kotlin.Boolean.referenceReceiverInContract() diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.txt new file mode 100644 index 00000000000..7a5c6283380 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceBooleanReceiverInContract.txt @@ -0,0 +1,49 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /referenceReceiverInContract + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSuccessfullyEffectDeclaration: + condition: + KtContractBooleanValueParameterExpression: + parameterSymbol: + KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtFunctionSymbol(/referenceReceiverInContract) + type: kotlin/Boolean + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: true + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: referenceReceiverInContract + origin: SOURCE + receiverParameter: KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtFunctionSymbol(/referenceReceiverInContract) + type: kotlin/Boolean + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.kt new file mode 100644 index 00000000000..f5bb206bbbd --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun (() -> Unit).referenceReceiverInContract() { + contract { + callsInPlace(this@referenceReceiverInContract, InvocationKind.EXACTLY_ONCE) + } + this() +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.pretty.txt new file mode 100644 index 00000000000..ec13443d646 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun () -> kotlin.Unit.referenceReceiverInContract() diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.txt new file mode 100644 index 00000000000..c0986b7846b --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/referenceReceiverInContract.txt @@ -0,0 +1,48 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /referenceReceiverInContract + contextReceivers: [] + contractEffects: [ + KtContractCallsInPlaceContractEffectDeclaration: + valueParameterReference: + KtContractParameterValue: + parameterSymbol: + KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtFunctionSymbol(/referenceReceiverInContract) + type: kotlin/Function0 + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + occurrencesRange: EXACTLY_ONCE + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: true + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: referenceReceiverInContract + origin: SOURCE + receiverParameter: KtReceiverParameterSymbol: + annotationsList: [] + origin: SOURCE + owningCallableSymbol: KtFunctionSymbol(/referenceReceiverInContract) + type: kotlin/Function0 + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.kt new file mode 100644 index 00000000000..08deb1d87da --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.kt @@ -0,0 +1,15 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +inline fun check(value: Boolean) { + contract { + returns() implies value + } + if (!value) { + throw IllegalStateException() + } +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.pretty.txt new file mode 100644 index 00000000000..3d08dc47be2 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +inline fun check(value: kotlin.Boolean) diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.txt new file mode 100644 index 00000000000..1e841afb304 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsContract.txt @@ -0,0 +1,75 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /check + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSuccessfullyEffectDeclaration: + condition: + KtContractBooleanValueParameterExpression: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: value + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: true + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: check + origin: SOURCE + receiverParameter: null + returnType: kotlin/Unit + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: value + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.kt new file mode 100644 index 00000000000..8b807204b4c --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun returnsFalseContract(foo: Any?): Boolean { + contract { + returns(false) implies (foo != null) + } + return foo == null +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.pretty.txt new file mode 100644 index 00000000000..6f2a663c8fc --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun returnsFalseContract(foo: kotlin.Any?): kotlin.Boolean diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.txt new file mode 100644 index 00000000000..c9f5c9ab1f7 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsFalseContract.txt @@ -0,0 +1,81 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /returnsFalseContract + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSpecificValueEffectDeclaration: + value: + KtContractConstantValue: + constantType: FALSE + condition: + KtContractIsNullPredicateExpression: + argument: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + isNegated: true + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: returnsFalseContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.kt new file mode 100644 index 00000000000..1dbcdd03302 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun returnsNotNullContract(foo: Any?): Any? { + contract { + returnsNotNull() implies (foo != null) + } + return foo +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.pretty.txt new file mode 100644 index 00000000000..15d2922b163 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun returnsNotNullContract(foo: kotlin.Any?): kotlin.Any? diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.txt new file mode 100644 index 00000000000..f87f239e1c9 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNotNullContract.txt @@ -0,0 +1,78 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /returnsNotNullContract + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsNotNullEffectDeclaration: + condition: + KtContractIsNullPredicateExpression: + argument: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + isNegated: true + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: returnsNotNullContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.kt new file mode 100644 index 00000000000..55cada7dddd --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun returnsNullContract(foo: Any?): Any? { + contract { + returns(null) implies (foo == null) + } + return foo +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.pretty.txt new file mode 100644 index 00000000000..57141378bd3 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun returnsNullContract(foo: kotlin.Any?): kotlin.Any? diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.txt new file mode 100644 index 00000000000..40df1264434 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsNullContract.txt @@ -0,0 +1,81 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /returnsNullContract + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSpecificValueEffectDeclaration: + value: + KtContractConstantValue: + constantType: NULL + condition: + KtContractIsNullPredicateExpression: + argument: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + isNegated: false + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: returnsNullContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.kt new file mode 100644 index 00000000000..7fcdd107eb4 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.kt @@ -0,0 +1,13 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun returnsTrueContract(foo: Any?): Boolean { + contract { + returns(true) implies (foo == null) + } + return foo == null +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.pretty.txt new file mode 100644 index 00000000000..ed69ae96637 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun returnsTrueContract(foo: kotlin.Any?): kotlin.Boolean diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.txt new file mode 100644 index 00000000000..70541620058 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/returnsTrueContract.txt @@ -0,0 +1,81 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /returnsTrueContract + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSpecificValueEffectDeclaration: + value: + KtContractConstantValue: + constantType: TRUE + condition: + KtContractIsNullPredicateExpression: + argument: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + isNegated: false + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: returnsTrueContract + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.kt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.kt new file mode 100644 index 00000000000..f13b0753926 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.kt @@ -0,0 +1,15 @@ +// WITH_STDLIB +// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE_K1 +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun twoContracts(foo: Any?, bar: Any?, block: () -> Unit): Boolean { + contract { + returns(true) implies (foo == null && bar != null) + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + return foo == null && bar != null +} diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.pretty.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.pretty.txt new file mode 100644 index 00000000000..8cfe5ae0d9e --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.pretty.txt @@ -0,0 +1,2 @@ +@kotlin.OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) +fun twoContracts(foo: kotlin.Any?, bar: kotlin.Any?, block: () -> kotlin.Unit): kotlin.Boolean diff --git a/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.txt b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.txt new file mode 100644 index 00000000000..c32a586f5a4 --- /dev/null +++ b/analysis/analysis-api/testData/symbols/singleSymbolByPsi/contracts/twoContracts.txt @@ -0,0 +1,171 @@ +KtFunctionSymbol: + annotationsList: [ + kotlin/OptIn(markerClass = [kotlin.contracts.ExperimentalContracts::class]) + psi: KtAnnotationEntry + ] + callableIdIfNonLocal: /twoContracts + contextReceivers: [] + contractEffects: [ + KtContractConditionalContractEffectDeclaration: + effect: + KtContractReturnsSpecificValueEffectDeclaration: + value: + KtContractConstantValue: + constantType: TRUE + condition: + KtContractBinaryLogicExpression: + left: + KtContractIsNullPredicateExpression: + argument: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + isNegated: false + right: + KtContractIsNullPredicateExpression: + argument: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: bar + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + isNegated: true + operation: AND + KtContractCallsInPlaceContractEffectDeclaration: + valueParameterReference: + KtContractParameterValue: + parameterSymbol: + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + occurrencesRange: EXACTLY_ONCE + ] + hasStableParameterNames: true + isBuiltinFunctionInvoke: false + isExtension: false + isExternal: false + isInfix: false + isInline: false + isOperator: false + isOverride: false + isStatic: false + isSuspend: false + modality: FINAL + name: twoContracts + origin: SOURCE + receiverParameter: null + returnType: kotlin/Boolean + symbolKind: TOP_LEVEL + typeParameters: [] + valueParameters: [ + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: foo + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: bar + origin: SOURCE + receiverParameter: null + returnType: kotlin/Any? + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + KtValueParameterSymbol: + annotationsList: [] + callableIdIfNonLocal: null + contextReceivers: [] + generatedPrimaryConstructorProperty: null + hasDefaultValue: false + isCrossinline: false + isExtension: false + isImplicitLambdaParameter: false + isNoinline: false + isVararg: false + name: block + origin: SOURCE + receiverParameter: null + returnType: kotlin/Function0 + symbolKind: LOCAL + typeParameters: [] + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null + ] + visibility: Public + getContainingModule: KtSourceModule "Sources of main" + deprecationStatus: null