FIR checker: report UNINITIALIZED_ENUM_(ENTRY|COMPANION)

This commit is contained in:
Jinseong Jeon
2021-04-02 10:50:10 -07:00
committed by Mikhail Glukhikh
parent ad9b962536
commit 619360fe4d
22 changed files with 500 additions and 25 deletions
@@ -23,7 +23,7 @@ enum class Planet(val m: Double, internal val r: Double) {
}
};
val g: Double = G * m / (r * r)
val g: Double = <!UNINITIALIZED_VARIABLE!>G<!> * m / (r * r)
abstract fun sayHello()
@@ -30900,6 +30900,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/testsWithStdLib/elvisOnUnitInLet.kt");
}
@Test
@TestMetadata("enumEntryInitialization.kt")
public void testEnumEntryInitialization() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/enumEntryInitialization.kt");
}
@Test
@TestMetadata("exitProcess.kt")
public void testExitProcess() throws Exception {
@@ -19,10 +19,7 @@ import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.Name
@@ -529,6 +526,12 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val UNINITIALIZED_VARIABLE by error<FirSourceElement, KtSimpleNameExpression> {
parameter<FirPropertySymbol>("variable")
}
val UNINITIALIZED_ENUM_ENTRY by error<FirSourceElement, KtSimpleNameExpression> {
parameter<FirVariableSymbol<FirEnumEntry>>("enumEntry")
}
val UNINITIALIZED_ENUM_COMPANION by error<FirSourceElement, KtSimpleNameExpression>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<FirRegularClassSymbol>("enumClass")
}
val VAL_REASSIGNMENT by error<FirSourceElement, KtExpression> {
parameter<FirVariableSymbol<*>>("variable")
}
@@ -19,12 +19,14 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.SourceElementPositioningStr
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
@@ -322,6 +324,8 @@ object FirErrors {
// Control flow diagnostics
val UNINITIALIZED_VARIABLE by error1<FirSourceElement, KtSimpleNameExpression, FirPropertySymbol>()
val UNINITIALIZED_ENUM_ENTRY by error1<FirSourceElement, KtSimpleNameExpression, FirVariableSymbol<FirEnumEntry>>()
val UNINITIALIZED_ENUM_COMPANION by error1<FirSourceElement, KtSimpleNameExpression, FirRegularClassSymbol>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val VAL_REASSIGNMENT by error1<FirSourceElement, KtExpression, FirVariableSymbol<*>>()
val VAL_REASSIGNMENT_VIA_BACKING_FIELD by warning1<FirSourceElement, KtExpression, FirPropertySymbol>()
val VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR by error1<FirSourceElement, KtExpression, FirPropertySymbol>()
@@ -21,11 +21,14 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
@@ -158,6 +161,16 @@ inline fun <reified T : Any> FirQualifiedAccessExpression.getDeclaration(): T? {
fun FirSymbolOwner<*>.getContainingClass(context: CheckerContext): FirClassLikeDeclaration<*>? =
this.safeAs<FirCallableMemberDeclaration<*>>()?.containingClass()?.toSymbol(context.session)?.fir
fun FirClassLikeSymbol<*>.outerClass(context: CheckerContext): FirClassLikeSymbol<*>? {
if (this !is FirClassSymbol<*>) return null
val outerClassId = classId.outerClassId ?: return null
return context.session.symbolProvider.getClassLikeSymbolByFqName(outerClassId)
}
fun FirClass<*>.outerClass(context: CheckerContext): FirClass<*>? {
return symbol.outerClass(context)?.fir as? FirClass<*>
}
/**
* Returns the FirClassLikeDeclaration that the
* sequence of FirTypeAlias'es points to starting
@@ -14,8 +14,10 @@ import org.jetbrains.kotlin.fir.analysis.checkers.modality
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.containingClassAttr
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
import org.jetbrains.kotlin.lexer.KtTokens
@@ -175,6 +177,12 @@ internal fun FirRegularClass.isInlineOrValueClass(): Boolean {
return isInline || hasModifier(KtTokens.VALUE_KEYWORD)
}
internal val FirDeclaration.isEnumEntryInitializer: Boolean
get() {
if (this !is FirConstructor || !this.isPrimary) return false
return (containingClassAttr as? ConeClassLookupTagWithFixedSymbol)?.symbol?.fir?.classKind == ClassKind.ENUM_ENTRY
}
internal val FirMemberDeclaration.isLocalMember: Boolean
get() = when (this) {
is FirProperty -> this.isLocal
@@ -0,0 +1,227 @@
/*
* 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.expression
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSymbolOwner
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.isEnumEntryInitializer
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass
import org.jetbrains.kotlin.fir.analysis.checkers.outerClass
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.*
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirLambdaArgumentExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
object FirUninitializedEnumChecker : FirQualifiedAccessChecker() {
// Initialization order: member property initializers, enum entries, companion object (including members in it).
//
// When JVM loads a class, the corresponding class initializer, a.k.a. <clinit>, is executed first.
// Kotlin (and Java as well) converts enum entries as static final field, which is initialized in that <clinit>:
// enum class E(...) {
// E1, E2, ...
// }
// ~>
// class E {
// final static E1, E2, ...
// static { // <clinit>
// E1 = new E(...)
// ...
// }
// }
//
// Note that, when initializing enum entries, now we call the enum class's constructor, a.k.a. <init>, to initialize non-final
// instance members. Therefore, if there is a member property in the enum class, and if that member has an access to enum entries,
// that is an illegal access since enum entries are not yet initialized:
// enum class E(...) {
// E1, E2, ...
// val m1 = E1
// }
// ~>
// class E {
// E m1 ...
// E(...) { // <init>
// m1 = E1
// }
// final static E1, E2, ...
// static { // <clinit>
// E1 = new E(...)
// ...
// }
// }
//
// A companion object is desugared to a static final singleton, and initialized in <clinit> too. However, enum lowering goes first,
// or in other words, companion object lowering goes last. Thus, any other things initialized in <clinit>, including enum entries,
// should not have access to companion object and members in it.
//
// See related discussions:
// https://youtrack.jetbrains.com/issue/KT-6054
// https://youtrack.jetbrains.com/issue/KT-11769
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val source = expression.source ?: return
if (source.kind is FirFakeSourceElementKind) return
val reference = expression.calleeReference as? FirResolvedNamedReference ?: return
val calleeDeclaration = reference.resolvedSymbol.fir
val calleeContainingClass = calleeDeclaration.getContainingClass(context) as? FirRegularClass ?: return
// We're looking for members/entries/companion object in an enum class or members in companion object of an enum class.
val calleeIsInsideEnum = calleeContainingClass.isEnumClass
val calleeIsInsideEnumCompanion =
calleeContainingClass.isCompanion && (calleeContainingClass.outerClass(context) as? FirRegularClass)?.isEnumClass == true
if (!calleeIsInsideEnum && !calleeIsInsideEnumCompanion) return
val enumClass =
if (calleeIsInsideEnum) calleeContainingClass
else calleeContainingClass.outerClass(context) as? FirRegularClass ?: return
// An accessed context within the enum class of interest. We should look up until either enum members or enum entries are found,
// not just last containing declaration. For example,
// enum class Fruit(...) {
// APPLE(...);
// companion object {
// val common = ...
// }
// val score = ... <!>common<!>
// val score2 = { ... <!>common<!> }()
// }
// companion object is not initialized for both member properties. The former has the property itself as the last containing
// declaration, whereas the latter has an anonymous function instead. For both cases, we're looking for member properties as an
// accessed context.
val accessedContext = context.containingDeclarations.lastOrNull {
// To not raise an error for an access from another enum class, e.g.,
// enum class EnumCompanion4(...) {
// INSTANCE(EnumCompanion2.foo())
// }
// find an accessed context within the same enum class.
(it as? FirSymbolOwner<*>)?.getContainingClass(context) == enumClass
} ?: return
val enumMemberProperties = enumClass.declarations.filterIsInstance<FirProperty>()
val enumEntries = enumClass.declarations.filterIsInstance<FirEnumEntry>()
// When checking enum member properties, accesses to enum entries in lazy delegation is legitimate, e.g.,
// enum JvmTarget(...) {
// JVM_1_6, ...
// val bytecodeVersion: ... by lazy {
// when (this) {
// JVM_1_6 -> ...
// }
// }
if (accessedContext in enumMemberProperties) {
val lazyDelegation = (accessedContext as FirProperty).lazyDelegation
if (lazyDelegation != null && lazyDelegation == context.containingDeclarations.lastOrNull()) {
return
}
}
// When checking enum entries, only entry initializer matters. For example,
// enum class EnumCompanion(...) {
// ANOTHER {
// override fun bar() = foo() // At this point, companion object is initialized
// }
// abstract bar(): ...
// companion object {
// fun foo() = ...
// }
// }
if (accessedContext in enumEntries && context.containingDeclarations.lastOrNull()?.isEnumEntryInitializer != true) {
return
}
// Members inside the companion object of an enum class
if (calleeContainingClass == enumClass.companionObject) {
// Uninitialized from the point of view of members or enum entries of that enum class
if (accessedContext in enumMemberProperties || accessedContext in enumEntries) {
if (calleeDeclaration is FirProperty) {
// From KT-11769
// enum class Fruit(...) {
// APPLE(...);
// companion object {
// val common = ...
// }
// val score = ... <!>common<!>
// }
reporter.reportOn(source, FirErrors.UNINITIALIZED_VARIABLE, calleeDeclaration.symbol, context)
} else {
// enum class EnumCompanion2(...) {
// INSTANCE(<!>foo<!>())
// companion object {
// fun foo() = ...
// }
// }
// <!>Companion<!>.foo() v.s. <!>foo<!>()
if ((expression.explicitReceiver as? FirResolvedQualifier)?.symbol?.fir == enumClass.companionObject) {
reporter.reportOn(
expression.explicitReceiver!!.source,
FirErrors.UNINITIALIZED_ENUM_COMPANION,
enumClass.symbol,
context
)
} else {
reporter.reportOn(
expression.calleeReference.source,
FirErrors.UNINITIALIZED_ENUM_COMPANION,
enumClass.symbol,
context
)
}
}
}
}
// The enum entries of an enum class
if (calleeDeclaration in enumEntries) {
val calleeEnumEntry = calleeDeclaration as FirEnumEntry
// Uninitialized from the point of view of members of that enum class
if (accessedContext in enumMemberProperties) {
// From KT-6054
// enum class MyEnum {
// A, B;
// val x = when(this) {
// <!>A<!> -> ...
// <!>B<!> -> ...
// }
// }
reporter.reportOn(source, FirErrors.UNINITIALIZED_ENUM_ENTRY, calleeEnumEntry.symbol, context)
}
// enum class A(...) {
// A1(<!>A2<!>),
// A2(...),
// A3(<!>A3<!>)
// }
if (accessedContext in enumEntries) {
// Technically, this is equal to `enumEntries.indexOf(accessedContext) <= enumEntries.indexOf(calleeDeclaration)`.
// Instead of double `indexOf`, we can iterate entries just once until either one appears.
var precedingEntry: FirEnumEntry? = null
enumEntries.forEach {
if (precedingEntry != null) return@forEach
if (it == calleeEnumEntry || it == accessedContext) {
precedingEntry = it
}
}
if (precedingEntry == accessedContext) {
reporter.reportOn(source, FirErrors.UNINITIALIZED_ENUM_ENTRY, calleeEnumEntry.symbol, context)
}
}
}
}
private val FirProperty.lazyDelegation: FirAnonymousFunction?
get() {
if (delegate == null || delegate !is FirFunctionCall) return null
val delegateCall = delegate as FirFunctionCall
val callee =
(delegateCall.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol?.fir as? FirSimpleFunction ?: return null
if (callee.symbol.callableId.asSingleFqName().asString() != "kotlin.lazy") return null
val lazyCallArgument = delegateCall.argumentList.arguments.singleOrNull() as? FirLambdaArgumentExpression ?: return null
return lazyCallArgument.expression as? FirAnonymousFunction
}
}
@@ -220,6 +220,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_ON_LHS_OF_DOT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNEXPECTED_SAFE_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_ENUM_COMPANION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_ENUM_ENTRY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_VARIABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNNECESSARY_LATEINIT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNNECESSARY_NOT_NULL_ASSERTION
@@ -722,6 +724,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
// Control flow diagnostics
map.put(UNINITIALIZED_VARIABLE, "{0} must be initialized before access", VARIABLE_NAME)
map.put(UNINITIALIZED_ENUM_ENTRY, "Enum entry ''{0}'' is uninitialized here", VARIABLE_NAME)
map.put(UNINITIALIZED_ENUM_COMPANION, "Companion object of enum class ''{0}'' is uninitialized here", SYMBOL)
map.put(VAL_REASSIGNMENT, "Val cannot be reassigned", VARIABLE_NAME)
map.put(VAL_REASSIGNMENT_VIA_BACKING_FIELD, "Reassignment of read-only property via backing field is deprecated", VARIABLE_NAME)
map.put(VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR, "Reassignment of read-only property via backing field", VARIABLE_NAME)
@@ -27,6 +27,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirTypeArgumentsNotAllowedExpressionChecker,
FirTypeParameterInQualifiedAccessChecker,
FirSealedClassConstructorCallChecker,
FirUninitializedEnumChecker,
)
override val functionCallCheckers: Set<FirFunctionCallChecker> = setOf(
@@ -9,7 +9,7 @@ enum class B(val x: Int) {
}
enum class C(val x: Int) {
C1(SUM),
C1(<!UNINITIALIZED_VARIABLE!>SUM<!>),
C2(1);
companion object {
@@ -26,13 +26,14 @@ enum class Fruit(personal: Int) {
val common = 20
}
val score = personal + common
val score = personal + <!UNINITIALIZED_VARIABLE!>common<!>
val score2 = { personal + <!UNINITIALIZED_VARIABLE!>common<!> }()
}
// Another example from KT-11769
enum class EnumCompanion1(val x: Int) {
INSTANCE(Companion.foo()),
ANOTHER(foo());
INSTANCE(<!UNINITIALIZED_ENUM_COMPANION!>Companion<!>.foo()),
ANOTHER(<!UNINITIALIZED_ENUM_COMPANION!>foo<!>());
companion object {
fun foo() = 42
@@ -40,7 +41,7 @@ enum class EnumCompanion1(val x: Int) {
}
// Also should be reported for implicit receiver
enum class EnumCompanion2(val x: Int) {
INSTANCE(foo());
INSTANCE(<!UNINITIALIZED_ENUM_COMPANION!>foo<!>());
companion object {
fun foo() = 42
@@ -53,3 +54,28 @@ enum class EnumCompanion3(val x: Int) {
companion object
}
interface ExtractableCodeDescriptor {
fun isInterface(): Boolean
}
enum class ExtractionTarget(val targetName: String) {
FUNCTION("function") {
override fun isAvailable(descriptor: ExtractableCodeDescriptor) = true
},
LAZY_PROPERTY("lazy property") {
override fun isAvailable(descriptor: ExtractableCodeDescriptor): Boolean {
// Should not report UNINITIALIZED_ENUM_COMPANION
return checkNotTrait(descriptor)
}
};
abstract fun isAvailable(descriptor: ExtractableCodeDescriptor): Boolean
companion object {
fun checkNotTrait(descriptor: ExtractableCodeDescriptor): Boolean {
return !descriptor.isInterface()
}
}
}
@@ -27,6 +27,7 @@ enum class Fruit(personal: Int) {
}
val score = personal + <!UNINITIALIZED_VARIABLE!>common<!>
val score2 = { personal + common }()
}
// Another example from KT-11769
@@ -53,3 +54,28 @@ enum class EnumCompanion3(val x: Int) {
companion object
}
interface ExtractableCodeDescriptor {
fun isInterface(): Boolean
}
enum class ExtractionTarget(val targetName: String) {
FUNCTION("function") {
override fun isAvailable(descriptor: ExtractableCodeDescriptor) = true
},
LAZY_PROPERTY("lazy property") {
override fun isAvailable(descriptor: ExtractableCodeDescriptor): Boolean {
// Should not report UNINITIALIZED_ENUM_COMPANION
return checkNotTrait(descriptor)
}
};
abstract fun isAvailable(descriptor: ExtractableCodeDescriptor): Boolean
companion object {
fun checkNotTrait(descriptor: ExtractableCodeDescriptor): Boolean {
return !descriptor.isInterface()
}
}
}
@@ -149,6 +149,44 @@ public final enum class EnumCompanion3 : kotlin.Enum<EnumCompanion3> {
public final /*synthesized*/ fun values(): kotlin.Array<EnumCompanion3>
}
public interface ExtractableCodeDescriptor {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun isInterface(): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final enum class ExtractionTarget : kotlin.Enum<ExtractionTarget> {
enum entry FUNCTION
enum entry LAZY_PROPERTY
private constructor ExtractionTarget(/*0*/ targetName: kotlin.String)
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
public final val targetName: kotlin.String
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: ExtractionTarget): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<ExtractionTarget!>!
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun isAvailable(/*0*/ descriptor: ExtractableCodeDescriptor): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public companion object Companion {
private constructor Companion()
public final fun checkNotTrait(/*0*/ descriptor: ExtractableCodeDescriptor): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): ExtractionTarget
public final /*synthesized*/ fun values(): kotlin.Array<ExtractionTarget>
}
public final enum class Fruit : kotlin.Enum<Fruit> {
enum entry APPLE
@@ -156,6 +194,7 @@ public final enum class Fruit : kotlin.Enum<Fruit> {
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
public final val score: kotlin.Int
public final val score2: kotlin.Int
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Fruit): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -1,10 +1,11 @@
enum class A(val v: A) {
A1(A2),
A2(A1)
A1(<!UNINITIALIZED_ENUM_ENTRY!>A2<!>),
A2(A1),
A3(<!UNINITIALIZED_ENUM_ENTRY!>A3<!>)
}
enum class D(val x: Int) {
D1(D2.x),
D1(<!UNINITIALIZED_ENUM_ENTRY!>D2<!>.x),
D2(D1.x)
}
@@ -28,8 +29,8 @@ object Object1 {
enum class MyEnum {
A, B;
val x = when(this) {
A -> 1
B -> 2
<!UNINITIALIZED_ENUM_ENTRY!>A<!> -> 1
<!UNINITIALIZED_ENUM_ENTRY!>B<!> -> 2
else -> 3
}
}
@@ -1,6 +1,7 @@
enum class A(val v: A) {
A1(<!UNINITIALIZED_ENUM_ENTRY!>A2<!>),
A2(A1)
A2(A1),
A3(A3)
}
enum class D(val x: Int) {
@@ -5,6 +5,8 @@ public final enum class A : kotlin.Enum<A> {
enum entry A2
enum entry A3
private constructor A(/*0*/ v: A)
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
@@ -0,0 +1,28 @@
// FIR_IDENTICAL
enum class JvmTarget(val description: String) {
JVM_1_6("1.6"),
JVM_1_8("1.8"),
JVM_9("9"),
JVM_10("10"),
JVM_11("11"),
JVM_12("12"),
JVM_13("13"),
JVM_14("14"),
JVM_15("15"),
;
// Should not report UNINITIALIZED_ENUM_ENTRY
val bytecodeVersion: String by lazy {
when (this) {
JVM_1_6 -> "Opcodes.V1_6"
JVM_1_8 -> "Opcodes.V1_8"
JVM_9 -> "Opcodes.V9"
JVM_10 -> "Opcodes.V10"
JVM_11 -> "Opcodes.V11"
JVM_12 -> "Opcodes.V12"
JVM_13 -> "Opcodes.V12 + 1"
JVM_14 -> "Opcodes.V12 + 2"
JVM_15 -> "Opcodes.V12 + 3"
}
}
}
@@ -0,0 +1,38 @@
package
public final enum class JvmTarget : kotlin.Enum<JvmTarget> {
enum entry JVM_1_6
enum entry JVM_1_8
enum entry JVM_9
enum entry JVM_10
enum entry JVM_11
enum entry JVM_12
enum entry JVM_13
enum entry JVM_14
enum entry JVM_15
private constructor JvmTarget(/*0*/ description: kotlin.String)
public final val bytecodeVersion: kotlin.String
public final val description: kotlin.String
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: JvmTarget): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<JvmTarget!>!
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): JvmTarget
public final /*synthesized*/ fun values(): kotlin.Array<JvmTarget>
}
@@ -30996,6 +30996,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/testsWithStdLib/elvisOnUnitInLet.kt");
}
@Test
@TestMetadata("enumEntryInitialization.kt")
public void testEnumEntryInitialization() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/enumEntryInitialization.kt");
}
@Test
@TestMetadata("exitProcess.kt")
public void testExitProcess() throws Exception {
@@ -18,10 +18,7 @@ import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.DiagnosticParamet
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
@@ -30,7 +27,6 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.psi.KtParameter
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.full.createType
@@ -147,6 +143,11 @@ private object FirToKtConversionCreator {
KtClassLikeSymbol::class.createType(),
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirClass")
),
FirRegularClassSymbol::class to HLFunctionCallConversion(
"firSymbolBuilder.classifierBuilder.buildClassLikeSymbol({0}.fir)",
KtClassLikeSymbol::class.createType(),
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirRegularClass")
),
FirMemberDeclaration::class to HLFunctionCallConversion(
"firSymbolBuilder.buildSymbol({0} as FirDeclaration)",
KtSymbol::class.createType(),
@@ -171,7 +172,7 @@ private object FirToKtConversionCreator {
KtType::class.createType()
),
FirPropertySymbol::class to HLFunctionCallConversion(
"firSymbolBuilder.variableLikeBuilder.buildVariableSymbol({0}.fir as FirProperty)",
"firSymbolBuilder.variableLikeBuilder.buildVariableSymbol({0}.fir)",
KtVariableSymbol::class.createType(),
importsToAdd = listOf("org.jetbrains.kotlin.fir.declarations.FirProperty")
),
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.psi
@@ -1471,7 +1472,21 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
}
add(FirErrors.UNINITIALIZED_VARIABLE) { firDiagnostic ->
UninitializedVariableImpl(
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir as FirProperty),
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.UNINITIALIZED_ENUM_ENTRY) { firDiagnostic ->
UninitializedEnumEntryImpl(
firSymbolBuilder.variableLikeBuilder.buildVariableLikeSymbol(firDiagnostic.a.fir),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.UNINITIALIZED_ENUM_COMPANION) { firDiagnostic ->
UninitializedEnumCompanionImpl(
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a.fir),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
@@ -1485,14 +1500,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
}
add(FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD) { firDiagnostic ->
ValReassignmentViaBackingFieldImpl(
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir as FirProperty),
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR) { firDiagnostic ->
ValReassignmentViaBackingFieldErrorImpl(
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir as FirProperty),
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
@@ -1044,6 +1044,16 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val variable: KtVariableSymbol
}
abstract class UninitializedEnumEntry : KtFirDiagnostic<KtSimpleNameExpression>() {
override val diagnosticClass get() = UninitializedEnumEntry::class
abstract val enumEntry: KtVariableLikeSymbol
}
abstract class UninitializedEnumCompanion : KtFirDiagnostic<KtSimpleNameExpression>() {
override val diagnosticClass get() = UninitializedEnumCompanion::class
abstract val enumClass: KtClassLikeSymbol
}
abstract class ValReassignment : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = ValReassignment::class
abstract val variable: KtVariableLikeSymbol
@@ -1687,6 +1687,22 @@ internal class UninitializedVariableImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class UninitializedEnumEntryImpl(
override val enumEntry: KtVariableLikeSymbol,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.UninitializedEnumEntry(), KtAbstractFirDiagnostic<KtSimpleNameExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class UninitializedEnumCompanionImpl(
override val enumClass: KtClassLikeSymbol,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.UninitializedEnumCompanion(), KtAbstractFirDiagnostic<KtSimpleNameExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ValReassignmentImpl(
override val variable: KtVariableLikeSymbol,
firDiagnostic: FirPsiDiagnostic<*>,