[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 <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
834927a901
commit
0fb853a995
+48
@@ -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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+48
@@ -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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+48
@@ -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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+48
@@ -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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+8
@@ -9,7 +9,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
|||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
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.declarations.FirFunction
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.ConeContractShouldBeFirstStatement
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
|
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
||||||
@@ -35,5 +39,9 @@ object FirContractNotFirstStatementChecker : FirFunctionCallChecker() {
|
|||||||
private fun FirFunctionCall.isCorrectlyPlacedIn(functionDeclaration: FirFunction): Boolean {
|
private fun FirFunctionCall.isCorrectlyPlacedIn(functionDeclaration: FirFunction): Boolean {
|
||||||
val firstStatement = functionDeclaration.body?.statements?.first()
|
val firstStatement = functionDeclaration.body?.statements?.first()
|
||||||
return firstStatement is FirContractCallBlock && firstStatement.call == this
|
return firstStatement is FirContractCallBlock && firstStatement.call == this
|
||||||
|
&& !(functionDeclaration is FirContractDescriptionOwner && functionDeclaration.contractDescription.isNonFirstStatement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val FirContractDescription.isNonFirstStatement: Boolean
|
||||||
|
get() = this is FirResolvedContractDescription && diagnostic == ConeContractShouldBeFirstStatement
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -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.descriptors.annotations.AnnotationUseSiteTarget.*
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.isCallTheFirstStatement
|
||||||
import org.jetbrains.kotlin.fir.builder.*
|
import org.jetbrains.kotlin.fir.builder.*
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||||
import org.jetbrains.kotlin.fir.contracts.builder.buildRawContractDescription
|
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.lexer.KtTokens.*
|
||||||
import org.jetbrains.kotlin.name.*
|
import org.jetbrains.kotlin.name.*
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
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.runIf
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
|
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
|
||||||
|
|
||||||
@@ -1818,7 +1820,14 @@ class LightTreeRawFirDeclarationBuilder(
|
|||||||
return when {
|
return when {
|
||||||
blockNode != null -> {
|
blockNode != null -> {
|
||||||
val block = convertBlock(blockNode)
|
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
|
block to contractDescription
|
||||||
}
|
}
|
||||||
expression != null -> FirSingleExpressionBlock(
|
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
|
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlock
|
||||||
*/
|
*/
|
||||||
|
|||||||
+12
-1
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.builtins.StandardNames.BACKING_FIELD
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
|
||||||
import org.jetbrains.kotlin.fir.*
|
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.FirContractDescription
|
||||||
import org.jetbrains.kotlin.fir.contracts.builder.buildRawContractDescription
|
import org.jetbrains.kotlin.fir.contracts.builder.buildRawContractDescription
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
@@ -419,7 +420,14 @@ open class PsiRawFirBuilder(
|
|||||||
if (hasBlockBody()) {
|
if (hasBlockBody()) {
|
||||||
val block = bodyBlockExpression?.accept(this@Visitor, null) as? FirBlock
|
val block = bodyBlockExpression?.accept(this@Visitor, null) as? FirBlock
|
||||||
val contractDescription = when {
|
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
|
else -> null
|
||||||
}
|
}
|
||||||
return@buildFirBody block to contractDescription
|
return@buildFirBody block to contractDescription
|
||||||
@@ -432,6 +440,9 @@ open class PsiRawFirBuilder(
|
|||||||
null to null
|
null to null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isCallTheFirstStatement(psi: PsiElement): Boolean =
|
||||||
|
isCallTheFirstStatement(psi, { it.elementType }, { it.allChildren.toList() })
|
||||||
|
|
||||||
private fun ValueArgument?.toFirExpression(): FirExpression {
|
private fun ValueArgument?.toFirExpression(): FirExpression {
|
||||||
if (this == null) {
|
if (this == null) {
|
||||||
return buildErrorExpression(
|
return buildErrorExpression(
|
||||||
|
|||||||
+33
@@ -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 <T> isCallTheFirstStatement(
|
||||||
|
root: T,
|
||||||
|
getElementType: (T) -> IElementType,
|
||||||
|
getChildren: (T) -> List<T>,
|
||||||
|
): 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
|
||||||
|
}
|
||||||
+5
-5
@@ -9,11 +9,11 @@ import com.intellij.psi.tree.IElementType
|
|||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.KtRealSourceElementKind
|
import org.jetbrains.kotlin.KtRealSourceElementKind
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
|
import org.jetbrains.kotlin.*
|
||||||
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||||
import org.jetbrains.kotlin.fakeElement
|
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
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.Name
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.realElement
|
|
||||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
@@ -556,19 +555,20 @@ fun <T> FirPropertyBuilder.generateAccessorsByDelegate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun processLegacyContractDescription(block: FirBlock): FirContractDescription? {
|
fun processLegacyContractDescription(block: FirBlock, diagnostic: ConeDiagnostic?): FirContractDescription? {
|
||||||
if (block.isContractPresentFirCheck()) {
|
if (block.isContractPresentFirCheck()) {
|
||||||
val contractCall = block.replaceFirstStatement<FirFunctionCall> { FirContractCallBlock(it) }
|
val contractCall = block.replaceFirstStatement<FirFunctionCall> { FirContractCallBlock(it) }
|
||||||
return contractCall.toLegacyRawContractDescription()
|
return contractCall.toLegacyRawContractDescription(diagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirFunctionCall.toLegacyRawContractDescription(): FirLegacyRawContractDescription {
|
fun FirFunctionCall.toLegacyRawContractDescription(diagnostic: ConeDiagnostic? = null): FirLegacyRawContractDescription {
|
||||||
return buildLegacyRawContractDescription {
|
return buildLegacyRawContractDescription {
|
||||||
this.source = this@toLegacyRawContractDescription.source
|
this.source = this@toLegacyRawContractDescription.source
|
||||||
this.contractCall = this@toLegacyRawContractDescription
|
this.contractCall = this@toLegacyRawContractDescription
|
||||||
|
this.diagnostic = diagnostic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -196,6 +196,7 @@ abstract class FirAbstractContractResolveTransformerDispatcher(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.source = contractDescription.source
|
this.source = contractDescription.source
|
||||||
|
this.diagnostic = contractDescription.diagnostic
|
||||||
}
|
}
|
||||||
owner.replaceContractDescription(resolvedContractDescription)
|
owner.replaceContractDescription(resolvedContractDescription)
|
||||||
dataFlowAnalyzer.exitContractDescription()
|
dataFlowAnalyzer.exitContractDescription()
|
||||||
|
|||||||
+2
@@ -10,6 +10,7 @@ package org.jetbrains.kotlin.fir.contracts
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
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.expressions.FirFunctionCall
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
@@ -20,6 +21,7 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
|||||||
abstract class FirLegacyRawContractDescription : FirContractDescription() {
|
abstract class FirLegacyRawContractDescription : FirContractDescription() {
|
||||||
abstract override val source: KtSourceElement?
|
abstract override val source: KtSourceElement?
|
||||||
abstract val contractCall: FirFunctionCall
|
abstract val contractCall: FirFunctionCall
|
||||||
|
abstract val diagnostic: ConeDiagnostic?
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
||||||
visitor.visitLegacyRawContractDescription(this, data)
|
visitor.visitLegacyRawContractDescription(this, data)
|
||||||
|
|||||||
+2
@@ -10,6 +10,7 @@ package org.jetbrains.kotlin.fir.contracts
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
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.FirTransformer
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ abstract class FirResolvedContractDescription : FirContractDescription() {
|
|||||||
abstract override val source: KtSourceElement?
|
abstract override val source: KtSourceElement?
|
||||||
abstract val effects: List<FirEffectDeclaration>
|
abstract val effects: List<FirEffectDeclaration>
|
||||||
abstract val unresolvedEffects: List<FirContractElementDeclaration>
|
abstract val unresolvedEffects: List<FirContractElementDeclaration>
|
||||||
|
abstract val diagnostic: ConeDiagnostic?
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
||||||
visitor.visitResolvedContractDescription(this, data)
|
visitor.visitResolvedContractDescription(this, data)
|
||||||
|
|||||||
+3
@@ -15,17 +15,20 @@ import org.jetbrains.kotlin.KtSourceElement
|
|||||||
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
|
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
||||||
import org.jetbrains.kotlin.fir.contracts.impl.FirLegacyRawContractDescriptionImpl
|
import org.jetbrains.kotlin.fir.contracts.impl.FirLegacyRawContractDescriptionImpl
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
|
||||||
@FirBuilderDsl
|
@FirBuilderDsl
|
||||||
class FirLegacyRawContractDescriptionBuilder {
|
class FirLegacyRawContractDescriptionBuilder {
|
||||||
var source: KtSourceElement? = null
|
var source: KtSourceElement? = null
|
||||||
lateinit var contractCall: FirFunctionCall
|
lateinit var contractCall: FirFunctionCall
|
||||||
|
var diagnostic: ConeDiagnostic? = null
|
||||||
|
|
||||||
fun build(): FirLegacyRawContractDescription {
|
fun build(): FirLegacyRawContractDescription {
|
||||||
return FirLegacyRawContractDescriptionImpl(
|
return FirLegacyRawContractDescriptionImpl(
|
||||||
source,
|
source,
|
||||||
contractCall,
|
contractCall,
|
||||||
|
diagnostic,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -17,18 +17,21 @@ import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
|||||||
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
||||||
import org.jetbrains.kotlin.fir.contracts.impl.FirResolvedContractDescriptionImpl
|
import org.jetbrains.kotlin.fir.contracts.impl.FirResolvedContractDescriptionImpl
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
|
|
||||||
@FirBuilderDsl
|
@FirBuilderDsl
|
||||||
class FirResolvedContractDescriptionBuilder {
|
class FirResolvedContractDescriptionBuilder {
|
||||||
var source: KtSourceElement? = null
|
var source: KtSourceElement? = null
|
||||||
val effects: MutableList<FirEffectDeclaration> = mutableListOf()
|
val effects: MutableList<FirEffectDeclaration> = mutableListOf()
|
||||||
val unresolvedEffects: MutableList<FirContractElementDeclaration> = mutableListOf()
|
val unresolvedEffects: MutableList<FirContractElementDeclaration> = mutableListOf()
|
||||||
|
var diagnostic: ConeDiagnostic? = null
|
||||||
|
|
||||||
fun build(): FirResolvedContractDescription {
|
fun build(): FirResolvedContractDescription {
|
||||||
return FirResolvedContractDescriptionImpl(
|
return FirResolvedContractDescriptionImpl(
|
||||||
source,
|
source,
|
||||||
effects,
|
effects,
|
||||||
unresolvedEffects,
|
unresolvedEffects,
|
||||||
|
diagnostic,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -12,6 +12,7 @@ package org.jetbrains.kotlin.fir.contracts.impl
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
|
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.expressions.FirFunctionCall
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
|||||||
internal class FirLegacyRawContractDescriptionImpl(
|
internal class FirLegacyRawContractDescriptionImpl(
|
||||||
override val source: KtSourceElement?,
|
override val source: KtSourceElement?,
|
||||||
override var contractCall: FirFunctionCall,
|
override var contractCall: FirFunctionCall,
|
||||||
|
override val diagnostic: ConeDiagnostic?,
|
||||||
) : FirLegacyRawContractDescription() {
|
) : FirLegacyRawContractDescription() {
|
||||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
||||||
contractCall.accept(visitor, data)
|
contractCall.accept(visitor, data)
|
||||||
|
|||||||
+2
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.KtSourceElement
|
|||||||
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
import org.jetbrains.kotlin.fir.contracts.FirContractElementDeclaration
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
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.FirTransformer
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
import org.jetbrains.kotlin.fir.visitors.transformInplace
|
import org.jetbrains.kotlin.fir.visitors.transformInplace
|
||||||
@@ -22,6 +23,7 @@ internal class FirResolvedContractDescriptionImpl(
|
|||||||
override val source: KtSourceElement?,
|
override val source: KtSourceElement?,
|
||||||
override val effects: MutableList<FirEffectDeclaration>,
|
override val effects: MutableList<FirEffectDeclaration>,
|
||||||
override val unresolvedEffects: MutableList<FirContractElementDeclaration>,
|
override val unresolvedEffects: MutableList<FirContractElementDeclaration>,
|
||||||
|
override val diagnostic: ConeDiagnostic?,
|
||||||
) : FirResolvedContractDescription() {
|
) : FirResolvedContractDescription() {
|
||||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
||||||
effects.forEach { it.accept(visitor, data) }
|
effects.forEach { it.accept(visitor, data) }
|
||||||
|
|||||||
@@ -87,6 +87,10 @@ object ConeMissingConstructorKeyword : ConeDiagnostic {
|
|||||||
override val reason: String get() = "Use the 'constructor' keyword after the modifiers of the primary constructor."
|
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 {
|
enum class DiagnosticKind {
|
||||||
ExpressionExpected,
|
ExpressionExpected,
|
||||||
NotLoopLabel,
|
NotLoopLabel,
|
||||||
|
|||||||
+2
@@ -777,10 +777,12 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
|||||||
resolvedContractDescription.configure {
|
resolvedContractDescription.configure {
|
||||||
+fieldList("effects", effectDeclaration)
|
+fieldList("effects", effectDeclaration)
|
||||||
+fieldList("unresolvedEffects", contractElementDeclaration)
|
+fieldList("unresolvedEffects", contractElementDeclaration)
|
||||||
|
+field("diagnostic", coneDiagnosticType, nullable = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
legacyRawContractDescription.configure {
|
legacyRawContractDescription.configure {
|
||||||
+field("contractCall", functionCall)
|
+field("contractCall", functionCall)
|
||||||
|
+field("diagnostic", coneDiagnosticType, nullable = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_NOT_ALLOWED!>contract<!> {
|
||||||
|
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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_NOT_ALLOWED!>contract<!> {
|
||||||
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -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(<!USAGE_IS_NOT_INLINABLE!>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(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTCASE NUMBER: 4
|
||||||
|
inline fun case_4(block: () -> Unit) {
|
||||||
|
(contract {
|
||||||
|
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
|
||||||
|
})
|
||||||
|
return block()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTCASE NUMBER: 5
|
||||||
|
inline fun case_5(block: () -> Unit) {
|
||||||
|
test@ contract {
|
||||||
|
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
return block()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTCASE NUMBER: 6
|
||||||
|
inline fun case_6(block: () -> Unit) {
|
||||||
|
throw Exception(contract {
|
||||||
|
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTCASE NUMBER: 7
|
||||||
|
inline fun case_7(block: () -> Unit) {
|
||||||
|
funWithAnyArg(contract {
|
||||||
|
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>block<!>, InvocationKind.EXACTLY_ONCE)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTCASE NUMBER: 8
|
||||||
|
val myProp = 8
|
||||||
|
inline fun case_8(block: () -> Unit) {
|
||||||
|
myProp
|
||||||
|
contract {
|
||||||
|
callsInPlace(<!USAGE_IS_NOT_INLINABLE!>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()
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
<!REDUNDANT_LABEL_WARNING!>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()
|
||||||
|
}
|
||||||
Generated
+48
@@ -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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+2
-2
@@ -33,7 +33,7 @@ inline fun case_3(block: () -> Unit) {
|
|||||||
|
|
||||||
// TESTCASE NUMBER: 4
|
// TESTCASE NUMBER: 4
|
||||||
inline fun case_4(block: () -> Unit) {
|
inline fun case_4(block: () -> Unit) {
|
||||||
(contract {
|
(<!CONTRACT_NOT_ALLOWED!>contract<!> {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
})
|
})
|
||||||
return block()
|
return block()
|
||||||
@@ -41,7 +41,7 @@ inline fun case_4(block: () -> Unit) {
|
|||||||
|
|
||||||
// TESTCASE NUMBER: 5
|
// TESTCASE NUMBER: 5
|
||||||
inline fun case_5(block: () -> Unit) {
|
inline fun case_5(block: () -> Unit) {
|
||||||
test@ contract {
|
test@ <!CONTRACT_NOT_ALLOWED!>contract<!> {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
}
|
}
|
||||||
return block()
|
return block()
|
||||||
|
|||||||
Reference in New Issue
Block a user