diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt index ac1d02a23472da27c75d28be9c29686af516c76d..2fda2ca1ce9fa55ed3e26a2b9b34f062f03bcd91 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt @@ -3,6 +3,6 @@ fun foo() { @Ann class Local { // There should also be NESTED_CLASS_NOT_ALLOWED report here. - annotation class Nested + annotation class Nested } } diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/localEntitytNotAllowed.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/localEntitytNotAllowed.kt index b419ca218d9f05fe2d9d5eea1c75822c510b751f..a31b4de7fe3c60263d18663559a06d3d75621471 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/localEntitytNotAllowed.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/localEntitytNotAllowed.kt @@ -8,7 +8,7 @@ object A { val a = object : Any() { object D { object G - interface Z + interface Z } interface Y @@ -17,7 +17,7 @@ object A { fun b() { object E { object F - interface M + interface M } interface N 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 af7fa915ff864e267b5dca297b6d8d5284b1e069..26211e27badacd14c995ac746afc0b9a3f9dfea9 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 @@ -42,6 +42,9 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val VARIABLE_EXPECTED by error() val RETURN_NOT_ALLOWED by error() val DELEGATION_IN_INTERFACE by error() + val NESTED_CLASS_NOT_ALLOWED by error(PositioningStrategy.DECLARATION_NAME) { + parameter("declaration") + } } val UNRESOLVED by object : DiagnosticGroup("Unresolved") { 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 97a193e7da3e9056f21220b70deac7e8a56de0ce..65956d2f666f497b259cb0f3bb4650472f39b1c0 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 @@ -61,6 +61,7 @@ object FirErrors { val VARIABLE_EXPECTED by error0() val RETURN_NOT_ALLOWED by error0() val DELEGATION_IN_INTERFACE by error0() + val NESTED_CLASS_NOT_ALLOWED by error1(SourceElementPositioningStrategies.DECLARATION_NAME) // Unresolved val HIDDEN by error1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNestedClassChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNestedClassChecker.kt new file mode 100644 index 0000000000000000000000000000000000000000..f96b7f97fec956b24aeb07c38165238b9b1f3184 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNestedClassChecker.kt @@ -0,0 +1,50 @@ +/* + * 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.NESTED_CLASS_NOT_ALLOWED +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.* + +// No need to visit anonymous object since an anonymous object is always inner. This aligns with +// compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java:198 +object FirNestedClassChecker : FirRegularClassChecker() { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + // Local enums / objects / companion objects are handled with different diagnostic codes. + if ((declaration.classKind.isSingleton || declaration.classKind == ClassKind.ENUM_CLASS) && declaration.isLocal) return + val containingDeclaration = context.containingDeclarations.lastOrNull() ?: return + + when (containingDeclaration) { + is FirRegularClass -> { + if (!declaration.isInner && (containingDeclaration.isInner || containingDeclaration.isLocal)) { + reporter.reportOn(declaration.source, NESTED_CLASS_NOT_ALLOWED, declaration.description, context) + } + } + is FirClass<*> -> { + // Since 1.3, enum entries can contain inner classes only. + // Companion objects are reported with code WRONG_MODIFIER_CONTAINING_DECLARATION instead + if (containingDeclaration.classKind == ClassKind.ENUM_ENTRY && !declaration.isInner && !declaration.isCompanion) { + reporter.reportOn(declaration.source, NESTED_CLASS_NOT_ALLOWED, declaration.description, context) + } + } + } + } + + // Note: here we don't differentiate anonymous object like in FE1.0 + // (org.jetbrains.kotlin.resolve.ModifiersChecker.DetailedClassKind) because this case has been ruled out in the first place. + private val FirRegularClass.description: String + get() = when (classKind) { + ClassKind.CLASS -> "Class" + ClassKind.INTERFACE -> "Interface" + ClassKind.ENUM_CLASS -> "Enum class" + ClassKind.ENUM_ENTRY -> "Enum entry" + ClassKind.ANNOTATION_CLASS -> "Annotation class" + ClassKind.OBJECT -> if (this.isCompanion) "Companion object" else "Object" + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index afb752ccfecb508192190b449aafda0af5d80100..71f6d59d6f3e846fb8d2280e70e46d22b60f51f3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -98,6 +98,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_INTERFACE_N import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_OBJECT_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_COMPANION_OBJECTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NESTED_CLASS_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_VARARG_PARAMETERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY @@ -211,6 +212,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(VARIABLE_EXPECTED, "Variable expected") map.put(RETURN_NOT_ALLOWED, "'return' is not allowed here") map.put(DELEGATION_IN_INTERFACE, "Interfaces cannot use delegation") + map.put(NESTED_CLASS_NOT_ALLOWED, "{0} is not allowed here", TO_STRING) // Unresolved map.put(HIDDEN, "Symbol {0} is invisible", SYMBOL) 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 4a2f21a63a41a2682527ddc015d5138d93c15e13..9ab8cea05946a947fadd4daa9a63077a6d6498a7 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 @@ -60,6 +60,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirTypeParametersInObjectChecker, FirMemberFunctionChecker, FirMemberPropertyChecker, + FirNestedClassChecker, ) override val constructorCheckers: Set = setOf( diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 53677a69d91d02f36fdf173ddb0bd610d2ee5de1..e4fa8e010a56eb314d1d3a3b931e1f68dc9c0ea4 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -793,7 +793,11 @@ class RawFirBuilder( override fun visitClassOrObject(classOrObject: KtClassOrObject, data: Unit): FirElement { return withChildClassName( classOrObject.nameAsSafeName, - classOrObject.isLocal || classOrObject.getStrictParentOfType() != null + classOrObject.isLocal + // TODO: currently enum entry initializer is represented in FIR as an FirAnonymousObject. Because of this, all + // nested declarations are now marked local. This causes the FirNestedClassChecker to ignore some invalid programs. + // See KT-45115 + || classOrObject.getStrictParentOfType() != null ) { val classKind = when (classOrObject) { is KtObjectDeclaration -> ClassKind.OBJECT diff --git a/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughEnum_after.fir.kt b/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughEnum_after.fir.kt index fe5a977f93d322b4817d27793e870c63fa4ff2ad..2921d76da138a39366257330fb1d6c146ccc3ef7 100644 --- a/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughEnum_after.fir.kt +++ b/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughEnum_after.fir.kt @@ -11,7 +11,7 @@ enum class C { O_O } - class G + class G }, E4 { diff --git a/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughEnum_before.fir.kt b/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughEnum_before.fir.kt index 21659f70c73c285c1b42a4d5d78440cde57ad8f2..34f21aed8ef56ce5cf1ec3588eeebe8d7353b16a 100644 --- a/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughEnum_before.fir.kt +++ b/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughEnum_before.fir.kt @@ -11,7 +11,7 @@ enum class C { O_O } - class G + class G }, E4 { diff --git a/compiler/testData/diagnostics/tests/classObjects/InnerClassClassObject.fir.kt b/compiler/testData/diagnostics/tests/classObjects/InnerClassClassObject.fir.kt index 57d0532952a44ed78dbf63c9a3432ffbdc59059a..50728484184f0028fd3be15229a99aa67d8312f4 100644 --- a/compiler/testData/diagnostics/tests/classObjects/InnerClassClassObject.fir.kt +++ b/compiler/testData/diagnostics/tests/classObjects/InnerClassClassObject.fir.kt @@ -2,7 +2,7 @@ class A { inner class B { - companion object { } + companion object { } } } diff --git a/compiler/testData/diagnostics/tests/classObjects/multipleDissallowedDefaultObjects.fir.kt b/compiler/testData/diagnostics/tests/classObjects/multipleDissallowedDefaultObjects.fir.kt index 690eadf9944910d4f5aae16dc0c11bd89a50151d..ec34b594b82edb2a231b46090dc60aa898214aa5 100644 --- a/compiler/testData/diagnostics/tests/classObjects/multipleDissallowedDefaultObjects.fir.kt +++ b/compiler/testData/diagnostics/tests/classObjects/multipleDissallowedDefaultObjects.fir.kt @@ -1,10 +1,10 @@ class A { inner class I { - companion object A + companion object A - companion object B + companion object B - companion object C + companion object C } } diff --git a/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_after.fir.kt b/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_after.fir.kt deleted file mode 100644 index a312890267b474c810254ca025128d44e914b396..0000000000000000000000000000000000000000 --- a/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_after.fir.kt +++ /dev/null @@ -1,16 +0,0 @@ -// !LANGUAGE: +NestedClassesInEnumEntryShouldBeInner - -enum class E { - FIRST, - SECOND { - class A - }; -} - -val foo: Any.() -> Unit = {} - -fun f1() = E.FIRST.foo() -fun f2() = E.FIRST.(foo)() -fun f3() = E.SECOND.foo() -fun f4() = E.SECOND.(foo)() -fun f5() = E.SECOND.A() diff --git a/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_after.kt b/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_after.kt index 85ccb01c43ea169fd974351a4c129004d6f42452..13969e49f5f180ca10d5f91e577512035e7cdbfe 100644 --- a/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_after.kt +++ b/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_after.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +NestedClassesInEnumEntryShouldBeInner enum class E { diff --git a/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_before.fir.kt b/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_before.fir.kt index 90a415dcc12ff9674ba511230d33f5aed984aea9..cbbe5d2cd96f4989e7fa23344e694e6c2dd50533 100644 --- a/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_before.fir.kt +++ b/compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry_before.fir.kt @@ -3,7 +3,7 @@ enum class E { FIRST, SECOND { - class A + class A }; } diff --git a/compiler/testData/diagnostics/tests/enum/inner/insideInnerClassNotAllowed.fir.kt b/compiler/testData/diagnostics/tests/enum/inner/insideInnerClassNotAllowed.fir.kt deleted file mode 100644 index 5adc47b7eb8484a55f5aefeae82c5f35e60a8837..0000000000000000000000000000000000000000 --- a/compiler/testData/diagnostics/tests/enum/inner/insideInnerClassNotAllowed.fir.kt +++ /dev/null @@ -1,7 +0,0 @@ -class A { - inner class B { - enum class E { - ENTRY - } - } -} diff --git a/compiler/testData/diagnostics/tests/enum/inner/insideInnerClassNotAllowed.kt b/compiler/testData/diagnostics/tests/enum/inner/insideInnerClassNotAllowed.kt index 17f11e03593288569bb949a2d41cd71345a6e4a7..fab6de96ba12bc82f463ebcdad5eafab5929ba11 100644 --- a/compiler/testData/diagnostics/tests/enum/inner/insideInnerClassNotAllowed.kt +++ b/compiler/testData/diagnostics/tests/enum/inner/insideInnerClassNotAllowed.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL class A { inner class B { enum class E { diff --git a/compiler/testData/diagnostics/tests/enum/inner/twoEnumsInClassObjectAndInnerClass.fir.kt b/compiler/testData/diagnostics/tests/enum/inner/twoEnumsInClassObjectAndInnerClass.fir.kt deleted file mode 100644 index 49cedfbdd6f4851294e3910a4bb6af341717c1f4..0000000000000000000000000000000000000000 --- a/compiler/testData/diagnostics/tests/enum/inner/twoEnumsInClassObjectAndInnerClass.fir.kt +++ /dev/null @@ -1,9 +0,0 @@ -class A { - companion object { - enum class E { ENTRY } // OK - } - - inner class B { - enum class E { ENTRY } - } -} diff --git a/compiler/testData/diagnostics/tests/enum/inner/twoEnumsInClassObjectAndInnerClass.kt b/compiler/testData/diagnostics/tests/enum/inner/twoEnumsInClassObjectAndInnerClass.kt index 1fe8e7f37bdaabd0e1e202ba80f2b394a11dbe65..066d84d8a39b2e2ce076ba038a06f8d55a69c234 100644 --- a/compiler/testData/diagnostics/tests/enum/inner/twoEnumsInClassObjectAndInnerClass.kt +++ b/compiler/testData/diagnostics/tests/enum/inner/twoEnumsInClassObjectAndInnerClass.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL class A { companion object { enum class E { ENTRY } // OK diff --git a/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.fir.kt b/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.fir.kt index a660ebca0bd268ebf65af5b92f948b7b711998f6..c67341d8b48d388316a0d4ace00553ff59a71f26 100644 --- a/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.fir.kt +++ b/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.fir.kt @@ -30,4 +30,4 @@ class Derived: Base() { inline final override fun foo(a: Int) { } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inner/annotationInInnerClass.fir.kt b/compiler/testData/diagnostics/tests/inner/annotationInInnerClass.fir.kt index 903b7c13869ce11433906eb5a92fd6925097cdcc..687712ccd5e935b447c43347fdbf1bc2e2455835 100644 --- a/compiler/testData/diagnostics/tests/inner/annotationInInnerClass.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/annotationInInnerClass.fir.kt @@ -1,5 +1,5 @@ class Outer { inner class Inner { - annotation class TestNestedAnnotation + annotation class TestNestedAnnotation } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inner/enumInInnerClass.fir.kt b/compiler/testData/diagnostics/tests/inner/enumInInnerClass.fir.kt index 8ca09096ec649d93426558213d6349f18c69adac..56c7e6229240b3d31ddf6b25ca4930e15229a84d 100644 --- a/compiler/testData/diagnostics/tests/inner/enumInInnerClass.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/enumInInnerClass.fir.kt @@ -1,5 +1,5 @@ class Outer { inner class Inner { - enum class TestNestedEnum + enum class TestNestedEnum } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv11.fir.kt b/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv11.fir.kt index 6391c59d91bd4487eb860191d8ff821c04a6f95d..79cc723a17bc675ba7f149699a93604d55b2cff4 100644 --- a/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv11.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv11.fir.kt @@ -4,9 +4,9 @@ enum class Enum { ENTRY_WITH_CLASS { inner class TestInner - class TestNested + class TestNested - interface TestInterface + interface TestInterface object TestObject diff --git a/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv12.fir.kt b/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv12.fir.kt index ba98e4a6478b139a84d4c50aa66c8e207095c2d5..51959e76b860a867f31893a86e316be7869af3d8 100644 --- a/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv12.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv12.fir.kt @@ -4,9 +4,9 @@ enum class Enum { ENTRY_WITH_CLASS { inner class TestInner - class TestNested + class TestNested - interface TestInterface + interface TestInterface object TestObject diff --git a/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv13.fir.kt b/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv13.fir.kt index 2f2869d3a40576aa964721e39c2366c50e625b7e..5fa11b1dc15371c930f397738c25c57c5d3a8b56 100644 --- a/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv13.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/innerClassInEnumEntryClass_lv13.fir.kt @@ -4,9 +4,9 @@ enum class Enum { ENTRY_WITH_CLASS { inner class TestInner - class TestNested + class TestNested - interface TestInterface + interface TestInterface object TestObject diff --git a/compiler/testData/diagnostics/tests/inner/interfaceInInnerClass.fir.kt b/compiler/testData/diagnostics/tests/inner/interfaceInInnerClass.fir.kt index a93f9f4155a695a9b8427d599807a0fbac0bc3da..963d6d729900bce74454cc1196dd06654e215c13 100644 --- a/compiler/testData/diagnostics/tests/inner/interfaceInInnerClass.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/interfaceInInnerClass.fir.kt @@ -1,5 +1,5 @@ class Outer { inner class Inner { - interface TestNestedInterface + interface TestNestedInterface } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_after.fir.kt b/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_after.fir.kt deleted file mode 100644 index 18778d77efb84a5ec1ce9564ade20c5b5374fcf4..0000000000000000000000000000000000000000 --- a/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_after.fir.kt +++ /dev/null @@ -1,26 +0,0 @@ -// !LANGUAGE: +NestedClassesInEnumEntryShouldBeInner - -class A { - inner class B { - class C - } - - fun foo() { - class B { - class C - } - } -} - -fun foo() { - class B { - class C - } -} - - -enum class E { - E1 { - class D - } -} diff --git a/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_after.kt b/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_after.kt index 8d16e2aa03e4b75115b9399ae288b93663828ddd..813f1c2965d892cc748aabc986a3baf2d1ecd5b7 100644 --- a/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_after.kt +++ b/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_after.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +NestedClassesInEnumEntryShouldBeInner class A { diff --git a/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_before.fir.kt b/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_before.fir.kt index 7e718dae2bb498f0bf248edf5fb6e19eeaae9371..7b44479fd6f97f2cb0156ede762982982dff8bc8 100644 --- a/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_before.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/nestedClassNotAllowed_before.fir.kt @@ -2,25 +2,25 @@ class A { inner class B { - class C + class C } fun foo() { class B { - class C + class C } } } fun foo() { class B { - class C + class C } } enum class E { E1 { - class D + class D } } diff --git a/compiler/testData/diagnostics/tests/inner/nestedObject.fir.kt b/compiler/testData/diagnostics/tests/inner/nestedObject.fir.kt index 35729b8cae873dfc8bc5ba4d49148dc5704f9892..a1527374a950df8007569ab65a876b3b02b600ae 100644 --- a/compiler/testData/diagnostics/tests/inner/nestedObject.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/nestedObject.fir.kt @@ -1,12 +1,12 @@ // SKIP_TXT class Outer { inner class Inner1 { - object Obj1 + object Obj1 - companion object Obj2 + companion object Obj2 inner class Inner2 { - object Obj3 + object Obj3 } } } diff --git a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClass.fir.kt b/compiler/testData/diagnostics/tests/localClasses/localAnnotationClass.fir.kt index 816f17a81b139ebbf8f658cdc656b70caf11313b..12c03ea7511e39350c0284a02e582a8e32ca51b9 100644 --- a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClass.fir.kt +++ b/compiler/testData/diagnostics/tests/localClasses/localAnnotationClass.fir.kt @@ -4,6 +4,6 @@ fun f() { annotation class Anno @Anno class Local { - annotation class Nested + annotation class Nested } } diff --git a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.fir.kt b/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.fir.kt deleted file mode 100644 index 6237efead020aa3a217117a29ac77acefd494cee..0000000000000000000000000000000000000000 --- a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.fir.kt +++ /dev/null @@ -1,9 +0,0 @@ -// !LANGUAGE: +ProhibitLocalAnnotations - -fun f() { - annotation class Anno - - @Anno class Local { - annotation class Nested - } -} diff --git a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.kt b/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.kt index 835df6f3cabb8aa65e2df37dc7bb96df6d489de9..7c78bea1354b1ba9771726b8c8f62bc07652b33c 100644 --- a/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.kt +++ b/compiler/testData/diagnostics/tests/localClasses/localAnnotationClassError.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +ProhibitLocalAnnotations fun f() { diff --git a/compiler/testData/diagnostics/tests/localInterfaces.fir.kt b/compiler/testData/diagnostics/tests/localInterfaces.fir.kt index d02f565bcfb6363a543cb2208c0fb8c9b4edd3e1..d71e05f5bf7bb03fe12bb447da090fa8d2301c07 100644 --- a/compiler/testData/diagnostics/tests/localInterfaces.fir.kt +++ b/compiler/testData/diagnostics/tests/localInterfaces.fir.kt @@ -6,9 +6,9 @@ fun foo() { interface c {} } class A { - interface d {} + interface d {} } val f = { interface e {} } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/modifiers/const/applicability.fir.kt b/compiler/testData/diagnostics/tests/modifiers/const/applicability.fir.kt index b6d572f84d91f78c3bfa0e54a1a022a5caf2b81d..81b6a56d5a80adc1de32a0c692f9aa7cb55ef061 100644 --- a/compiler/testData/diagnostics/tests/modifiers/const/applicability.fir.kt +++ b/compiler/testData/diagnostics/tests/modifiers/const/applicability.fir.kt @@ -61,7 +61,7 @@ enum class MyEnum { class Outer { inner class Inner { - object C { + object C { const val a = 18 } } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt index 24c68a085d9ec7d9fa8dadaa8238547109d71203..068fa5796e9aac02df25f4f1b8431be221c195bc 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt @@ -173,7 +173,10 @@ internal class NonReanalyzableDeclarationStructureElement( firFile, onDeclarationEnter = { firDeclaration -> when { - firDeclaration.isGeneratedDeclaration -> DiagnosticCollectorDeclarationAction.SKIP + // Some generated declaration contains structures that we need to check. For example the FIR representation of an + // enum entry initializer, when present, is a generated anonymous object of kind `ENUM_ENTRY`. + firDeclaration.isGeneratedDeclaration -> + DiagnosticCollectorDeclarationAction.SKIP_CURRENT_DECLARATION_AND_CHECK_NESTED firDeclaration is FirFile -> DiagnosticCollectorDeclarationAction.CHECK_CURRENT_DECLARATION_AND_CHECK_NESTED firDeclaration == fir -> { inCurrentDeclaration = true diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index d27b5afeb025f1dd64b363c39a9a6671fe6a6316..18b7697b6c73b3ed6c197a202515d3b8f1d45350 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -99,6 +99,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NESTED_CLASS_NOT_ALLOWED) { firDiagnostic -> + NestedClassNotAllowedImpl( + firDiagnostic.a, + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.HIDDEN) { firDiagnostic -> HiddenImpl( firSymbolBuilder.buildSymbol(firDiagnostic.a.fir as FirDeclaration), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index f5ca7841dce15e0cf405359622dddc7e4835d4ef..52a7d860d88f0dca3f69bfd7da9608cfcd5497f8 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -83,6 +83,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = DelegationInInterface::class } + abstract class NestedClassNotAllowed : KtFirDiagnostic() { + override val diagnosticClass get() = NestedClassNotAllowed::class + abstract val declaration: String + } + abstract class Hidden : KtFirDiagnostic() { override val diagnosticClass get() = Hidden::class abstract val hidden: KtSymbol diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 66f5656e0d0930901e6e78bf23c170f7859965f6..828b94230713e38b9a2ad1b808bb824c69cbec0f 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -114,6 +114,14 @@ internal class DelegationInInterfaceImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class NestedClassNotAllowedImpl( + override val declaration: String, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.NestedClassNotAllowed(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class HiddenImpl( override val hidden: KtSymbol, firDiagnostic: FirPsiDiagnostic<*>,