Update and clarify documentation for kotlinx-metadata-jvm attributes:

- Review fixes
- Clarify KmClass.isData and enhance nodes documentaiton to mention extensions
This commit is contained in:
Leonid Startsev
2023-06-19 12:13:55 +02:00
committed by Space Team
parent 283f816320
commit 0a573a803d
6 changed files with 276 additions and 96 deletions
@@ -16,28 +16,42 @@ import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmFlags as JF import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmFlags as JF
/** /**
* Applied to a property declared in an interface's companion object, signifies that its backing field is declared as a static * Applicable to a property declared in an interface's companion object.
* Indicates that its backing field is declared as a static
* field in the interface. In Kotlin code, this usually happens if the property is annotated with [JvmField]. * field in the interface. In Kotlin code, this usually happens if the property is annotated with [JvmField].
* *
* Has no effect if the property is not declared in a companion object of some interface. * Returns `false` if the property is not declared in a companion object of some interface.
*/ */
var KmProperty.isMovedFromInterfaceCompanion by BooleanFlagDelegate(KmProperty::jvmFlags, booleanFlag(JF.IS_MOVED_FROM_INTERFACE_COMPANION)) var KmProperty.isMovedFromInterfaceCompanion by BooleanFlagDelegate(KmProperty::jvmFlags, booleanFlag(JF.IS_MOVED_FROM_INTERFACE_COMPANION))
/** /**
* Applied to an interface compiled with -Xjvm-default=all or all-compatibility. * Applicable to an interface compiled with -Xjvm-default=all or all-compatibility.
* * True if interface has method bodies in it, false if Kotlin compiler moved all interface method bodies into a nested `DefaultImpls`
* Without this flag or a `@JvmDefault` annotation on individual interface methods
* the Kotlin compiler moves all interface method bodies into a nested `DefaultImpls`
* class. * class.
*
* Method bodies are also present in interface method if it has `@JvmDefault` annotation (now deprecated).
*
* Check [documentation](https://kotlinlang.org/docs/java-to-kotlin-interop.html#compatibility-modes-for-default-methods) for more details.
*
* @see JvmDefault
* @see JvmDefaultWithCompatibility
* @see JvmDefaultWithoutCompatibility
*/ */
var KmClass.hasMethodBodiesInInterface by BooleanFlagDelegate(KmClass::jvmFlags, booleanFlag(JF.IS_COMPILED_IN_JVM_DEFAULT_MODE)) var KmClass.hasMethodBodiesInInterface by BooleanFlagDelegate(KmClass::jvmFlags, booleanFlag(JF.IS_COMPILED_IN_JVM_DEFAULT_MODE))
/** /**
* Applied to an interface compiled with -Xjvm-default=all-compatibility. * Indicates if an interface was compiled with -Xjvm-default=all-compatibility.
* *
* In compatibility mode we generate method bodies directly in the interface, * In compatibility mode Kotlin/JVM compiler generates method bodies directly in the interface,
* but we also generate bridges in a nested `DefaultImpls` class for use by * and also generates bridges in a nested `DefaultImpls` class.
* clients compiled without all-compatibility. * Bridges are intended for use by already existing clients,
* such as compiled Java code or Kotlin code compiled without all/all-compatibility setting.
*
* Also, can be a result of compiling interface with `@JvmDefaultWithCompatibility` annotation.
* Check [documentation](https://kotlinlang.org/docs/java-to-kotlin-interop.html#compatibility-modes-for-default-methods) for more details.
*
* @see JvmDefaultWithCompatibility
* @see JvmDefaultWithoutCompatibility
*/ */
var KmClass.isCompiledInCompatibilityMode by BooleanFlagDelegate(KmClass::jvmFlags, booleanFlag(JF.IS_COMPILED_IN_COMPATIBILITY_MODE)) var KmClass.isCompiledInCompatibilityMode by BooleanFlagDelegate(KmClass::jvmFlags, booleanFlag(JF.IS_COMPILED_IN_COMPATIBILITY_MODE))
@@ -62,7 +62,7 @@ object JvmFlag {
* clients compiled without all-compatibility. * clients compiled without all-compatibility.
*/ */
@JvmField @JvmField
@Deprecated("$prefix KmProperty.isCompiledInCompatibilityMode") @Deprecated("$prefix KmClass.isCompiledInCompatibilityMode")
val IS_COMPILED_IN_COMPATIBILITY_MODE = booleanFlag(JF.IS_COMPILED_IN_COMPATIBILITY_MODE) val IS_COMPILED_IN_COMPATIBILITY_MODE = booleanFlag(JF.IS_COMPILED_IN_COMPATIBILITY_MODE)
} }
@@ -160,4 +160,59 @@ class FlagDelegatesTest {
} }
} }
class X {
val x2 = 2
fun x22() = 2
val x3 = x22()
companion object Y {
val y2 = 2
const val y3 = 3
}
}
@Test
fun testHasConstantExample() {
class X {
val a = 1
val b = a
fun x() = 2
val c = x()
}
val props = X::class.java.readMetadataAsKmClass().properties.associateBy { it.name }
props.values.forEach { assertFalse(it.isConst, it.name) }
assertTrue(props.getValue("a").hasConstant)
assertTrue(props.getValue("b").hasConstant)
assertFalse(props.getValue("c").hasConstant)
}
interface I {
val x: Int
}
class Foo(i: I) : I by i {
val props: Map<String, Int> = mapOf()
val y: Int by props
}
@Test
fun testDelegation() {
val foo = Foo::class.java.readMetadataAsKmClass()
val props = foo.properties.associateBy { it.name }
with(props["x"]!!) {
assertEquals(MemberKind.DELEGATION, kind)
assertFalse(isDelegated)
assertFalse(getter.isNotDefault)
}
with(props["y"]!!) {
assertEquals(MemberKind.DECLARATION, kind)
assertTrue(isDelegated)
assertTrue(getter.isNotDefault)
}
}
} }
@@ -19,65 +19,79 @@ import org.jetbrains.kotlin.metadata.deserialization.Flags as ProtoFlags
// --- ANNOTATIONS --- // --- ANNOTATIONS ---
/** /**
* Signifies that the corresponding class has at least one annotation. * Indicates that the corresponding class has at least one annotation.
* *
* This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin * This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin
* metadata, but directly on the corresponding declarations in the class file. This flag can be used as an optimization to avoid * metadata, but directly to the corresponding declarations in the class file. This flag can be used as an optimization to avoid
* reading annotations from the class file (which can be slow) in case when a class has no annotations. * reading annotations from the class file (which can be slow) in case when a class has no annotations.
*
* Only annotations with [AnnotationRetention.BINARY] and [AnnotationRetention.RUNTIME] are written to the class files.
*/ */
var KmClass.hasAnnotations by annotationsOn(KmClass::flags) var KmClass.hasAnnotations by annotationsOn(KmClass::flags)
/** /**
* Signifies that the corresponding constructor has at least one annotation. * Indicates that the corresponding constructor has at least one annotation.
* *
* This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin * This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin
* metadata, but directly on the corresponding declarations in the class file. This flag can be used as an optimization to avoid * metadata, but directly to the corresponding declarations in the class file. This flag can be used as an optimization to avoid
* reading annotations from the class file (which can be slow) in case when a constructor has no annotations. * reading annotations from the class file (which can be slow) in case when a constructor has no annotations.
*
* Only annotations with [AnnotationRetention.BINARY] and [AnnotationRetention.RUNTIME] are written to the class files.
*/ */
var KmConstructor.hasAnnotations by annotationsOn(KmConstructor::flags) var KmConstructor.hasAnnotations by annotationsOn(KmConstructor::flags)
/** /**
* Signifies that the corresponding function has at least one annotation. * Indicates that the corresponding function has at least one annotation.
* *
* This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin * This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin
* metadata, but directly on the corresponding declarations in the class file. This flag can be used as an optimization to avoid * metadata, but directly to the corresponding declarations in the class file. This flag can be used as an optimization to avoid
* reading annotations from the class file (which can be slow) in case when a function has no annotations. * reading annotations from the class file (which can be slow) in case when a function has no annotations.
*
* Only annotations with [AnnotationRetention.BINARY] and [AnnotationRetention.RUNTIME] are written to the class files.
*/ */
var KmFunction.hasAnnotations by annotationsOn(KmFunction::flags) var KmFunction.hasAnnotations by annotationsOn(KmFunction::flags)
/** /**
* Signifies that the corresponding property has at least one annotation. * Indicates that the corresponding property has at least one annotation.
* *
* This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin * This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin
* metadata, but directly on the corresponding declarations in the class file. This flag can be used as an optimization to avoid * metadata, but directly to the corresponding declarations in the class file. This flag can be used as an optimization to avoid
* reading annotations from the class file (which can be slow) in case when a property has no annotations. * reading annotations from the class file (which can be slow) in case when a property has no annotations.
*
* Only annotations with [AnnotationRetention.BINARY] and [AnnotationRetention.RUNTIME] are written to the class files.
*/ */
var KmProperty.hasAnnotations by annotationsOn(KmProperty::flags) var KmProperty.hasAnnotations by annotationsOn(KmProperty::flags)
/** /**
* Signifies that the corresponding property accessor has at least one annotation. * Indicates that the corresponding property accessor has at least one annotation.
* *
* This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin * This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin
* metadata, but directly on the corresponding declarations in the class file. This flag can be used as an optimization to avoid * metadata, but directly to the corresponding declarations in the class file. This flag can be used as an optimization to avoid
* reading annotations from the class file (which can be slow) in case when a property accessor has no annotations. * reading annotations from the class file (which can be slow) in case when a property accessor has no annotations.
*
* Only annotations with [AnnotationRetention.BINARY] and [AnnotationRetention.RUNTIME] are written to the class files.
*/ */
var KmPropertyAccessorAttributes.hasAnnotations by annotationsOn(KmPropertyAccessorAttributes::flags) var KmPropertyAccessorAttributes.hasAnnotations by annotationsOn(KmPropertyAccessorAttributes::flags)
/** /**
* Signifies that the corresponding value parameter has at least one annotation. * Indicates that the corresponding value parameter has at least one annotation.
* *
* This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin * This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin
* metadata, but directly on the corresponding declarations in the class file. This flag can be used as an optimization to avoid * metadata, but directly to the corresponding declarations in the class file. This flag can be used as an optimization to avoid
* reading annotations from the class file (which can be slow) in case when a value parameter has no annotations. * reading annotations from the class file (which can be slow) in case when a value parameter has no annotations.
*
* Only annotations with [AnnotationRetention.BINARY] and [AnnotationRetention.RUNTIME] are written to the class files.
*/ */
var KmValueParameter.hasAnnotations by annotationsOn(KmValueParameter::flags) var KmValueParameter.hasAnnotations by annotationsOn(KmValueParameter::flags)
/** /**
* Signifies that the corresponding type alias has at least one annotation. * Indicates that the corresponding type alias has at least one annotation.
* *
* Type aliases store their annotation in metadata directly (accessible via [KmTypeAlias.annotations]) and * Type aliases store their annotation in metadata directly (accessible via [KmTypeAlias.annotations]) and
* in the class file at the same time. * in the class file at the same time.
* As a result, Kotlin compiler still writes this flag for them, and this extension is left for completeness. * As a result, Kotlin compiler still writes this flag for them, and this extension is left for completeness.
*
* Only annotations with [AnnotationRetention.BINARY] and [AnnotationRetention.RUNTIME] are written to the class files and metadata.
*/ */
var KmTypeAlias.hasAnnotations by annotationsOn(KmTypeAlias::flags) var KmTypeAlias.hasAnnotations by annotationsOn(KmTypeAlias::flags)
@@ -86,17 +100,22 @@ var KmTypeAlias.hasAnnotations by annotationsOn(KmTypeAlias::flags)
// --- CLASS --- // --- CLASS ---
/** /**
* Represents modality of a corresponding class * Represents modality of the corresponding class.
*
* Modality determines when and where it is possible to extend/implement a class/interface.
*/ */
var KmClass.modality: Modality by modalityDelegate(KmClass::flags) var KmClass.modality: Modality by modalityDelegate(KmClass::flags)
/** /**
* Represents visibility of a corresponding class * Represents visibility of the corresponding class.
*
* Note that Kotlin metadata has an extended list of visibilities; some of them are non-denotable.
* For additional details, see [Visibility].
*/ */
var KmClass.visibility: Visibility by visibilityDelegate(KmClass::flags) var KmClass.visibility: Visibility by visibilityDelegate(KmClass::flags)
/** /**
* Represents kind of a corresponding class * Represents kind of the corresponding class — whether it is a regular class or an interface, companion object, et cetera.
*/ */
var KmClass.kind: ClassKind by EnumFlagDelegate( var KmClass.kind: ClassKind by EnumFlagDelegate(
KmClass::flags, KmClass::flags,
@@ -106,223 +125,285 @@ var KmClass.kind: ClassKind by EnumFlagDelegate(
) )
/** /**
* Signifies that the corresponding class is `inner`. * Indicates that the corresponding class is `inner`.
*/ */
var KmClass.isInner: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_INNER)) var KmClass.isInner: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_INNER))
/** /**
* Signifies that the corresponding class is `data`. * Indicates that the corresponding `class` or `object` is `data`.
* Always false for other kinds.
*/ */
var KmClass.isData: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_DATA)) var KmClass.isData: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_DATA))
/** /**
* Signifies that the corresponding class is `external`. * Indicates that the corresponding class is `external`.
*/ */
var KmClass.isExternal: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_EXTERNAL_CLASS)) var KmClass.isExternal: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_EXTERNAL_CLASS))
/** /**
* Signifies that the corresponding class is `expect`. * Indicates that the corresponding class is `expect`.
*/ */
var KmClass.isExpect: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_EXPECT_CLASS)) var KmClass.isExpect: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_EXPECT_CLASS))
/** /**
* Signifies that the corresponding class is either a pre-Kotlin-1.5 `inline` class, or a 1.5+ `value` class. * Indicates that the corresponding class is either a pre-Kotlin-1.5 `inline` class, or a 1.5+ `value` class.
* *
* Note that it doesn't imply that the class has [JvmInline] annotation and will be inlined. * Note that it does not imply that the class has [JvmInline] annotation and will be inlined.
* Currently, it is impossible to declare a value class without this annotation, but this can be changed in the future. * Currently, it is impossible to declare a value class without this annotation, but this can be changed in the future.
*/ */
var KmClass.isValue: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_VALUE_CLASS)) var KmClass.isValue: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_VALUE_CLASS))
/** /**
* Signifies that the corresponding class is a functional interface, i.e. marked with the keyword `fun`. * Indicates that the corresponding class is a functional interface, i.e., marked with the keyword `fun`.
*
* Always `false` if [KmClass.kind] is not an interface.
*/ */
var KmClass.isFunInterface: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_FUN_INTERFACE)) var KmClass.isFunInterface: Boolean by classBooleanFlag(Flag(ProtoFlags.IS_FUN_INTERFACE))
/** /**
* Signifies that the corresponding enum class has synthetic ".entries" property in bytecode. * Indicates that the corresponding enum class has synthetic ".entries" property in bytecode.
* Always `false` for not enum classes. *
* Always `false` if [KmClass.kind] is not an enum.
* Enum classes always have enum entries property starting from Kotlin 1.9.0.
*/ */
var KmClass.hasEnumEntries: Boolean by classBooleanFlag(Flag(ProtoFlags.HAS_ENUM_ENTRIES)) var KmClass.hasEnumEntries: Boolean by classBooleanFlag(Flag(ProtoFlags.HAS_ENUM_ENTRIES))
// --- CONSTRUCTOR --- // --- CONSTRUCTOR ---
/** /**
* Represents visibility of a corresponding constructor. * Represents visibility of the corresponding constructor.
*
* Note that Kotlin metadata has an extended list of visibilities; some of them are non-denotable.
* For additional details, see [Visibility].
*/ */
var KmConstructor.visibility: Visibility by visibilityDelegate(KmConstructor::flags) var KmConstructor.visibility: Visibility by visibilityDelegate(KmConstructor::flags)
/** /**
* Signifies that the corresponding constructor is secondary, i.e. declared not in the class header, but in the class body. * Indicates that the corresponding constructor is secondary, i.e., declared not in the class header, but in the class body.
*/ */
var KmConstructor.isSecondary: Boolean by constructorBooleanFlag(Flag(ProtoFlags.IS_SECONDARY)) var KmConstructor.isSecondary: Boolean by constructorBooleanFlag(Flag(ProtoFlags.IS_SECONDARY))
/** /**
* Signifies that the corresponding constructor has non-stable parameter names, i.e. cannot be called with named arguments. * Indicates that the corresponding constructor has non-stable parameter names, i.e., cannot be called with named arguments.
*
* Currently, this attribute is Kotlin/Native-specific and is never set by Kotlin/JVM compiler.
* This may be changed in the future.
*/ */
var KmConstructor.hasNonStableParameterNames: Boolean by constructorBooleanFlag(Flag(ProtoFlags.IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES)) var KmConstructor.hasNonStableParameterNames: Boolean by constructorBooleanFlag(Flag(ProtoFlags.IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES))
// --- FUNCTION --- // --- FUNCTION ---
/** /**
* Represents kind of a corresponding function * Represents kind of the corresponding function.
*
* Kind indicates the origin of a declaration within a containing class. For details, see [MemberKind].
*/ */
var KmFunction.kind: MemberKind by memberKindDelegate(KmFunction::flags) var KmFunction.kind: MemberKind by memberKindDelegate(KmFunction::flags)
/** /**
* Represents visibility of a corresponding function * Represents visibility of the corresponding function.
*
* Note that Kotlin metadata has an extended list of visibilities; some of them are non-denotable.
* For additional details, see [Visibility].
*/ */
var KmFunction.visibility: Visibility by visibilityDelegate(KmFunction::flags) var KmFunction.visibility: Visibility by visibilityDelegate(KmFunction::flags)
/** /**
* Represents modality of a corresponding function. * Represents modality of the corresponding function.
*
* Modality determines when and where it is possible or mandatory to override a declaration.
* For additional details, see [Modality].
*
* [Modality.SEALED] is not applicable for [KmFunction] and setting it as a value results in undefined behavior.
*/ */
var KmFunction.modality: Modality by modalityDelegate(KmFunction::flags) var KmFunction.modality: Modality by modalityDelegate(KmFunction::flags)
/** /**
* Signifies that the corresponding function is `operator`. * Indicates that the corresponding function is `operator`.
*/ */
var KmFunction.isOperator: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_OPERATOR)) var KmFunction.isOperator: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_OPERATOR))
/** /**
* Signifies that the corresponding function is `infix`. * Indicates that the corresponding function is `infix`.
*/ */
var KmFunction.isInfix: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_INFIX)) var KmFunction.isInfix: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_INFIX))
/** /**
* Signifies that the corresponding function is `inline`. * Indicates that the corresponding function is `inline`.
*/ */
var KmFunction.isInline: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_INLINE)) var KmFunction.isInline: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_INLINE))
/** /**
* Signifies that the corresponding function is `tailrec`. * Indicates that the corresponding function is `tailrec`.
*/ */
var KmFunction.isTailrec: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_TAILREC)) var KmFunction.isTailrec: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_TAILREC))
/** /**
* Signifies that the corresponding function is `external`. * Indicates that the corresponding function is `external`.
*/ */
var KmFunction.isExternal: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_EXTERNAL_FUNCTION)) var KmFunction.isExternal: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_EXTERNAL_FUNCTION))
/** /**
* Signifies that the corresponding function is `suspend`. * Indicates that the corresponding function is `suspend`.
*/ */
var KmFunction.isSuspend: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_SUSPEND)) var KmFunction.isSuspend: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_SUSPEND))
/** /**
* Signifies that the corresponding function is `expect`. * Indicates that the corresponding function is `expect`.
*/ */
var KmFunction.isExpect: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_EXPECT_FUNCTION)) var KmFunction.isExpect: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_EXPECT_FUNCTION))
/** /**
* Signifies that the corresponding function has non-stable parameter names, i.e. cannot be called with named arguments. * Indicates that the corresponding function has non-stable parameter names, i.e., cannot be called with named arguments.
*
* Currently, this attribute is Kotlin/Native-specific and is never set by Kotlin/JVM compiler.
* This may be changed in the future.
*/ */
var KmFunction.hasNonStableParameterNames: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES)) var KmFunction.hasNonStableParameterNames: Boolean by functionBooleanFlag(Flag(ProtoFlags.IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES))
// --- PROPERTY --- // --- PROPERTY ---
/** /**
* Represents visibility of a corresponding property * Represents visibility of the corresponding property.
*
* Note that Kotlin metadata has an extended list of visibilities; some of them are non-denotable.
* For additional details, see [Visibility].
*/ */
var KmProperty.visibility: Visibility by visibilityDelegate(KmProperty::flags) var KmProperty.visibility: Visibility by visibilityDelegate(KmProperty::flags)
/** /**
* Represents modality of a corresponding property. * Represents modality of the corresponding property.
*
* Modality determines when and where it is possible or mandatory to override a declaration.
* For additional details, see [Modality].
*
* [Modality.SEALED] is not applicable for [KmProperty] and setting it as a value results in undefined behavior.
*/ */
var KmProperty.modality: Modality by modalityDelegate(KmProperty::flags) var KmProperty.modality: Modality by modalityDelegate(KmProperty::flags)
/** /**
* Represents kind of a corresponding property * Represents kind of the corresponding property.
*
* Kind indicates the origin of a declaration within a containing class. For details, see [MemberKind].
*/ */
var KmProperty.kind: MemberKind by memberKindDelegate(KmProperty::flags) var KmProperty.kind: MemberKind by memberKindDelegate(KmProperty::flags)
/** /**
* Signifies that the corresponding property is `var`. * Indicates that the corresponding property is `var`.
*/ */
var KmProperty.isVar: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_VAR)) var KmProperty.isVar: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_VAR))
/** /**
* Signifies that the corresponding property has a getter. * Indicates that the corresponding property has a getter.
*/ */
var KmProperty.hasGetter: Boolean by propertyBooleanFlag(Flag(ProtoFlags.HAS_GETTER)) var KmProperty.hasGetter: Boolean by propertyBooleanFlag(Flag(ProtoFlags.HAS_GETTER))
/** /**
* Signifies that the corresponding property has a setter. * Indicates that the corresponding property has a setter.
*/ */
var KmProperty.hasSetter: Boolean by propertyBooleanFlag(Flag(ProtoFlags.HAS_SETTER)) var KmProperty.hasSetter: Boolean by propertyBooleanFlag(Flag(ProtoFlags.HAS_SETTER))
/** /**
* Signifies that the corresponding property is `const`. * Indicates that the corresponding property is `const`.
*/ */
var KmProperty.isConst: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_CONST)) var KmProperty.isConst: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_CONST))
/** /**
* Signifies that the corresponding property is `lateinit`. * Indicates that the corresponding property is `lateinit`.
*/ */
var KmProperty.isLateinit: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_LATEINIT)) var KmProperty.isLateinit: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_LATEINIT))
/** /**
* Signifies that the corresponding property has a constant value. On JVM, this flag allows an optimization similarly to * Indicates that the corresponding property has a constant value. On JVM, this flag allows an optimization similarly to
* [KmProperty.hasAnnotations]: constant values of properties are written to the bytecode directly, and this flag can be used to avoid * [KmProperty.hasAnnotations]: constant values of properties are written to the bytecode directly, and this flag can be used to avoid
* reading the value from the bytecode in case there isn't one. * reading the value from the bytecode in case there isn't one.
*
* Not to be confused with [KmProperty.isConst], because `const` modifier is applicable only to properties on top-level and inside objects,
* while property in a regular class can also have constant value.
* Whether the property has a constant value is ultimately decided by the compiler and its optimizations.
* Generally, a property initializer that can be computed in compile time is likely to have a constant value written to the bytecode.
* In the following example, properties `a` and `b` have `hasConstant = true`, while `c` has `hasConstant = false`:
*
* ```
* class X {
* val a = 1
* val b = a
*
* fun x() = 2
* val c = x()
* }
* ```
*/ */
var KmProperty.hasConstant: Boolean by propertyBooleanFlag(Flag(ProtoFlags.HAS_CONSTANT)) var KmProperty.hasConstant: Boolean by propertyBooleanFlag(Flag(ProtoFlags.HAS_CONSTANT))
/** /**
* Signifies that the corresponding property is `external`. * Indicates that the corresponding property is `external`.
*/ */
var KmProperty.isExternal: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_EXTERNAL_PROPERTY)) var KmProperty.isExternal: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_EXTERNAL_PROPERTY))
/** /**
* Signifies that the corresponding property is a delegated property. * Indicates that the corresponding property is a delegated property.
*
* Not to be confused with interface delegation.
* If a property was produced by interface delegation, it would have the corresponding [KmProperty.kind].
*/ */
var KmProperty.isDelegated: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_DELEGATED)) var KmProperty.isDelegated: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_DELEGATED))
/** /**
* Signifies that the corresponding property is `expect`. * Indicates that the corresponding property is `expect`.
*/ */
var KmProperty.isExpect: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_EXPECT_PROPERTY)) var KmProperty.isExpect: Boolean by propertyBooleanFlag(Flag(ProtoFlags.IS_EXPECT_PROPERTY))
// --- PROPERTY ACCESSOR --- // --- PROPERTY ACCESSOR ---
/** /**
* Represents visibility of a corresponding property accessor. * Represents visibility of the corresponding property accessor.
*
* Note that Kotlin metadata has an extended list of visibilities; some of them are non-denotable.
* For additional details, see [Visibility].
*/ */
var KmPropertyAccessorAttributes.visibility: Visibility by visibilityDelegate(KmPropertyAccessorAttributes::flags) var KmPropertyAccessorAttributes.visibility: Visibility by visibilityDelegate(KmPropertyAccessorAttributes::flags)
/** /**
* Represents modality of a corresponding property accessor. * Represents modality of the corresponding property accessor.
*
* Modality determines when and where it is possible or mandatory to override a declaration.
* For additional details, see [Modality].
*
* [Modality.SEALED] is not applicable for [KmPropertyAccessorAttributes] and setting it as a value results in undefined behavior.
*/ */
var KmPropertyAccessorAttributes.modality: Modality by modalityDelegate(KmPropertyAccessorAttributes::flags) var KmPropertyAccessorAttributes.modality: Modality by modalityDelegate(KmPropertyAccessorAttributes::flags)
/** /**
* Signifies that the corresponding property accessor is not default, i.e. it has a body and/or annotations in the source code. * Indicates that the corresponding property accessor is not default, i.e. it has a body and/or annotations in the source code,
* or the property is delegated.
*/ */
var KmPropertyAccessorAttributes.isNotDefault: Boolean by propertyAccessorBooleanFlag(Flag(ProtoFlags.IS_NOT_DEFAULT)) var KmPropertyAccessorAttributes.isNotDefault: Boolean by propertyAccessorBooleanFlag(Flag(ProtoFlags.IS_NOT_DEFAULT))
/** /**
* Signifies that the corresponding property accessor is `external`. * Indicates that the corresponding property accessor is `external`.
*/ */
var KmPropertyAccessorAttributes.isExternal: Boolean by propertyAccessorBooleanFlag(Flag(ProtoFlags.IS_EXTERNAL_ACCESSOR)) var KmPropertyAccessorAttributes.isExternal: Boolean by propertyAccessorBooleanFlag(Flag(ProtoFlags.IS_EXTERNAL_ACCESSOR))
/** /**
* Signifies that the corresponding property accessor is `inline`. * Indicates that the corresponding property accessor is `inline`.
*/ */
var KmPropertyAccessorAttributes.isInline: Boolean by propertyAccessorBooleanFlag(Flag(ProtoFlags.IS_INLINE_ACCESSOR)) var KmPropertyAccessorAttributes.isInline: Boolean by propertyAccessorBooleanFlag(Flag(ProtoFlags.IS_INLINE_ACCESSOR))
// --- TYPE & TYPE_PARAM // --- TYPE & TYPE_PARAM
/** /**
* Signifies that the corresponding type is marked as nullable, i.e. has a question mark at the end of its notation. * Indicates that the corresponding type is marked as nullable, i.e. has a question mark at the end of its notation.
*/ */
var KmType.isNullable: Boolean by typeBooleanFlag(FlagImpl(0, 1, 1)) var KmType.isNullable: Boolean by typeBooleanFlag(FlagImpl(0, 1, 1))
/** /**
* Signifies that the corresponding type is `suspend`. * Indicates that the corresponding type is `suspend`.
*/ */
var KmType.isSuspend: Boolean by typeBooleanFlag(FlagImpl(ProtoFlags.SUSPEND_TYPE.offset + 1, ProtoFlags.SUSPEND_TYPE.bitWidth, 1)) var KmType.isSuspend: Boolean by typeBooleanFlag(FlagImpl(ProtoFlags.SUSPEND_TYPE.offset + 1, ProtoFlags.SUSPEND_TYPE.bitWidth, 1))
/** /**
* Signifies that the corresponding type is [definitely non-null](https://kotlinlang.org/docs/whatsnew17.html#stable-definitely-non-nullable-types). * Indicates that the corresponding type is [definitely non-null](https://kotlinlang.org/docs/whatsnew17.html#stable-definitely-non-nullable-types).
*/ */
var KmType.isDefinitelyNonNull: Boolean by typeBooleanFlag( var KmType.isDefinitelyNonNull: Boolean by typeBooleanFlag(
FlagImpl( FlagImpl(
@@ -334,14 +415,17 @@ var KmType.isDefinitelyNonNull: Boolean by typeBooleanFlag(
/** /**
* Signifies that the corresponding type parameter is `reified`. * Indicates that the corresponding type parameter is `reified`.
*/ */
var KmTypeParameter.isReified: Boolean by BooleanFlagDelegate(KmTypeParameter::flags, FlagImpl(0, 1, 1)) var KmTypeParameter.isReified: Boolean by BooleanFlagDelegate(KmTypeParameter::flags, FlagImpl(0, 1, 1))
// --- TYPE ALIAS --- // --- TYPE ALIAS ---
/** /**
* Represents visibility of a corresponding type alias. * Represents visibility of the corresponding type alias.
*
* Note that Kotlin metadata has an extended list of visibilities; some of them are non-denotable.
* For additional details, see [Visibility].
*/ */
var KmTypeAlias.visibility: Visibility by visibilityDelegate(KmTypeAlias::flags) var KmTypeAlias.visibility: Visibility by visibilityDelegate(KmTypeAlias::flags)
@@ -350,7 +434,7 @@ var KmTypeAlias.visibility: Visibility by visibilityDelegate(KmTypeAlias::flags)
/** /**
* Signifies that the corresponding value parameter declares a default value. Note that the default value itself can be a complex * Indicates that the corresponding value parameter declares a default value. Note that the default value itself can be a complex
* expression and is not available via metadata. Also note that in case of an override of a parameter with default value, the * expression and is not available via metadata. Also note that in case of an override of a parameter with default value, the
* parameter in the derived method does _not_ declare the default value, but the parameter is * parameter in the derived method does _not_ declare the default value, but the parameter is
* still optional at the call site because the default value from the base method is used. * still optional at the call site because the default value from the base method is used.
@@ -358,19 +442,19 @@ var KmTypeAlias.visibility: Visibility by visibilityDelegate(KmTypeAlias::flags)
var KmValueParameter.declaresDefaultValue: Boolean by valueParameterBooleanFlag(Flag(ProtoFlags.DECLARES_DEFAULT_VALUE)) var KmValueParameter.declaresDefaultValue: Boolean by valueParameterBooleanFlag(Flag(ProtoFlags.DECLARES_DEFAULT_VALUE))
/** /**
* Signifies that the corresponding value parameter is `crossinline`. * Indicates that the corresponding value parameter is `crossinline`.
*/ */
var KmValueParameter.isCrossinline: Boolean by valueParameterBooleanFlag(Flag(ProtoFlags.IS_CROSSINLINE)) var KmValueParameter.isCrossinline: Boolean by valueParameterBooleanFlag(Flag(ProtoFlags.IS_CROSSINLINE))
/** /**
* Signifies that the corresponding value parameter is `noinline`. * Indicates that the corresponding value parameter is `noinline`.
*/ */
var KmValueParameter.isNoinline: Boolean by valueParameterBooleanFlag(Flag(ProtoFlags.IS_NOINLINE)) var KmValueParameter.isNoinline: Boolean by valueParameterBooleanFlag(Flag(ProtoFlags.IS_NOINLINE))
// --- EFFECT EXPRESSION --- // --- EFFECT EXPRESSION ---
/** /**
* Signifies that the corresponding effect expression should be negated to compute the proposition or the conclusion of an effect. * Indicates that the corresponding effect expression should be negated to compute the proposition or the conclusion of an effect.
* *
* Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format * Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format
* may change in a subsequent release. * may change in a subsequent release.
@@ -379,7 +463,7 @@ var KmValueParameter.isNoinline: Boolean by valueParameterBooleanFlag(Flag(Proto
var KmEffectExpression.isNegated: Boolean by BooleanFlagDelegate(KmEffectExpression::flags, Flag(ProtoFlags.IS_NEGATED)) var KmEffectExpression.isNegated: Boolean by BooleanFlagDelegate(KmEffectExpression::flags, Flag(ProtoFlags.IS_NEGATED))
/** /**
* Signifies that the corresponding effect expression checks whether a value of some variable is `null`. * Indicates that the corresponding effect expression checks whether a value of some variable is `null`.
* *
* Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format * Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format
* may change in a subsequent release. * may change in a subsequent release.
@@ -12,10 +12,13 @@ import org.jetbrains.kotlin.metadata.ProtoBuf.Visibility as ProtoVisibility
import org.jetbrains.kotlin.metadata.ProtoBuf.Modality as ProtoModality import org.jetbrains.kotlin.metadata.ProtoBuf.Modality as ProtoModality
import org.jetbrains.kotlin.metadata.ProtoBuf.MemberKind as ProtoMemberKind import org.jetbrains.kotlin.metadata.ProtoBuf.MemberKind as ProtoMemberKind
// Do not reorder any enums in this file! // Pay attention to the order of enums in this file!
// Order of enum values is directly linked to order of corresponding protobuf enums in org.jetbrains.kotlin.metadata.ProtoBuf.
// Changes in the binary format should be reflected in the protobuf and therefore in enums in this file.
// Arbitrary reordering of enum members here will likely break deserialization.
/** /**
* Represents visibility level (also known as access level) of a corresponding declaration. * Represents visibility level (also known as access level) of the corresponding declaration.
* Some of these visibilities may be non-denotable in Kotlin. * Some of these visibilities may be non-denotable in Kotlin.
*/ */
enum class Visibility(kind: Int) { enum class Visibility(kind: Int) {
@@ -72,7 +75,9 @@ enum class Visibility(kind: Int) {
} }
/** /**
* Represents modality of a corresponding declaration. * Represents modality of the corresponding declaration.
*
* Modality determines when and where it is possible to extend/override a class/member.
*/ */
enum class Modality(kind: Int) { enum class Modality(kind: Int) {
/** /**
@@ -93,8 +98,8 @@ enum class Modality(kind: Int) {
/** /**
* Signifies that the corresponding declaration is `sealed`. * Signifies that the corresponding declaration is `sealed`.
* *
* Pay attention that this modality is not applicable to class' members. * Pay attention that this modality is not applicable to class members.
* Setting it as a value for member modality leads to an undefined behaviour. * Setting it as a value for member modality leads to an undefined behavior.
*/ */
SEALED(ProtoModality.SEALED_VALUE) SEALED(ProtoModality.SEALED_VALUE)
; ;
@@ -103,11 +108,11 @@ enum class Modality(kind: Int) {
} }
/** /**
* Represents the nature of a corresponding class. * Represents the kind of the corresponding class, i.e., the way it is declared in the source code.
*/ */
enum class ClassKind(kind: Int) { enum class ClassKind(kind: Int) {
/** /**
* Signifies that the corresponding class is a usual `class`. * Signifies that the corresponding class is a usual or anonymous class.
*/ */
CLASS(ProtoClassKind.CLASS_VALUE), CLASS(ProtoClassKind.CLASS_VALUE),
@@ -132,7 +137,7 @@ enum class ClassKind(kind: Int) {
ANNOTATION_CLASS(ProtoClassKind.ANNOTATION_CLASS_VALUE), ANNOTATION_CLASS(ProtoClassKind.ANNOTATION_CLASS_VALUE),
/** /**
* Signifies that the corresponding class is a non-companion `object`. * Signifies that the corresponding class is a non-companion, singleton `object`.
*/ */
OBJECT(ProtoClassKind.OBJECT_VALUE), OBJECT(ProtoClassKind.OBJECT_VALUE),
@@ -169,7 +174,7 @@ enum class MemberKind(kind: Int) {
* Signifies that the corresponding function or property exists in the containing class because it has been produced * Signifies that the corresponding function or property exists in the containing class because it has been produced
* by interface delegation. * by interface delegation.
* *
* Do not confuse with property delegation which is denoted by [KmProperty.isDelegated]. * Not to be confused with property delegation which is denoted by [KmProperty.isDelegated].
*/ */
DELEGATION(ProtoMemberKind.DELEGATION_VALUE), DELEGATION(ProtoMemberKind.DELEGATION_VALUE),
@@ -33,6 +33,10 @@ interface KmDeclarationContainer {
/** /**
* Represents a Kotlin class. * Represents a Kotlin class.
*
* 'Class' here is used in a broad sense and includes interfaces, enum classes, companion objects, et cetera.
* Precise kind of the class can be obtained via [KmClass.kind].
* Various class attributes can be read and manipulated via extension properties, such as [KmClass.visibility] or [KmClass.isData].
*/ */
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
class KmClass : KmClassVisitor(), KmDeclarationContainer { class KmClass : KmClassVisitor(), KmDeclarationContainer {
@@ -306,7 +310,8 @@ class KmLambda : KmLambdaVisitor() {
/** /**
* Represents a constructor of a Kotlin class. * Represents a constructor of a Kotlin class.
* *
* @property flags constructor flags, consisting of [Flag.HAS_ANNOTATIONS], a visibility flag and [Flag.Constructor] flags * Various constructor attributes can be read and manipulated via extension properties,
* such as [KmConstructor.visibility] or [KmConstructor.isSecondary].
*/ */
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
class KmConstructor @Deprecated(flagsCtorDeprecated) constructor( class KmConstructor @Deprecated(flagsCtorDeprecated) constructor(
@@ -357,7 +362,9 @@ class KmConstructor @Deprecated(flagsCtorDeprecated) constructor(
/** /**
* Represents a Kotlin function declaration. * Represents a Kotlin function declaration.
* *
* @property flags function flags, consisting of [Flag.HAS_ANNOTATIONS], visibility flag, modality flag and [Flag.Function] flags * Various function attributes can be read and manipulated via extension properties,
* such as [KmFunction.visibility] or [KmFunction.isSuspend].
*
* @property name the name of the function * @property name the name of the function
*/ */
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@@ -464,8 +471,9 @@ class KmFunction @Deprecated(flagsCtorDeprecated) constructor(
/** /**
* Represents a Kotlin property accessor. * Represents a Kotlin property accessor.
*
* Does not contain meaningful information except attributes, such as visibility and modality. * Does not contain meaningful information except attributes, such as visibility and modality.
* Attributes can be read and written using extension functions, e.g. [KmPropertyAccessorAttributes.visibility] or [KmPropertyAccessorAttributes.isNotDefault]. * Attributes can be read and written using extension properties, e.g. [KmPropertyAccessorAttributes.visibility] or [KmPropertyAccessorAttributes.isNotDefault].
*/ */
public class KmPropertyAccessorAttributes internal constructor(internal var flags: Int) { public class KmPropertyAccessorAttributes internal constructor(internal var flags: Int) {
public constructor() : this(0) public constructor() : this(0)
@@ -474,7 +482,11 @@ public class KmPropertyAccessorAttributes internal constructor(internal var flag
/** /**
* Represents a Kotlin property declaration. * Represents a Kotlin property declaration.
* *
* @property flags property flags, consisting of [Flag.HAS_ANNOTATIONS], visibility flag, modality flag and [Flag.Property] flags * Various property attributes can be read and manipulated via extension properties,
* such as [KmProperty.visibility] or [KmProperty.isVar].
*
* Getter and setter attributes are available separately via extensions on [KmProperty.getter] and [KmProperty.setter] correspondingly.
*
* @property name the name of the property * @property name the name of the property
*/ */
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@@ -489,7 +501,7 @@ class KmProperty @Deprecated(flagsCtorDeprecated) constructor(
/** /**
* Attributes of the getter of this property. * Attributes of the getter of this property.
* Attributes can be retrieved with extension functions, such as [KmPropertyAccessorAttributes.visibility] or [KmPropertyAccessorAttributes.isNotDefault]. * Attributes can be retrieved with extension properties, such as [KmPropertyAccessorAttributes.visibility] or [KmPropertyAccessorAttributes.isNotDefault].
* *
* Getter for property is always present, hence return type of this function is non-nullable. * Getter for property is always present, hence return type of this function is non-nullable.
*/ */
@@ -497,7 +509,7 @@ class KmProperty @Deprecated(flagsCtorDeprecated) constructor(
/** /**
* Attributes of the setter of this property. * Attributes of the setter of this property.
* Attributes can be retrieved with extension functions, such as [KmPropertyAccessorAttributes.visibility] or [KmPropertyAccessorAttributes.isNotDefault]. * Attributes can be retrieved with extension properties, such as [KmPropertyAccessorAttributes.visibility] or [KmPropertyAccessorAttributes.isNotDefault].
* *
* Returns null if setter is absent, i.e. [KmProperty.isVar] is false. * Returns null if setter is absent, i.e. [KmProperty.isVar] is false.
*/ */
@@ -635,7 +647,9 @@ class KmProperty @Deprecated(flagsCtorDeprecated) constructor(
/** /**
* Represents a Kotlin type alias declaration. * Represents a Kotlin type alias declaration.
* *
* @property flags type alias flags, consisting of [Flag.HAS_ANNOTATIONS] and visibility flag * Various type alias attributes can be read and manipulated via extension properties,
* such as [KmTypeAlias.visibility] or [KmTypeAlias.hasAnnotations].
*
* @property name the name of the type alias * @property name the name of the type alias
*/ */
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@@ -720,7 +734,9 @@ class KmTypeAlias @Deprecated(flagsCtorDeprecated) constructor(
/** /**
* Represents a value parameter of a Kotlin constructor, function or property setter. * Represents a value parameter of a Kotlin constructor, function or property setter.
* *
* @property flags value parameter flags, consisting of [Flag.ValueParameter] flags * Various value parameter attributes can be read and manipulated via extension properties,
* such as [KmValueParameter.declaresDefaultValue].
*
* @property name the name of the value parameter * @property name the name of the value parameter
*/ */
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@@ -774,7 +790,9 @@ class KmValueParameter @Deprecated(flagsCtorDeprecated) constructor(
/** /**
* Represents a type parameter of a Kotlin class, function, property or type alias. * Represents a type parameter of a Kotlin class, function, property or type alias.
* *
* @property flags type parameter flags, consisting of [Flag.TypeParameter] flags * Various type parameter attributes can be read and manipulated via extension properties,
* such as [KmTypeParameter.isReified].
*
* @property name the name of the type parameter * @property name the name of the type parameter
* @property id the id of the type parameter, useful to be able to uniquely identify the type parameter in different contexts where * @property id the id of the type parameter, useful to be able to uniquely identify the type parameter in different contexts where
* the name is not enough (e.g. `class A<T> { fun <T> foo(t: T) }`) * the name is not enough (e.g. `class A<T> { fun <T> foo(t: T) }`)
@@ -822,7 +840,8 @@ class KmTypeParameter @Deprecated(flagsCtorDeprecated) constructor(
/** /**
* Represents a type. * Represents a type.
* *
* @property flags type flags, consisting of [Flag.Type] flags * Various type attributes can be read and manipulated via extension properties,
* such as [KmType.isNullable].
*/ */
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
class KmType @Deprecated(flagsCtorDeprecated) constructor( class KmType @Deprecated(flagsCtorDeprecated) constructor(
@@ -1086,6 +1105,9 @@ class KmEffect(
* *
* Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format * Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format
* may change in a subsequent release. * may change in a subsequent release.
*
* Various effect expression attributes can be read and manipulated via extension properties,
* such as [KmEffectExpression.isNegated].
*/ */
@ExperimentalContracts @ExperimentalContracts
@Suppress("DEPRECATION") @Suppress("DEPRECATION")