From 0fb853a995d1c561326f3b9d0718a72677d862f1 Mon Sep 17 00:00:00 2001 From: Vladimir Sukharev Date: Thu, 2 Nov 2023 20:47:05 +0000 Subject: [PATCH] [FIR] Fix Disappeared CONTRACT_NOT_ALLOWED https://youtrack.jetbrains.com/issue/KT-60004/K2-Disappeared-CONTRACTNOTALLOWED Merge-request: KT-MR-12613 Merged-by: Vladimir Sukharev --- ...CompilerTestFE10TestdataTestGenerated.java | 48 +++++++++++ ...sticCompilerFE10TestDataTestGenerated.java | 48 +++++++++++ ...eeOldFrontendDiagnosticsTestGenerated.java | 48 +++++++++++ ...siOldFrontendDiagnosticsTestGenerated.java | 48 +++++++++++ .../FirContractNotFirstStatementChecker.kt | 8 ++ .../LightTreeRawFirDeclarationBuilder.kt | 14 +++- .../kotlin/fir/builder/PsiRawFirBuilder.kt | 13 ++- .../kotlin/fir/analysis/Traversals.kt | 33 ++++++++ .../kotlin/fir/builder/ConversionUtils.kt | 10 +-- ...actContractResolveTransformerDispatcher.kt | 1 + .../FirLegacyRawContractDescription.kt | 2 + .../FirResolvedContractDescription.kt | 2 + .../FirLegacyRawContractDescriptionBuilder.kt | 3 + .../FirResolvedContractDescriptionBuilder.kt | 3 + .../FirLegacyRawContractDescriptionImpl.kt | 2 + .../FirResolvedContractDescriptionImpl.kt | 2 + .../fir/diagnostics/ConeSimpleDiagnostic.kt | 4 + .../fir/tree/generator/NodeConfigurator.kt | 2 + .../diagnostics/tests/contracts/neg/14.fir.kt | 23 ++++++ .../diagnostics/tests/contracts/neg/14.kt | 23 ++++++ .../diagnostics/tests/contracts/pos/1.kt | 20 +++++ .../tests/contracts/pos/14UserDefined.fir.kt | 82 +++++++++++++++++++ .../tests/contracts/pos/14UserDefined.kt | 82 +++++++++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 48 +++++++++++ .../contractBuilder/common/neg/14.fir.kt | 4 +- 25 files changed, 564 insertions(+), 9 deletions(-) create mode 100644 compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/analysis/Traversals.kt create mode 100644 compiler/testData/diagnostics/tests/contracts/neg/14.fir.kt create mode 100644 compiler/testData/diagnostics/tests/contracts/neg/14.kt create mode 100644 compiler/testData/diagnostics/tests/contracts/pos/1.kt create mode 100644 compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.fir.kt create mode 100644 compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index b7dd5e0fb37..1b3c597d975 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -6645,6 +6645,54 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts") + @TestDataPath("$PROJECT_ROOT") + public class Contracts { + @Test + public void testAllFilesPresentInContracts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/neg") + @TestDataPath("$PROJECT_ROOT") + public class Neg { + @Test + @TestMetadata("14.kt") + public void test14() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/neg/14.kt"); + } + + @Test + public void testAllFilesPresentInNeg() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/neg"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/pos") + @TestDataPath("$PROJECT_ROOT") + public class Pos { + @Test + @TestMetadata("1.kt") + public void test1() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/1.kt"); + } + + @Test + @TestMetadata("14UserDefined.kt") + public void test14UserDefined() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.kt"); + } + + @Test + public void testAllFilesPresentInPos() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/pos"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index dc938e96ff0..01eee7c15e6 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -6645,6 +6645,54 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts") + @TestDataPath("$PROJECT_ROOT") + public class Contracts { + @Test + public void testAllFilesPresentInContracts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/neg") + @TestDataPath("$PROJECT_ROOT") + public class Neg { + @Test + @TestMetadata("14.kt") + public void test14() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/neg/14.kt"); + } + + @Test + public void testAllFilesPresentInNeg() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/neg"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/pos") + @TestDataPath("$PROJECT_ROOT") + public class Pos { + @Test + @TestMetadata("1.kt") + public void test1() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/1.kt"); + } + + @Test + @TestMetadata("14UserDefined.kt") + public void test14UserDefined() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.kt"); + } + + @Test + public void testAllFilesPresentInPos() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/pos"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index 1ebd6f85001..3fe86efd2da 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -6639,6 +6639,54 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts") + @TestDataPath("$PROJECT_ROOT") + public class Contracts { + @Test + public void testAllFilesPresentInContracts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/neg") + @TestDataPath("$PROJECT_ROOT") + public class Neg { + @Test + @TestMetadata("14.kt") + public void test14() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/neg/14.kt"); + } + + @Test + public void testAllFilesPresentInNeg() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/neg"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/pos") + @TestDataPath("$PROJECT_ROOT") + public class Pos { + @Test + @TestMetadata("1.kt") + public void test1() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/1.kt"); + } + + @Test + @TestMetadata("14UserDefined.kt") + public void test14UserDefined() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.kt"); + } + + @Test + public void testAllFilesPresentInPos() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/pos"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index f0dba44b2aa..a5e6db89800 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -6645,6 +6645,54 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts") + @TestDataPath("$PROJECT_ROOT") + public class Contracts { + @Test + public void testAllFilesPresentInContracts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/neg") + @TestDataPath("$PROJECT_ROOT") + public class Neg { + @Test + @TestMetadata("14.kt") + public void test14() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/neg/14.kt"); + } + + @Test + public void testAllFilesPresentInNeg() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/neg"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/pos") + @TestDataPath("$PROJECT_ROOT") + public class Pos { + @Test + @TestMetadata("1.kt") + public void test1() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/1.kt"); + } + + @Test + @TestMetadata("14UserDefined.kt") + public void test14UserDefined() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.kt"); + } + + @Test + public void testAllFilesPresentInPos() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/pos"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); + } + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirContractNotFirstStatementChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirContractNotFirstStatementChecker.kt index 378bb3e2fe0..67a0cf8329a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirContractNotFirstStatementChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirContractNotFirstStatementChecker.kt @@ -9,7 +9,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.contracts.FirContractDescription +import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription +import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner import org.jetbrains.kotlin.fir.declarations.FirFunction +import org.jetbrains.kotlin.fir.diagnostics.ConeContractShouldBeFirstStatement import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock @@ -35,5 +39,9 @@ object FirContractNotFirstStatementChecker : FirFunctionCallChecker() { private fun FirFunctionCall.isCorrectlyPlacedIn(functionDeclaration: FirFunction): Boolean { val firstStatement = functionDeclaration.body?.statements?.first() return firstStatement is FirContractCallBlock && firstStatement.call == this + && !(functionDeclaration is FirContractDescriptionOwner && functionDeclaration.contractDescription.isNonFirstStatement) } + + private val FirContractDescription.isNonFirstStatement: Boolean + get() = this is FirResolvedContractDescription && diagnostic == ConeContractShouldBeFirstStatement } diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt index 23cb42580cc..c68503f50ad 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.* import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.analysis.isCallTheFirstStatement import org.jetbrains.kotlin.fir.builder.* import org.jetbrains.kotlin.fir.contracts.FirContractDescription import org.jetbrains.kotlin.fir.contracts.builder.buildRawContractDescription @@ -53,6 +54,7 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes +import org.jetbrains.kotlin.util.getChildren import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.runUnless @@ -1818,7 +1820,14 @@ class LightTreeRawFirDeclarationBuilder( return when { blockNode != null -> { val block = convertBlock(blockNode) - val contractDescription = runIf(allowLegacyContractDescription) { processLegacyContractDescription(block) } + val contractDescription = runIf(allowLegacyContractDescription) { + val blockSource = block.source + val diagnostic = when { + blockSource == null || !isCallTheFirstStatement(blockSource) -> ConeContractShouldBeFirstStatement + else -> null + } + processLegacyContractDescription(block, diagnostic) + } block to contractDescription } expression != null -> FirSingleExpressionBlock( @@ -1828,6 +1837,9 @@ class LightTreeRawFirDeclarationBuilder( } } + private fun isCallTheFirstStatement(sourceElement: KtSourceElement): Boolean = + isCallTheFirstStatement(sourceElement.lighterASTNode, { it.elementType }, { it.getChildren(sourceElement.treeStructure) }) + /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlock */ diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt index 8bffd56120f..bebf852602e 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.builtins.StandardNames.BACKING_FIELD import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.* import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.analysis.isCallTheFirstStatement import org.jetbrains.kotlin.fir.contracts.FirContractDescription import org.jetbrains.kotlin.fir.contracts.builder.buildRawContractDescription import org.jetbrains.kotlin.fir.declarations.* @@ -419,7 +420,14 @@ open class PsiRawFirBuilder( if (hasBlockBody()) { val block = bodyBlockExpression?.accept(this@Visitor, null) as? FirBlock val contractDescription = when { - !hasContractEffectList() -> block?.let(::processLegacyContractDescription) + !hasContractEffectList() -> block?.let { + val blockSourcePsi = it.source?.psi + val diagnostic = when { + blockSourcePsi == null || !isCallTheFirstStatement(blockSourcePsi) -> ConeContractShouldBeFirstStatement + else -> null + } + processLegacyContractDescription(block, diagnostic) + } else -> null } return@buildFirBody block to contractDescription @@ -432,6 +440,9 @@ open class PsiRawFirBuilder( null to null } + private fun isCallTheFirstStatement(psi: PsiElement): Boolean = + isCallTheFirstStatement(psi, { it.elementType }, { it.allChildren.toList() }) + private fun ValueArgument?.toFirExpression(): FirExpression { if (this == null) { return buildErrorExpression( diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/analysis/Traversals.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/analysis/Traversals.kt new file mode 100644 index 00000000000..a039e27483b --- /dev/null +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/analysis/Traversals.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2023 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.fir.analysis + +import com.intellij.psi.tree.IElementType +import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.utils.addToStdlib.popLast + +inline fun isCallTheFirstStatement( + root: T, + getElementType: (T) -> IElementType, + getChildren: (T) -> List, +): Boolean { + val stack = getChildren(root).asReversed().toMutableList() + + while (stack.isNotEmpty()) { + val child = stack.popLast() + when (getElementType(child)) { + KtTokens.LBRACE, KtTokens.WHITE_SPACE, KtTokens.DOT, KtTokens.EOL_COMMENT -> {} + KtNodeTypes.CALL_EXPRESSION -> return true + KtNodeTypes.REFERENCE_EXPRESSION -> {} + KtNodeTypes.DOT_QUALIFIED_EXPRESSION -> { + stack += getChildren(child).asReversed() + } + else -> return false + } + } + return false +} diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt index 7713ec5b4c4..f1dcf84c0b9 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt @@ -9,11 +9,11 @@ import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtRealSourceElementKind import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.* import org.jetbrains.kotlin.contracts.description.LogicOperationKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget -import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.contracts.FirContractDescription import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription @@ -56,7 +56,6 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.StandardClassIds -import org.jetbrains.kotlin.realElement import org.jetbrains.kotlin.types.ConstantValueKind import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.expressions.OperatorConventions @@ -556,19 +555,20 @@ fun FirPropertyBuilder.generateAccessorsByDelegate( } } -fun processLegacyContractDescription(block: FirBlock): FirContractDescription? { +fun processLegacyContractDescription(block: FirBlock, diagnostic: ConeDiagnostic?): FirContractDescription? { if (block.isContractPresentFirCheck()) { val contractCall = block.replaceFirstStatement { FirContractCallBlock(it) } - return contractCall.toLegacyRawContractDescription() + return contractCall.toLegacyRawContractDescription(diagnostic) } return null } -fun FirFunctionCall.toLegacyRawContractDescription(): FirLegacyRawContractDescription { +fun FirFunctionCall.toLegacyRawContractDescription(diagnostic: ConeDiagnostic? = null): FirLegacyRawContractDescription { return buildLegacyRawContractDescription { this.source = this@toLegacyRawContractDescription.source this.contractCall = this@toLegacyRawContractDescription + this.diagnostic = diagnostic } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirAbstractContractResolveTransformerDispatcher.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirAbstractContractResolveTransformerDispatcher.kt index 6536fe50df4..d92602da361 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirAbstractContractResolveTransformerDispatcher.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirAbstractContractResolveTransformerDispatcher.kt @@ -196,6 +196,7 @@ abstract class FirAbstractContractResolveTransformerDispatcher( } } this.source = contractDescription.source + this.diagnostic = contractDescription.diagnostic } owner.replaceContractDescription(resolvedContractDescription) dataFlowAnalyzer.exitContractDescription() diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirLegacyRawContractDescription.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirLegacyRawContractDescription.kt index 9a65e4fbf9d..f5438f7c146 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirLegacyRawContractDescription.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirLegacyRawContractDescription.kt @@ -10,6 +10,7 @@ package org.jetbrains.kotlin.fir.contracts import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor @@ -20,6 +21,7 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitor abstract class FirLegacyRawContractDescription : FirContractDescription() { abstract override val source: KtSourceElement? abstract val contractCall: FirFunctionCall + abstract val diagnostic: ConeDiagnostic? override fun accept(visitor: FirVisitor, data: D): R = visitor.visitLegacyRawContractDescription(this, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirResolvedContractDescription.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirResolvedContractDescription.kt index d26d442f94b..3b14444c571 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirResolvedContractDescription.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/FirResolvedContractDescription.kt @@ -10,6 +10,7 @@ package org.jetbrains.kotlin.fir.contracts import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor @@ -20,6 +21,7 @@ abstract class FirResolvedContractDescription : FirContractDescription() { abstract override val source: KtSourceElement? abstract val effects: List abstract val unresolvedEffects: List + abstract val diagnostic: ConeDiagnostic? override fun accept(visitor: FirVisitor, data: D): R = visitor.visitResolvedContractDescription(this, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirLegacyRawContractDescriptionBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirLegacyRawContractDescriptionBuilder.kt index a67fbb17532..9aac8e2e32f 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirLegacyRawContractDescriptionBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirLegacyRawContractDescriptionBuilder.kt @@ -15,17 +15,20 @@ import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.fir.builder.FirBuilderDsl import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription import org.jetbrains.kotlin.fir.contracts.impl.FirLegacyRawContractDescriptionImpl +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.expressions.FirFunctionCall @FirBuilderDsl class FirLegacyRawContractDescriptionBuilder { var source: KtSourceElement? = null lateinit var contractCall: FirFunctionCall + var diagnostic: ConeDiagnostic? = null fun build(): FirLegacyRawContractDescription { return FirLegacyRawContractDescriptionImpl( source, contractCall, + diagnostic, ) } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirResolvedContractDescriptionBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirResolvedContractDescriptionBuilder.kt index 9768124b25f..c7657cfa9b3 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirResolvedContractDescriptionBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/builder/FirResolvedContractDescriptionBuilder.kt @@ -17,18 +17,21 @@ import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription import org.jetbrains.kotlin.fir.contracts.impl.FirResolvedContractDescriptionImpl +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic @FirBuilderDsl class FirResolvedContractDescriptionBuilder { var source: KtSourceElement? = null val effects: MutableList = mutableListOf() val unresolvedEffects: MutableList = mutableListOf() + var diagnostic: ConeDiagnostic? = null fun build(): FirResolvedContractDescription { return FirResolvedContractDescriptionImpl( source, effects, unresolvedEffects, + diagnostic, ) } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirLegacyRawContractDescriptionImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirLegacyRawContractDescriptionImpl.kt index 9e0966cb57a..34638e5af56 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirLegacyRawContractDescriptionImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirLegacyRawContractDescriptionImpl.kt @@ -12,6 +12,7 @@ package org.jetbrains.kotlin.fir.contracts.impl import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor @@ -19,6 +20,7 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitor internal class FirLegacyRawContractDescriptionImpl( override val source: KtSourceElement?, override var contractCall: FirFunctionCall, + override val diagnostic: ConeDiagnostic?, ) : FirLegacyRawContractDescription() { override fun acceptChildren(visitor: FirVisitor, data: D) { contractCall.accept(visitor, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirResolvedContractDescriptionImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirResolvedContractDescriptionImpl.kt index edde6cbdf08..5dfd1d83d36 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirResolvedContractDescriptionImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/contracts/impl/FirResolvedContractDescriptionImpl.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.fir.visitors.transformInplace @@ -22,6 +23,7 @@ internal class FirResolvedContractDescriptionImpl( override val source: KtSourceElement?, override val effects: MutableList, override val unresolvedEffects: MutableList, + override val diagnostic: ConeDiagnostic?, ) : FirResolvedContractDescription() { override fun acceptChildren(visitor: FirVisitor, data: D) { effects.forEach { it.accept(visitor, data) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt index 079308f0a5d..23c6d71dc24 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt @@ -87,6 +87,10 @@ object ConeMissingConstructorKeyword : ConeDiagnostic { override val reason: String get() = "Use the 'constructor' keyword after the modifiers of the primary constructor." } +object ConeContractShouldBeFirstStatement : ConeDiagnostic { + override val reason: String get() = "Contract should be the first statement." +} + enum class DiagnosticKind { ExpressionExpected, NotLoopLabel, diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index 36d4c66a844..8eb653c41fe 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -777,10 +777,12 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild resolvedContractDescription.configure { +fieldList("effects", effectDeclaration) +fieldList("unresolvedEffects", contractElementDeclaration) + +field("diagnostic", coneDiagnosticType, nullable = true) } legacyRawContractDescription.configure { +field("contractCall", functionCall) + +field("diagnostic", coneDiagnosticType, nullable = true) } } } diff --git a/compiler/testData/diagnostics/tests/contracts/neg/14.fir.kt b/compiler/testData/diagnostics/tests/contracts/neg/14.fir.kt new file mode 100644 index 00000000000..c6c3ac03528 --- /dev/null +++ b/compiler/testData/diagnostics/tests/contracts/neg/14.fir.kt @@ -0,0 +1,23 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !OPT_IN: kotlin.contracts.ExperimentalContracts + +/* + * ADDITION TO `KOTLIN DIAGNOSTICS NOT LINKED SPEC TEST (NEGATIVE)` + * + * SECTIONS: contracts, declarations, contractBuilder, common + * NUMBER: 14 + * DESCRIPTION: Contract is first statement in control flow terms, but not in tokens order terms. + * ISSUES: KT-26153 + * HELPERS: functions + */ + +import kotlin.contracts.* + +// TESTCASE NUMBER: 8 +val myProp = 8 +inline fun case_8(block: () -> Unit) { + myProp + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } +} diff --git a/compiler/testData/diagnostics/tests/contracts/neg/14.kt b/compiler/testData/diagnostics/tests/contracts/neg/14.kt new file mode 100644 index 00000000000..893d702f0a4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/contracts/neg/14.kt @@ -0,0 +1,23 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !OPT_IN: kotlin.contracts.ExperimentalContracts + +/* + * ADDITION TO `KOTLIN DIAGNOSTICS NOT LINKED SPEC TEST (NEGATIVE)` + * + * SECTIONS: contracts, declarations, contractBuilder, common + * NUMBER: 14 + * DESCRIPTION: Contract is first statement in control flow terms, but not in tokens order terms. + * ISSUES: KT-26153 + * HELPERS: functions + */ + +import kotlin.contracts.* + +// TESTCASE NUMBER: 8 +val myProp = 8 +inline fun case_8(block: () -> Unit) { + myProp + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } +} diff --git a/compiler/testData/diagnostics/tests/contracts/pos/1.kt b/compiler/testData/diagnostics/tests/contracts/pos/1.kt new file mode 100644 index 00000000000..239f1118a76 --- /dev/null +++ b/compiler/testData/diagnostics/tests/contracts/pos/1.kt @@ -0,0 +1,20 @@ +// FIR_IDENTICAL +// !OPT_IN: kotlin.contracts.ExperimentalContracts + +/* + * ADDITION TO `KOTLIN DIAGNOSTICS NOT LINKED SPEC TEST (POSITIVE)` + * + * SECTIONS: contracts, declarations, contractBuilder, common + * NUMBER: 1 + * DESCRIPTION: Functions with simple contracts. + */ + +import kotlin.contracts.* + +// The following is an useful addition to testcases in compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/pos/1.kt + +// TESTCASE NUMBER: 4 +inline fun case_4(block: () -> Unit) { + kotlin.contracts.contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return block() +} diff --git a/compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.fir.kt b/compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.fir.kt new file mode 100644 index 00000000000..9c9f2898184 --- /dev/null +++ b/compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.fir.kt @@ -0,0 +1,82 @@ +// KT-60004: Ensure diagnostics for `kotlin.contracts.contract()` are not raised for user-defined fun `contract()` + +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !OPT_IN: kotlin.contracts.ExperimentalContracts + +/* + * POSITIVE ADDITION TO `KOTLIN DIAGNOSTICS NOT LINKED SPEC TEST (NEGATIVE)` + * + * SECTIONS: contracts, declarations, contractBuilder, common + * NUMBER: 14UserDefined + * DESCRIPTION: Invocation of user-defined fun `contract()` is first statement in control flow terms, but not in tokens order terms. + * ISSUES: KT-60004 + * HELPERS: functions + */ + +import kotlin.contracts.ContractBuilder +import kotlin.contracts.InvocationKind + +// User-defined fun `contract()` must not be mixed up with `kotlin.contracts.contract()` +inline fun contract(builder: ContractBuilder.() -> Unit) {} + +// TESTCASE NUMBER: 1 +inline fun case_1(block: () -> Unit) { + return contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } +} + +// TESTCASE NUMBER: 2 +fun case_2() = contract { } + +// TESTCASE NUMBER: 3 +inline fun case_3(block: () -> Unit) { + val value_1 = contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() +} + +// TESTCASE NUMBER: 4 +inline fun case_4(block: () -> Unit) { + (contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + }) + return block() +} + +// TESTCASE NUMBER: 5 +inline fun case_5(block: () -> Unit) { + test@ contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return block() +} + +// TESTCASE NUMBER: 6 +inline fun case_6(block: () -> Unit) { + throw Exception(contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + }.toString()) +} + +// TESTCASE NUMBER: 7 +inline fun case_7(block: () -> Unit) { + funWithAnyArg(contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + }) +} + +// TESTCASE NUMBER: 8 +val myProp = 8 +inline fun case_8(block: () -> Unit) { + myProp + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } +} + +// Copy-pasted from compiler/tests-spec/testData/diagnostics/helpers/functions.kt +fun funWithAnyArg(value_1: Any): Int { + return value_1.hashCode() +} diff --git a/compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.kt b/compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.kt new file mode 100644 index 00000000000..1a47f084416 --- /dev/null +++ b/compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.kt @@ -0,0 +1,82 @@ +// KT-60004: Ensure diagnostics for `kotlin.contracts.contract()` are not raised for user-defined fun `contract()` + +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !OPT_IN: kotlin.contracts.ExperimentalContracts + +/* + * POSITIVE ADDITION TO `KOTLIN DIAGNOSTICS NOT LINKED SPEC TEST (NEGATIVE)` + * + * SECTIONS: contracts, declarations, contractBuilder, common + * NUMBER: 14UserDefined + * DESCRIPTION: Invocation of user-defined fun `contract()` is first statement in control flow terms, but not in tokens order terms. + * ISSUES: KT-60004 + * HELPERS: functions + */ + +import kotlin.contracts.ContractBuilder +import kotlin.contracts.InvocationKind + +// User-defined fun `contract()` must not be mixed up with `kotlin.contracts.contract()` +inline fun contract(builder: ContractBuilder.() -> Unit) {} + +// TESTCASE NUMBER: 1 +inline fun case_1(block: () -> Unit) { + return contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } +} + +// TESTCASE NUMBER: 2 +fun case_2() = contract { } + +// TESTCASE NUMBER: 3 +inline fun case_3(block: () -> Unit) { + val value_1 = contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() +} + +// TESTCASE NUMBER: 4 +inline fun case_4(block: () -> Unit) { + (contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + }) + return block() +} + +// TESTCASE NUMBER: 5 +inline fun case_5(block: () -> Unit) { + test@ contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return block() +} + +// TESTCASE NUMBER: 6 +inline fun case_6(block: () -> Unit) { + throw Exception(contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + }.toString()) +} + +// TESTCASE NUMBER: 7 +inline fun case_7(block: () -> Unit) { + funWithAnyArg(contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + }) +} + +// TESTCASE NUMBER: 8 +val myProp = 8 +inline fun case_8(block: () -> Unit) { + myProp + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } +} + +// Copy-pasted from compiler/tests-spec/testData/diagnostics/helpers/functions.kt +fun funWithAnyArg(value_1: Any): Int { + return value_1.hashCode() +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index ae9c89eb8e8..7d1856f53b4 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -6645,6 +6645,54 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts") + @TestDataPath("$PROJECT_ROOT") + public class Contracts { + @Test + public void testAllFilesPresentInContracts() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true); + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/neg") + @TestDataPath("$PROJECT_ROOT") + public class Neg { + @Test + @TestMetadata("14.kt") + public void test14() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/neg/14.kt"); + } + + @Test + public void testAllFilesPresentInNeg() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/neg"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true); + } + } + + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/contracts/pos") + @TestDataPath("$PROJECT_ROOT") + public class Pos { + @Test + @TestMetadata("1.kt") + public void test1() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/1.kt"); + } + + @Test + @TestMetadata("14UserDefined.kt") + public void test14UserDefined() throws Exception { + runTest("compiler/testData/diagnostics/tests/contracts/pos/14UserDefined.kt"); + } + + @Test + public void testAllFilesPresentInPos() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/contracts/pos"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true); + } + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/14.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/14.fir.kt index d666fb6c577..4c77a43a17d 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/14.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/14.fir.kt @@ -33,7 +33,7 @@ inline fun case_3(block: () -> Unit) { // TESTCASE NUMBER: 4 inline fun case_4(block: () -> Unit) { - (contract { + (contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }) return block() @@ -41,7 +41,7 @@ inline fun case_4(block: () -> Unit) { // TESTCASE NUMBER: 5 inline fun case_5(block: () -> Unit) { - test@ contract { + test@ contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block()