[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 // !DUMP_CFG
val x = object { val x = object {
class Nested { <!NESTED_CLASS_NOT_ALLOWED!>class Nested<!> {
fun foo() {} fun foo() {}
} }
} }
@@ -8,16 +8,16 @@ object A {
val a = object : Any() { val a = object : Any() {
<!LOCAL_OBJECT_NOT_ALLOWED!>object D<!> { <!LOCAL_OBJECT_NOT_ALLOWED!>object D<!> {
<!LOCAL_OBJECT_NOT_ALLOWED!>object G<!> <!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() { fun b() {
<!LOCAL_OBJECT_NOT_ALLOWED!>object E<!> { <!LOCAL_OBJECT_NOT_ALLOWED!>object E<!> {
<!LOCAL_OBJECT_NOT_ALLOWED!>object F<!> <!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<!> <!LOCAL_INTERFACE_NOT_ALLOWED!>interface N<!>
@@ -25,7 +25,7 @@ object A {
val c = object : Any() { val c = object : Any() {
val t = "test" 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.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.diagnostics.reportOn 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.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.visibility import org.jetbrains.kotlin.fir.declarations.utils.visibility
@@ -21,10 +22,12 @@ object FirLocalEntityNotAllowedChecker : FirRegularClassChecker() {
return return
} }
val container = context.containingDeclarations.lastOrNull()
when { when {
declaration.classKind == ClassKind.OBJECT && !declaration.isCompanion -> declaration.classKind == ClassKind.OBJECT && !declaration.isCompanion ->
reporter.reportOn(declaration.source, FirErrors.LOCAL_OBJECT_NOT_ALLOWED, declaration.name, context) 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) reporter.reportOn(declaration.source, FirErrors.LOCAL_INTERFACE_NOT_ALLOWED, declaration.name, context)
else -> { else -> {
} }
@@ -6,12 +6,13 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind 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.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NESTED_CLASS_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NESTED_CLASS_NOT_ALLOWED
import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.declarations.utils.isLocal
@@ -22,25 +23,24 @@ object FirNestedClassChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
// Local enums / objects / companion objects are handled with different diagnostic codes. // Local enums / objects / companion objects are handled with different diagnostic codes.
if ((declaration.classKind.isSingleton || declaration.classKind == ClassKind.ENUM_CLASS) && declaration.isLocal) return 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) { // Since 1.3, enum entries can contain inner classes only.
is FirRegularClass -> { // Companion objects are reported with code WRONG_MODIFIER_CONTAINING_DECLARATION instead
if (!declaration.isInner && (containingDeclaration.isInner || containingDeclaration.isLocal)) { if (containingDeclaration.classKind == ClassKind.ENUM_ENTRY && !declaration.isInner && !declaration.isCompanion) {
reporter.reportOn(declaration.source, NESTED_CLASS_NOT_ALLOWED, declaration.description, context) reporter.reportOn(declaration.source, NESTED_CLASS_NOT_ALLOWED, declaration.description, context)
} return
} }
is FirClass -> {
// Since 1.3, enum entries can contain inner classes only. val containerIsLocal = containingDeclaration.effectiveVisibility == EffectiveVisibility.Local
// Companion objects are reported with code WRONG_MODIFIER_CONTAINING_DECLARATION instead
if (containingDeclaration.classKind == ClassKind.ENUM_ENTRY && !declaration.isInner && !declaration.isCompanion) { if (!declaration.isInner && (containingDeclaration.isInner || containerIsLocal || context.isInsideAnonymousObject)) {
reporter.reportOn(declaration.source, NESTED_CLASS_NOT_ALLOWED, declaration.description, context) reporter.reportOn(declaration.source, NESTED_CLASS_NOT_ALLOWED, declaration.description, context)
}
}
else -> {}
} }
} }
private val CheckerContext.isInsideAnonymousObject get() = containingDeclarations.any { it is FirAnonymousObject }
// Note: here we don't differentiate anonymous object like in FE1.0 // 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. // (org.jetbrains.kotlin.resolve.ModifiersChecker.DetailedClassKind) because this case has been ruled out in the first place.
private val FirRegularClass.description: String private val FirRegularClass.description: String
@@ -6,7 +6,7 @@ enum class Enum {
<!NESTED_CLASS_NOT_ALLOWED!>class TestNested<!> <!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<!> <!LOCAL_OBJECT_NOT_ALLOWED!>object TestObject<!>
@@ -6,7 +6,7 @@ enum class Enum {
<!NESTED_CLASS_NOT_ALLOWED!>class TestNested<!> <!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<!> <!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 // KT-6026 Exception on instantiating a nested class in an anonymous object
val oo = 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 // !DIAGNOSTICS: -UNUSED_VARIABLE
fun foo() { 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 { class X {
val foo = object { val foo = object {
<!NESTED_CLASS_NOT_ALLOWED!>class Foo<!> <!NESTED_CLASS_NOT_ALLOWED!>class Foo<!>