aboutsummaryrefslogtreecommitdiff
path: root/interop/kotlinx-metadata/src/main/kotlin/com/squareup/kotlinpoet/metadata/KotlinPoetMetadata.kt
diff options
context:
space:
mode:
Diffstat (limited to 'interop/kotlinx-metadata/src/main/kotlin/com/squareup/kotlinpoet/metadata/KotlinPoetMetadata.kt')
-rw-r--r--interop/kotlinx-metadata/src/main/kotlin/com/squareup/kotlinpoet/metadata/KotlinPoetMetadata.kt112
1 files changed, 112 insertions, 0 deletions
diff --git a/interop/kotlinx-metadata/src/main/kotlin/com/squareup/kotlinpoet/metadata/KotlinPoetMetadata.kt b/interop/kotlinx-metadata/src/main/kotlin/com/squareup/kotlinpoet/metadata/KotlinPoetMetadata.kt
new file mode 100644
index 00000000..6cb3c91d
--- /dev/null
+++ b/interop/kotlinx-metadata/src/main/kotlin/com/squareup/kotlinpoet/metadata/KotlinPoetMetadata.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:JvmName("KotlinPoetMetadata")
+@file:Suppress("unused")
+
+package com.squareup.kotlinpoet.metadata
+
+import javax.lang.model.element.TypeElement
+import kotlin.annotation.AnnotationTarget.CLASS
+import kotlin.annotation.AnnotationTarget.FUNCTION
+import kotlin.annotation.AnnotationTarget.PROPERTY
+import kotlin.reflect.KClass
+import kotlinx.metadata.KmClass
+import kotlinx.metadata.jvm.KotlinClassHeader
+import kotlinx.metadata.jvm.KotlinClassMetadata
+
+/**
+ * Indicates that a given API is part of the experimental KotlinPoet metadata support. This exists
+ * because kotlinx-metadata is not a stable API, and will remain in place until it is.
+ */
+@RequiresOptIn
+@Retention(AnnotationRetention.BINARY)
+@Target(CLASS, FUNCTION, PROPERTY)
+public annotation class KotlinPoetMetadataPreview
+
+/** @return a new [KmClass] representation of the Kotlin metadata for [this] class. */
+@KotlinPoetMetadataPreview
+public fun KClass<*>.toKmClass(): KmClass = java.toKmClass()
+
+/** @return a new [KmClass] representation of the Kotlin metadata for [this] class. */
+@KotlinPoetMetadataPreview
+public fun Class<*>.toKmClass(): KmClass = readMetadata(::getAnnotation).toKmClass()
+
+/** @return a new [KmClass] representation of the Kotlin metadata for [this] type. */
+@KotlinPoetMetadataPreview
+public fun TypeElement.toKmClass(): KmClass = readMetadata(::getAnnotation).toKmClass()
+
+@KotlinPoetMetadataPreview
+public fun Metadata.toKmClass(): KmClass {
+ return toKotlinClassMetadata<KotlinClassMetadata.Class>()
+ .toKmClass()
+}
+
+@KotlinPoetMetadataPreview
+public inline fun <reified T : KotlinClassMetadata> Metadata.toKotlinClassMetadata(): T {
+ val expectedType = T::class
+ val metadata = readKotlinClassMetadata()
+ return when (expectedType) {
+ KotlinClassMetadata.Class::class -> {
+ check(metadata is KotlinClassMetadata.Class)
+ metadata as T
+ }
+ KotlinClassMetadata.FileFacade::class -> {
+ check(metadata is KotlinClassMetadata.FileFacade)
+ metadata as T
+ }
+ KotlinClassMetadata.SyntheticClass::class ->
+ throw UnsupportedOperationException("SyntheticClass isn't supported yet!")
+ KotlinClassMetadata.MultiFileClassFacade::class ->
+ throw UnsupportedOperationException("MultiFileClassFacade isn't supported yet!")
+ KotlinClassMetadata.MultiFileClassPart::class ->
+ throw UnsupportedOperationException("MultiFileClassPart isn't supported yet!")
+ KotlinClassMetadata.Unknown::class ->
+ throw RuntimeException("Recorded unknown metadata type! $metadata")
+ else -> TODO("Unrecognized KotlinClassMetadata type: $expectedType")
+ }
+}
+
+/**
+ * Returns the [KotlinClassMetadata] this represents. In general you should only use this function
+ * when you don't know what the underlying [KotlinClassMetadata] subtype is, otherwise you should
+ * use one of the more direct functions like [toKmClass].
+ */
+@KotlinPoetMetadataPreview
+public fun Metadata.readKotlinClassMetadata(): KotlinClassMetadata {
+ val metadata = KotlinClassMetadata.read(asClassHeader())
+ checkNotNull(metadata) {
+ "Could not parse metadata! Try bumping kotlinpoet and/or kotlinx-metadata version."
+ }
+ return metadata
+}
+
+private inline fun readMetadata(lookup: ((Class<Metadata>) -> Metadata?)): Metadata {
+ return checkNotNull(lookup.invoke(Metadata::class.java)) {
+ "No Metadata annotation found! Must be Kotlin code built with the standard library on the classpath."
+ }
+}
+
+private fun Metadata.asClassHeader(): KotlinClassHeader {
+ return KotlinClassHeader(
+ kind = kind,
+ metadataVersion = metadataVersion,
+ data1 = data1,
+ data2 = data2,
+ extraString = extraString,
+ packageName = packageName,
+ extraInt = extraInt,
+ )
+}