diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/localAnnotationClass.kt index ac1d02a2347..2fda2ca1ce9 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 b419ca218d9..a31b4de7fe3 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 af7fa915ff8..26211e27bad 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 97a193e7da3..65956d2f666 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 00000000000..f96b7f97fec --- /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 afb752ccfec..71f6d59d6f3 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 4a2f21a63a4..9ab8cea0594 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 53677a69d91..e4fa8e010a5 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 fe5a977f93d..2921d76da13 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 21659f70c73..34f21aed8ef 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 57d0532952a..50728484184 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 690eadf9944..ec34b594b82 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 a312890267b..00000000000 --- 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 85ccb01c43e..13969e49f5f 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 90a415dcc12..cbbe5d2cd96 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 5adc47b7eb8..00000000000 --- 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 17f11e03593..fab6de96ba1 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 49cedfbdd6f..00000000000 --- 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 1fe8e7f37bd..066d84d8a39 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 a660ebca0bd..c67341d8b48 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 903b7c13869..687712ccd5e 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 8ca09096ec6..56c7e622924 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 6391c59d91b..79cc723a17b 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 ba98e4a6478..51959e76b86 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 2f2869d3a40..5fa11b1dc15 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 a93f9f4155a..963d6d72990 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 18778d77efb..00000000000 --- 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 8d16e2aa03e..813f1c2965d 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 7e718dae2bb..7b44479fd6f 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 35729b8cae8..a1527374a95 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 816f17a81b1..12c03ea7511 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 6237efead02..00000000000 --- 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 835df6f3cab..7c78bea1354 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 d02f565bcfb..d71e05f5bf7 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 b6d572f84d9..81b6a56d5a8 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 24c68a085d9..068fa5796e9 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 d27b5afeb02..18b7697b6c7 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 f5ca7841dce..52a7d860d88 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 66f5656e0d0..828b9423071 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<*>,