From dd3bc1a9649813e33577acefc95ad1aac00cbcfc Mon Sep 17 00:00:00 2001 From: Br0mm Date: Thu, 4 Feb 2021 13:44:35 +0300 Subject: [PATCH] FIR: Introduce CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT diagnostic --- ...TouchedTilContractsPhaseTestGenerated.java | 18 ++++ .../constValNotTopLevelOrObject.fir.txt | 100 ++++++++++++++++++ .../constVal/constValNotTopLevelOrObject.kt | 42 ++++++++ .../runners/FirDiagnosticTestGenerated.java | 16 +++ ...DiagnosticsWithLightTreeTestGenerated.java | 17 +++ .../generator/diagnostics/DiagnosticData.kt | 1 + .../diagnostics/FirDiagnosticsList.kt | 1 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../declaration/FirConstPropertyChecker.kt | 26 +++++ .../LightTreePositioningStrategies.kt | 3 + .../SourceElementPositioningStrategies.kt | 5 + .../fir/checkers/CommonDeclarationCheckers.kt | 1 + .../diagnostics/PositioningStrategies.kt | 3 + ...ocalVariablesWithTypeParameters_1_3.fir.kt | 2 +- ...ocalVariablesWithTypeParameters_1_4.fir.kt | 2 +- .../modifiers/const/applicability.fir.kt | 12 +-- 16 files changed, 242 insertions(+), 8 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.kt create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstPropertyChecker.kt diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 20c20e84b29..87dc3b96ecf 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -894,6 +894,24 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract } } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/constVal") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ConstVal extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInConstVal() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/constVal"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @TestMetadata("constValNotTopLevelOrObject.kt") + public void testConstValNotTopLevelOrObject() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.kt"); + } + } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/constructors") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.fir.txt b/compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.fir.txt new file mode 100644 index 00000000000..2d2712c64fc --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.fir.txt @@ -0,0 +1,100 @@ +FILE: constValNotTopLevelOrObject.kt + public final const val a: R|kotlin/Int| = Int(1) + public get(): R|kotlin/Int| + public final object B : R|kotlin/Any| { + private constructor(): R|B| { + super() + } + + public final const val b: R|kotlin/Int| = Int(2) + public get(): R|kotlin/Int| + + } + public final class C : R|kotlin/Any| { + public constructor(): R|C| { + super() + } + + public final const val c: R|kotlin/Int| = Int(3) + public get(): R|kotlin/Int| + + } + public final class D : R|kotlin/Any| { + public constructor(): R|D| { + super() + } + + public final object E : R|kotlin/Any| { + private constructor(): R|D.E| { + super() + } + + public final const val e: R|kotlin/Int| = Int(4) + public get(): R|kotlin/Int| + + } + + public final companion object K : R|kotlin/Any| { + private constructor(): R|D.K| { + super() + } + + public final const val k: R|kotlin/Int| = Int(4) + public get(): R|kotlin/Int| + + } + + public final val M: R|kotlin/Any| = object : R|kotlin/Any| { + private constructor(): R|| { + super() + } + + public final const val m: R|kotlin/Int| = Int(3) + public get(): R|kotlin/Int| + + } + + public get(): R|kotlin/Any| + + public open class O : R|kotlin/Any| { + public constructor(): R|D.O| { + super() + } + + public open val y: R|kotlin/Int| = Int(8) + public get(): R|kotlin/Int| + + } + + public final val t: R|D.O| = object : R|D.O| { + private constructor(): R|| { + super() + } + + public final const val x: R|kotlin/Int| = Int(15) + public get(): R|kotlin/Int| + + } + + public get(): R|D.O| + + } + public final object F : R|kotlin/Any| { + private constructor(): R|F| { + super() + } + + public final class G : R|kotlin/Any| { + public constructor(): R|F.G| { + super() + } + + public final const val e: R|kotlin/Int| = Int(4) + public get(): R|kotlin/Int| + + } + + } + public final fun foo(): R|kotlin/Unit| { + lval a: R|kotlin/String| = String(2) + } diff --git a/compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.kt b/compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.kt new file mode 100644 index 00000000000..b935b7d0a6e --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.kt @@ -0,0 +1,42 @@ +const val a = 1 + +object B { + const val b = 2 +} + +class C { + const val c = 3 +} + +class D { + object E { + const val e = 4 + } + + companion object K { + const val k = 4 + } + + val M = object { + const val m = 3 + } + + open class O { + open val y: Int = 8 + } + + val t: O = object : O() { + const val x = 15 + } + +} + +object F { + class G { + const val e = 4 + } +} + +fun foo() { + const val a = "2" +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index 953aaffdbf1..2e8c5b5d8e8 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -1036,6 +1036,22 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/constVal") + @TestDataPath("$PROJECT_ROOT") + public class ConstVal { + @Test + public void testAllFilesPresentInConstVal() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/constVal"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("constValNotTopLevelOrObject.kt") + public void testConstValNotTopLevelOrObject() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/constructors") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 694267105eb..330d8501dfb 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -1044,6 +1044,23 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/constVal") + @TestDataPath("$PROJECT_ROOT") + @Execution(ExecutionMode.SAME_THREAD) + public class ConstVal { + @Test + public void testAllFilesPresentInConstVal() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/constVal"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("constValNotTopLevelOrObject.kt") + public void testConstValNotTopLevelOrObject() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/constVal/constValNotTopLevelOrObject.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/constructors") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt index 171819433a1..cb14bdb3d39 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt @@ -46,6 +46,7 @@ enum class PositioningStrategy(private val strategy: String? = null) { REFERENCE_BY_QUALIFIED, PRIVATE_MODIFIER, COMPANION_OBJECT, + CONST_MODIFIER, ; diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index cc1014b2f07..955b7fbbbcb 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -328,6 +328,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error(PositioningStrategy.PRIVATE_MODIFIER) val EXPECTED_PRIVATE_DECLARATION by error(PositioningStrategy.VISIBILITY_MODIFIER) val VAL_WITH_SETTER by error() + val CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT by error(PositioningStrategy.CONST_MODIFIER) } val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 8d43990af5f..c96f58c1ea8 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -222,6 +222,7 @@ object FirErrors { val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error0(SourceElementPositioningStrategies.PRIVATE_MODIFIER) val EXPECTED_PRIVATE_DECLARATION by error0(SourceElementPositioningStrategies.VISIBILITY_MODIFIER) val VAL_WITH_SETTER by error0() + val CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT by error0(SourceElementPositioningStrategies.CONST_MODIFIER) // Multi-platform projects val EXPECTED_DECLARATION_WITH_BODY by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstPropertyChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstPropertyChecker.kt new file mode 100644 index 00000000000..83df6d54796 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstPropertyChecker.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2021 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.checkers.declaration + +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.lexer.KtTokens + +object FirConstPropertyChecker : FirPropertyChecker() { + override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) { + val modifierList = with(FirModifierList) { declaration.source.getModifierList() } + if (modifierList?.modifiers?.any { it.token == KtTokens.CONST_KEYWORD } != true) + return + val classKind = (context.containingDeclarations.lastOrNull() as? FirRegularClass)?.classKind + if (classKind != ClassKind.OBJECT && context.containingDeclarations.size > 1) + reporter.reportOn(declaration.source, FirErrors.CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT, context) + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt index 98b1ddc58e0..de3653ba25f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt @@ -292,6 +292,9 @@ object LightTreePositioningStrategies { val VARIANCE_MODIFIER: LightTreePositioningStrategy = ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD)) + val CONST_MODIFIER: LightTreePositioningStrategy = + ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.CONST_KEYWORD)) + val OPERATOR: LightTreePositioningStrategy = object : LightTreePositioningStrategy() { override fun mark( node: LighterASTNode, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt index cae8244b4c6..e3cb6927c74 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt @@ -127,4 +127,9 @@ object SourceElementPositioningStrategies { LightTreePositioningStrategies.IF_EXPRESSION, PositioningStrategies.IF_EXPRESSION ) + + val CONST_MODIFIER = SourceElementPositioningStrategy( + LightTreePositioningStrategies.CONST_MODIFIER, + PositioningStrategies.CONST_MODIFIER + ) } diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt index 9ab8cea0594..2a0b08da41c 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt @@ -35,6 +35,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { override val propertyCheckers: Set = setOf( FirInapplicableLateinitChecker, FirDestructuringDeclarationChecker, + FirConstPropertyChecker, ) override val classCheckers: Set = setOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index 602933b4938..bf6074a3c3a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -353,6 +353,9 @@ object PositioningStrategies { @JvmField val VARIANCE_MODIFIER: PositioningStrategy = modifierSetPosition(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD) + @JvmField + val CONST_MODIFIER: PositioningStrategy = modifierSetPosition(KtTokens.CONST_KEYWORD) + @JvmField val FOR_REDECLARATION: PositioningStrategy = object : PositioningStrategy() { override fun mark(element: PsiElement): List { diff --git a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.fir.kt b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.fir.kt index 7276f6c9207..60e17034a74 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.fir.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.fir.kt @@ -8,7 +8,7 @@ fun test() { val a0 = 0 val a1 = "" val a2 = 0 - const val a3 = 0 + const val a3 = 0 lateinit val a4 = 0 val a5 by Delegate() val a6 by Delegate<T>() diff --git a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.fir.kt b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.fir.kt index 8d09b2a5612..181048b6958 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.fir.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.fir.kt @@ -8,7 +8,7 @@ fun test() { val a0 = 0 val a1 = "" val a2 = 0 - const val a3 = 0 + const val a3 = 0 lateinit val a4 = 0 val a5 by Delegate() val a6 by Delegate<T>() diff --git a/compiler/testData/diagnostics/tests/modifiers/const/applicability.fir.kt b/compiler/testData/diagnostics/tests/modifiers/const/applicability.fir.kt index 81b6a56d5a8..98a6c24e386 100644 --- a/compiler/testData/diagnostics/tests/modifiers/const/applicability.fir.kt +++ b/compiler/testData/diagnostics/tests/modifiers/const/applicability.fir.kt @@ -12,12 +12,12 @@ object A { const val inObject: Int = 4 } -class B(const val constructor: Int = 5) +class B(const val constructor: Int = 5) abstract class C { - open const val x: Int = 6 + open const val x: Int = 6 - abstract const val y: Int = 7 + abstract const val y: Int = 7 companion object { const val inCompaionObject = 8 @@ -48,15 +48,15 @@ const val withExplicitDefaultGetter: Int = 1 get fun foo(): Int { - const val local: Int = 14 + const val local: Int = 14 return 15 } enum class MyEnum { A { - const val inEnumEntry = 16 + const val inEnumEntry = 16 }; - const val inEnum = 17 + const val inEnum = 17 } class Outer {