FIR: Introduce CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT diagnostic

This commit is contained in:
Br0mm
2021-02-04 13:44:35 +03:00
committed by Mikhail Glukhikh
parent 6c2eaf2df8
commit dd3bc1a964
16 changed files with 242 additions and 8 deletions
@@ -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)
@@ -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<R|kotlin/Any|>()
}
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<R|kotlin/Any|>()
}
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<R|kotlin/Any|>()
}
public final object E : R|kotlin/Any| {
private constructor(): R|D.E| {
super<R|kotlin/Any|>()
}
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<R|kotlin/Any|>()
}
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|<anonymous>| {
super<R|kotlin/Any|>()
}
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<R|kotlin/Any|>()
}
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|<anonymous>| {
super<R|D.O|>()
}
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<R|kotlin/Any|>()
}
public final class G : R|kotlin/Any| {
public constructor(): R|F.G| {
super<R|kotlin/Any|>()
}
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)
}
@@ -0,0 +1,42 @@
const val a = 1
object B {
const val b = 2
}
class C {
<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val c = 3
}
class D {
object E {
const val e = 4
}
companion object K {
const val k = 4
}
val M = object {
<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val m = 3
}
open class O {
open val y: Int = 8
}
val t: O = object : O() {
<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val x = 15
}
}
object F {
class G {
<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val e = 4
}
}
fun foo() {
<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val a = "2"
}
@@ -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")
@@ -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")
@@ -46,6 +46,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
REFERENCE_BY_QUALIFIED,
PRIVATE_MODIFIER,
COMPANION_OBJECT,
CONST_MODIFIER,
;
@@ -328,6 +328,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.PRIVATE_MODIFIER)
val EXPECTED_PRIVATE_DECLARATION by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.VISIBILITY_MODIFIER)
val VAL_WITH_SETTER by error<FirSourceElement, KtPropertyAccessor>()
val CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT by error<FirSourceElement, KtProperty>(PositioningStrategy.CONST_MODIFIER)
}
val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") {
@@ -222,6 +222,7 @@ object FirErrors {
val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.PRIVATE_MODIFIER)
val EXPECTED_PRIVATE_DECLARATION by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
val VAL_WITH_SETTER by error0<FirSourceElement, KtPropertyAccessor>()
val CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT by error0<FirSourceElement, KtProperty>(SourceElementPositioningStrategies.CONST_MODIFIER)
// Multi-platform projects
val EXPECTED_DECLARATION_WITH_BODY by error0<FirSourceElement, KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -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)
}
}
@@ -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,
@@ -127,4 +127,9 @@ object SourceElementPositioningStrategies {
LightTreePositioningStrategies.IF_EXPRESSION,
PositioningStrategies.IF_EXPRESSION
)
val CONST_MODIFIER = SourceElementPositioningStrategy(
LightTreePositioningStrategies.CONST_MODIFIER,
PositioningStrategies.CONST_MODIFIER
)
}
@@ -35,6 +35,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
override val propertyCheckers: Set<FirPropertyChecker> = setOf(
FirInapplicableLateinitChecker,
FirDestructuringDeclarationChecker,
FirConstPropertyChecker,
)
override val classCheckers: Set<FirClassChecker> = setOf(
@@ -353,6 +353,9 @@ object PositioningStrategies {
@JvmField
val VARIANCE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD)
@JvmField
val CONST_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.CONST_KEYWORD)
@JvmField
val FOR_REDECLARATION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
override fun mark(element: PsiElement): List<TextRange> {
@@ -8,7 +8,7 @@ fun test() {
val <T> a0 = 0
val <T : __UNRESOLVED__> a1 = ""
val <T : String> a2 = 0
const val <T> a3 = 0
<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val <T> a3 = 0
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> val <T> a4 = 0
val <T> a5 by Delegate<Int>()
val <T> a6 by <!INAPPLICABLE_CANDIDATE!>Delegate<!><<!UNRESOLVED_REFERENCE!>T<!>>()
@@ -8,7 +8,7 @@ fun test() {
val <T> a0 = 0
val <T : __UNRESOLVED__> a1 = ""
val <T : String> a2 = 0
const val <T> a3 = 0
<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val <T> a3 = 0
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> val <T> a4 = 0
val <T> a5 by Delegate<Int>()
val <T> a6 by <!INAPPLICABLE_CANDIDATE!>Delegate<!><<!UNRESOLVED_REFERENCE!>T<!>>()
@@ -12,12 +12,12 @@ object A {
const val inObject: Int = 4
}
class B(const val constructor: Int = 5)
class B(<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val constructor: Int = 5)
abstract class C {
<!INCOMPATIBLE_MODIFIERS!>open<!> <!INCOMPATIBLE_MODIFIERS!>const<!> val x: Int = 6
<!INCOMPATIBLE_MODIFIERS!>open<!> <!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT, INCOMPATIBLE_MODIFIERS!>const<!> val x: Int = 6
<!INCOMPATIBLE_MODIFIERS!>abstract<!> <!INCOMPATIBLE_MODIFIERS!>const<!> val y: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>7<!>
<!INCOMPATIBLE_MODIFIERS!>abstract<!> <!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT, INCOMPATIBLE_MODIFIERS!>const<!> val y: Int = <!ABSTRACT_PROPERTY_WITH_INITIALIZER!>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_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val local: Int = 14
return 15
}
enum class MyEnum {
A {
const val inEnumEntry = 16
<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val inEnumEntry = 16
};
const val inEnum = 17
<!CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT!>const<!> val inEnum = 17
}
class Outer {