[FIR] Make Volatile diagnostics applicable to kotlin.concurrent.Volatile

#KT-55628 Fixed
This commit is contained in:
Kirill Rakhman
2023-04-03 17:58:23 +02:00
committed by Space Team
parent 91adb88eff
commit 085df96afe
18 changed files with 96 additions and 153 deletions
@@ -1023,6 +1023,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.VOLATILE_ON_VALUE) { firDiagnostic ->
VolatileOnValueImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.VOLATILE_ON_DELEGATE) { firDiagnostic ->
VolatileOnDelegateImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirJsErrors.WRONG_JS_QUALIFIER) { firDiagnostic ->
WrongJsQualifierImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -4400,18 +4412,6 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirJvmErrors.VOLATILE_ON_VALUE) { firDiagnostic ->
VolatileOnValueImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirJvmErrors.VOLATILE_ON_DELEGATE) { firDiagnostic ->
VolatileOnDelegateImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirJvmErrors.SYNCHRONIZED_ON_ABSTRACT) { firDiagnostic ->
SynchronizedOnAbstractImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -739,6 +739,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val symbols: List<KtSymbol>
}
abstract class VolatileOnValue : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = VolatileOnValue::class
}
abstract class VolatileOnDelegate : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = VolatileOnDelegate::class
}
abstract class WrongJsQualifier : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = WrongJsQualifier::class
}
@@ -3066,14 +3074,6 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = StrictfpOnClass::class
}
abstract class VolatileOnValue : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = VolatileOnValue::class
}
abstract class VolatileOnDelegate : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = VolatileOnDelegate::class
}
abstract class SynchronizedOnAbstract : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = SynchronizedOnAbstract::class
}
@@ -886,6 +886,16 @@ internal class AmbiguousAnnotationArgumentImpl(
override val token: KtLifetimeToken,
) : KtFirDiagnostic.AmbiguousAnnotationArgument(), KtAbstractFirDiagnostic<PsiElement>
internal class VolatileOnValueImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.VolatileOnValue(), KtAbstractFirDiagnostic<KtAnnotationEntry>
internal class VolatileOnDelegateImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.VolatileOnDelegate(), KtAbstractFirDiagnostic<KtAnnotationEntry>
internal class WrongJsQualifierImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
@@ -3702,16 +3712,6 @@ internal class StrictfpOnClassImpl(
override val token: KtLifetimeToken,
) : KtFirDiagnostic.StrictfpOnClass(), KtAbstractFirDiagnostic<KtAnnotationEntry>
internal class VolatileOnValueImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.VolatileOnValue(), KtAbstractFirDiagnostic<KtAnnotationEntry>
internal class VolatileOnDelegateImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.VolatileOnDelegate(), KtAbstractFirDiagnostic<KtAnnotationEntry>
internal class SynchronizedOnAbstractImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
@@ -321,6 +321,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val AMBIGUOUS_ANNOTATION_ARGUMENT by error<PsiElement> {
parameter<List<FirBasedSymbol<*>>>("symbols")
}
val VOLATILE_ON_VALUE by error<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error<KtAnnotationEntry>()
}
val OPT_IN by object : DiagnosticGroup("OptIn") {
@@ -55,8 +55,6 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
val ANNOTATIONS by object : DiagnosticGroup("annotations") {
val STRICTFP_ON_CLASS by error<KtAnnotationEntry>()
val VOLATILE_ON_VALUE by error<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_ABSTRACT by error<KtAnnotationEntry>()
val SYNCHRONIZED_IN_INTERFACE by error<KtAnnotationEntry>()
val SYNCHRONIZED_ON_INLINE by warning<KtAnnotationEntry>()
@@ -54,8 +54,6 @@ object FirJvmErrors {
// annotations
val STRICTFP_ON_CLASS by error0<KtAnnotationEntry>()
val VOLATILE_ON_VALUE by error0<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error0<KtAnnotationEntry>()
val SYNCHRONIZED_ON_ABSTRACT by error0<KtAnnotationEntry>()
val SYNCHRONIZED_IN_INTERFACE by error0<KtAnnotationEntry>()
val SYNCHRONIZED_ON_INLINE by warning0<KtAnnotationEntry>()
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOL
import org.jetbrains.kotlin.fir.analysis.diagnostics.checkMissingMessages
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONCURRENT_HASH_MAP_CONTAINS_OPERATOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONFLICTING_JVM_DECLARATIONS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET
@@ -87,8 +86,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZ
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_ON_SUSPEND
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.UPPER_BOUND_CANNOT_BE_ARRAY
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_DELEGATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_VALUE
object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
@@ -97,8 +94,6 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(JAVA_TYPE_MISMATCH, "Java type mismatch expected {0} but found {1}. Use explicit cast", RENDER_TYPE, RENDER_TYPE)
map.put(UPPER_BOUND_CANNOT_BE_ARRAY, "Upper bound of a type parameter cannot be an array")
map.put(STRICTFP_ON_CLASS, "'@Strictfp' annotation on classes is unsupported yet")
map.put(VOLATILE_ON_VALUE, "'@Volatile' annotation cannot be used on immutable properties")
map.put(VOLATILE_ON_DELEGATE, "'@Volatile' annotation cannot be used on delegated properties")
map.put(SYNCHRONIZED_ON_ABSTRACT, "'@Synchronized' annotation cannot be used on abstract functions")
map.put(SYNCHRONIZED_ON_INLINE, "'@Synchronized' annotation has no effect on inline functions")
map.put(SYNCHRONIZED_ON_SUSPEND, "@Synchronized annotation is not applicable to suspend functions and lambdas")
@@ -302,4 +297,4 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
TO_STRING,
)
}
}
}
@@ -35,7 +35,6 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
override val propertyCheckers: Set<FirPropertyChecker>
get() = setOf(
FirVolatileAnnotationChecker,
FirJvmFieldApplicabilityChecker,
FirJvmSyntheticApplicabilityChecker,
FirJvmInlinePropertyChecker,
@@ -1,33 +0,0 @@
/*
* 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.jvm.checkers.declaration
import org.jetbrains.kotlin.KtRealSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyChecker
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.name.JvmNames.VOLATILE_ANNOTATION_CLASS_ID
object FirVolatileAnnotationChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.source?.kind != KtRealSourceElementKind) return
val fieldAnnotation = declaration.getAnnotationByClassId(VOLATILE_ANNOTATION_CLASS_ID, context.session)
if (fieldAnnotation != null && !declaration.isVar) {
reporter.reportOn(fieldAnnotation.source, FirJvmErrors.VOLATILE_ON_VALUE, context)
}
val delegateAnnotation = declaration.delegateFieldSymbol?.getAnnotationByClassId(VOLATILE_ANNOTATION_CLASS_ID, context.session)
if (delegateAnnotation != null) {
reporter.reportOn(delegateAnnotation.source, FirJvmErrors.VOLATILE_ON_DELEGATE, context)
}
}
}
@@ -268,6 +268,8 @@ object FirErrors {
val ANNOTATION_IN_WHERE_CLAUSE_ERROR by error0<KtAnnotationEntry>()
val PLUGIN_ANNOTATION_AMBIGUITY by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val AMBIGUOUS_ANNOTATION_ARGUMENT by error1<PsiElement, List<FirBasedSymbol<*>>>()
val VOLATILE_ON_VALUE by error0<KtAnnotationEntry>()
val VOLATILE_ON_DELEGATE by error0<KtAnnotationEntry>()
// OptIn
val OPT_IN_USAGE by warning2<PsiElement, FqName, String>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -76,6 +76,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirTopLevelPropertiesChecker,
FirLocalExtensionPropertyChecker,
ContractSyntaxV2PropertyChecker,
FirVolatileAnnotationChecker,
)
override val backingFieldCheckers: Set<FirBackingFieldChecker>
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2023 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.KtRealSourceElementKind
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassIds
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.name.StandardClassIds
object FirVolatileAnnotationChecker : FirPropertyChecker() {
private val VOLATILE_CLASS_IDS = listOf(StandardClassIds.Annotations.Volatile, StandardClassIds.Annotations.JvmVolatile)
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.source?.kind != KtRealSourceElementKind) return
val fieldAnnotation = declaration.annotations.getAnnotationByClassIds(VOLATILE_CLASS_IDS, context.session)
?: declaration.backingField?.annotations?.getAnnotationByClassIds(VOLATILE_CLASS_IDS, context.session)
?: return
if (!declaration.isVar) {
reporter.reportOn(fieldAnnotation.source, FirErrors.VOLATILE_ON_VALUE, context)
}
if (declaration.delegateFieldSymbol != null) {
reporter.reportOn(fieldAnnotation.source, FirErrors.VOLATILE_ON_DELEGATE, context)
}
}
}
@@ -608,6 +608,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_OVERRIDDEN_BY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_INHERITANCE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_OVERRIDE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VIRTUAL_MEMBER_HIDDEN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VOLATILE_ON_DELEGATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VOLATILE_ON_VALUE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_EXTENSION_FUNCTION_TYPE
@@ -891,6 +893,8 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(REPEATED_ANNOTATION, "This annotation is not repeatable")
map.put(REPEATED_ANNOTATION_WARNING, "This annotation is not repeatable")
map.put(NON_INTERNAL_PUBLISHED_API, "@PublishedApi annotation is only applicable to internal declaration")
map.put(VOLATILE_ON_VALUE, "'@Volatile' annotation cannot be used on immutable properties")
map.put(VOLATILE_ON_DELEGATE, "'@Volatile' annotation cannot be used on delegated properties")
// OptIn
map.put(OPT_IN_USAGE, "{1}", TO_STRING, STRING)
@@ -178,6 +178,12 @@ fun List<FirAnnotation>.getAnnotationsByClassId(classId: ClassId, session: FirSe
}
}
fun List<FirAnnotation>.getAnnotationByClassIds(classIds: Collection<ClassId>, session: FirSession): FirAnnotation? {
return firstOrNull {
it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.fullyExpandedType(session)?.lookupTag?.classId in classIds
}
}
inline fun <T> List<FirAnnotation>.mapAnnotationsWithClassIdTo(
classId: ClassId,
destination: MutableCollection<T>,
@@ -1,63 +0,0 @@
// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER
// !API_VERSION: 1.9
// !LANGUAGE: +MultiPlatformProjects
// MODULE: common
// FILE: common.kt
// TARGET_PLATFORM: Common
import kotlin.concurrent.Volatile
import kotlin.properties.Delegates
@OptIn(ExperimentalStdlibApi::class)
class ConcurrentVolatile {
@Volatile val x = 0
// ok
@Volatile var y = 1
@delegate:Volatile var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() }
@field:Volatile val w = 2
<!WRONG_ANNOTATION_TARGET!>@Volatile<!>
var noBacking: String
get() = ""
set(value) {}
}
// MODULE: jvm
// FILE: jvm.kt
// TARGET_PLATFORM: JVM
import kotlin.jvm.Volatile as JvmVolatile
import kotlin.concurrent.Volatile
import kotlin.properties.Delegates
@OptIn(ExperimentalStdlibApi::class)
class ConcurrentVolatileOnJvm {
<!VOLATILE_ON_VALUE!>@Volatile<!> val x = 0
// ok
@Volatile var y = 1
<!VOLATILE_ON_DELEGATE!>@delegate:Volatile<!> var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() }
<!VOLATILE_ON_VALUE!>@field:Volatile<!> val w = 2
<!WRONG_ANNOTATION_TARGET!>@Volatile<!>
var noBacking: String
get() = ""
set(value) {}
}
class JvmVolatile {
<!VOLATILE_ON_VALUE!>@JvmVolatile<!> val x = 0
// ok
@JvmVolatile var y = 1
<!VOLATILE_ON_DELEGATE!>@delegate:JvmVolatile<!> var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() }
<!VOLATILE_ON_VALUE!>@field:JvmVolatile<!> val w = 2
<!WRONG_ANNOTATION_TARGET!>@JvmVolatile<!>
var noBacking: String
get() = ""
set(value) {}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER
// !API_VERSION: 1.9
// !LANGUAGE: +MultiPlatformProjects
@@ -10,15 +11,15 @@ import kotlin.properties.Delegates
@OptIn(ExperimentalStdlibApi::class)
class ConcurrentVolatile {
<!VOLATILE_ON_VALUE, VOLATILE_ON_VALUE{JVM}!>@Volatile<!> val x = 0
<!VOLATILE_ON_VALUE!>@Volatile<!> val x = 0
// ok
@Volatile var y = 1
<!VOLATILE_ON_DELEGATE, VOLATILE_ON_DELEGATE{JVM}!>@delegate:Volatile<!> var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() }
<!VOLATILE_ON_DELEGATE!>@delegate:Volatile<!> var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() }
<!VOLATILE_ON_VALUE, VOLATILE_ON_VALUE{JVM}!>@field:Volatile<!> val w = 2
<!VOLATILE_ON_VALUE!>@field:Volatile<!> val w = 2
<!WRONG_ANNOTATION_TARGET, WRONG_ANNOTATION_TARGET{JVM}!>@Volatile<!>
<!WRONG_ANNOTATION_TARGET!>@Volatile<!>
var noBacking: String
get() = ""
set(value) {}
@@ -16,18 +16,6 @@ package
// -- Module: <jvm> --
package
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) public final class ConcurrentVolatile {
public constructor ConcurrentVolatile()
@field:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final var noBacking: kotlin.String
@field:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final val w: kotlin.Int = 2
@field:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final val x: kotlin.Int = 0
@field:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final var y: kotlin.Int
@delegate:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final var z: kotlin.String
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
}
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) public final class ConcurrentVolatileOnJvm {
public constructor ConcurrentVolatileOnJvm()
@field:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final var noBacking: kotlin.String
@@ -18,6 +18,7 @@ object StandardClassIds {
val BASE_COROUTINES_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("coroutines"))
val BASE_ENUMS_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("enums"))
val BASE_CONTRACTS_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("contracts"))
val BASE_CONCURRENT_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("concurrent"))
val builtInsPackages = setOf(
BASE_KOTLIN_PACKAGE,
@@ -164,8 +165,11 @@ object StandardClassIds {
val JvmDefault = "JvmDefault".jvmId()
val JvmRepeatable = "JvmRepeatable".jvmId()
val JvmRecord = "JvmRecord".jvmId()
val JvmVolatile = "Volatile".jvmId()
val Throws = "Throws".jvmId()
val Volatile = "Volatile".concurrentId()
val RawTypeAnnotation = "RawType".internalIrId()
val FlexibleNullability = "FlexibleNullability".internalIrId()
val EnhancedNullability = "EnhancedNullability".jvmInternalId()
@@ -255,6 +259,7 @@ private fun String.internalId() = ClassId(StandardClassIds.BASE_INTERNAL_PACKAGE
private fun String.internalIrId() = ClassId(StandardClassIds.BASE_INTERNAL_IR_PACKAGE, Name.identifier(this))
private fun String.coroutinesId() = ClassId(StandardClassIds.BASE_COROUTINES_PACKAGE, Name.identifier(this))
private fun String.enumsId() = ClassId(StandardClassIds.BASE_ENUMS_PACKAGE, Name.identifier(this))
private fun String.concurrentId() = ClassId(StandardClassIds.BASE_CONCURRENT_PACKAGE, Name.identifier(this))
private fun String.callableId(packageName: FqName) = CallableId(packageName, Name.identifier(this))
private fun String.callableId(classId: ClassId) = CallableId(classId, Name.identifier(this))