[FIR] Make reporting of local class diagnostics more consistent with K1

It would be nice to report more appropriate diagnostics at the
corresponding places, but right now it's more important to
fix greenness-redness problems. Plus, this is already how K1 works.

^KT-59900 Fixed
This commit is contained in:
Nikolay Lunyak
2023-08-30 15:54:11 +03:00
committed by Space Team
parent 9b114335fb
commit 0d19942d2c
12 changed files with 31 additions and 58 deletions
@@ -1,7 +1,7 @@
// !DUMP_CFG
val x = object {
class Nested {
<!NESTED_CLASS_NOT_ALLOWED!>class Nested<!> {
fun foo() {}
}
}
@@ -8,16 +8,16 @@ object A {
val a = object : Any() {
<!LOCAL_OBJECT_NOT_ALLOWED!>object D<!> {
<!LOCAL_OBJECT_NOT_ALLOWED!>object G<!>
<!LOCAL_INTERFACE_NOT_ALLOWED, NESTED_CLASS_NOT_ALLOWED!>interface Z<!>
<!NESTED_CLASS_NOT_ALLOWED!>interface Z<!>
}
<!LOCAL_INTERFACE_NOT_ALLOWED!>interface Y<!>
<!NESTED_CLASS_NOT_ALLOWED!>interface Y<!>
}
fun b() {
<!LOCAL_OBJECT_NOT_ALLOWED!>object E<!> {
<!LOCAL_OBJECT_NOT_ALLOWED!>object F<!>
<!LOCAL_INTERFACE_NOT_ALLOWED, NESTED_CLASS_NOT_ALLOWED!>interface M<!>
<!NESTED_CLASS_NOT_ALLOWED!>interface M<!>
}
<!LOCAL_INTERFACE_NOT_ALLOWED!>interface N<!>
@@ -25,7 +25,7 @@ object A {
val c = object : Any() {
val t = "test"
<!LOCAL_INTERFACE_NOT_ALLOWED!>interface U<!>
<!NESTED_CLASS_NOT_ALLOWED!>interface U<!>
}
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.visibility
@@ -21,10 +22,12 @@ object FirLocalEntityNotAllowedChecker : FirRegularClassChecker() {
return
}
val container = context.containingDeclarations.lastOrNull()
when {
declaration.classKind == ClassKind.OBJECT && !declaration.isCompanion ->
reporter.reportOn(declaration.source, FirErrors.LOCAL_OBJECT_NOT_ALLOWED, declaration.name, context)
declaration.classKind == ClassKind.INTERFACE ->
declaration.classKind == ClassKind.INTERFACE && container !is FirClass ->
reporter.reportOn(declaration.source, FirErrors.LOCAL_INTERFACE_NOT_ALLOWED, declaration.name, context)
else -> {
}
@@ -6,12 +6,13 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NESTED_CLASS_NOT_ALLOWED
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
@@ -22,25 +23,24 @@ 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
val containingDeclaration = context.containingDeclarations.lastOrNull() as? FirClass ?: 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)
}
}
else -> {}
// 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)
return
}
val containerIsLocal = containingDeclaration.effectiveVisibility == EffectiveVisibility.Local
if (!declaration.isInner && (containingDeclaration.isInner || containerIsLocal || context.isInsideAnonymousObject)) {
reporter.reportOn(declaration.source, NESTED_CLASS_NOT_ALLOWED, declaration.description, context)
}
}
private val CheckerContext.isInsideAnonymousObject get() = containingDeclarations.any { it is FirAnonymousObject }
// 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
@@ -6,7 +6,7 @@ enum class Enum {
<!NESTED_CLASS_NOT_ALLOWED!>class TestNested<!>
<!LOCAL_INTERFACE_NOT_ALLOWED, NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
<!NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
<!LOCAL_OBJECT_NOT_ALLOWED!>object TestObject<!>
@@ -6,7 +6,7 @@ enum class Enum {
<!NESTED_CLASS_NOT_ALLOWED!>class TestNested<!>
<!LOCAL_INTERFACE_NOT_ALLOWED, NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
<!NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
<!LOCAL_OBJECT_NOT_ALLOWED!>object TestObject<!>
@@ -1,8 +0,0 @@
// KT-6026 Exception on instantiating a nested class in an anonymous object
val oo = object {
// Forbidden in KT-13510
class Nested
fun f1() = Nested(<!TOO_MANY_ARGUMENTS!>11<!>)
}
+1
View File
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// KT-6026 Exception on instantiating a nested class in an anonymous object
val oo = object {
@@ -1,14 +0,0 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
fun foo() {
<!LOCAL_INTERFACE_NOT_ALLOWED!>interface a<!> {}
val b = object {
<!LOCAL_INTERFACE_NOT_ALLOWED!>interface c<!> {}
}
class A {
<!LOCAL_INTERFACE_NOT_ALLOWED, NESTED_CLASS_NOT_ALLOWED!>interface d<!> {}
}
val f = {
<!LOCAL_INTERFACE_NOT_ALLOWED!>interface e<!> {}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_VARIABLE
fun foo() {
@@ -1,11 +0,0 @@
class X {
val foo = object {
class Foo
}
fun test() {
object {
class Foo
}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
class X {
val foo = object {
<!NESTED_CLASS_NOT_ALLOWED!>class Foo<!>