• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 Square, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 @file:JvmName("KotlinPoetMetadata")
17 @file:Suppress("unused")
18 
19 package com.squareup.kotlinpoet.metadata
20 
21 import javax.lang.model.element.TypeElement
22 import kotlin.annotation.AnnotationTarget.CLASS
23 import kotlin.annotation.AnnotationTarget.FUNCTION
24 import kotlin.annotation.AnnotationTarget.PROPERTY
25 import kotlin.reflect.KClass
26 import kotlinx.metadata.KmClass
27 import kotlinx.metadata.jvm.KotlinClassHeader
28 import kotlinx.metadata.jvm.KotlinClassMetadata
29 
30 /**
31  * Indicates that a given API is part of the experimental KotlinPoet metadata support. This exists
32  * because kotlinx-metadata is not a stable API, and will remain in place until it is.
33  */
34 @RequiresOptIn
35 @Retention(AnnotationRetention.BINARY)
36 @Target(CLASS, FUNCTION, PROPERTY)
37 public annotation class KotlinPoetMetadataPreview
38 
39 /** @return a new [KmClass] representation of the Kotlin metadata for [this] class. */
40 @KotlinPoetMetadataPreview
toKmClassnull41 public fun KClass<*>.toKmClass(): KmClass = java.toKmClass()
42 
43 /** @return a new [KmClass] representation of the Kotlin metadata for [this] class. */
44 @KotlinPoetMetadataPreview
45 public fun Class<*>.toKmClass(): KmClass = readMetadata(::getAnnotation).toKmClass()
46 
47 /** @return a new [KmClass] representation of the Kotlin metadata for [this] type. */
48 @KotlinPoetMetadataPreview
49 public fun TypeElement.toKmClass(): KmClass = readMetadata(::getAnnotation).toKmClass()
50 
51 @KotlinPoetMetadataPreview
52 public fun Metadata.toKmClass(): KmClass {
53   return toKotlinClassMetadata<KotlinClassMetadata.Class>()
54     .toKmClass()
55 }
56 
57 @KotlinPoetMetadataPreview
toKotlinClassMetadatanull58 public inline fun <reified T : KotlinClassMetadata> Metadata.toKotlinClassMetadata(): T {
59   val expectedType = T::class
60   val metadata = readKotlinClassMetadata()
61   return when (expectedType) {
62     KotlinClassMetadata.Class::class -> {
63       check(metadata is KotlinClassMetadata.Class)
64       metadata as T
65     }
66     KotlinClassMetadata.FileFacade::class -> {
67       check(metadata is KotlinClassMetadata.FileFacade)
68       metadata as T
69     }
70     KotlinClassMetadata.SyntheticClass::class ->
71       throw UnsupportedOperationException("SyntheticClass isn't supported yet!")
72     KotlinClassMetadata.MultiFileClassFacade::class ->
73       throw UnsupportedOperationException("MultiFileClassFacade isn't supported yet!")
74     KotlinClassMetadata.MultiFileClassPart::class ->
75       throw UnsupportedOperationException("MultiFileClassPart isn't supported yet!")
76     KotlinClassMetadata.Unknown::class ->
77       throw RuntimeException("Recorded unknown metadata type! $metadata")
78     else -> TODO("Unrecognized KotlinClassMetadata type: $expectedType")
79   }
80 }
81 
82 /**
83  * Returns the [KotlinClassMetadata] this represents. In general you should only use this function
84  * when you don't know what the underlying [KotlinClassMetadata] subtype is, otherwise you should
85  * use one of the more direct functions like [toKmClass].
86  */
87 @KotlinPoetMetadataPreview
readKotlinClassMetadatanull88 public fun Metadata.readKotlinClassMetadata(): KotlinClassMetadata {
89   val metadata = KotlinClassMetadata.read(asClassHeader())
90   checkNotNull(metadata) {
91     "Could not parse metadata! Try bumping kotlinpoet and/or kotlinx-metadata version."
92   }
93   return metadata
94 }
95 
readMetadatanull96 private inline fun readMetadata(lookup: ((Class<Metadata>) -> Metadata?)): Metadata {
97   return checkNotNull(lookup.invoke(Metadata::class.java)) {
98     "No Metadata annotation found! Must be Kotlin code built with the standard library on the classpath."
99   }
100 }
101 
asClassHeadernull102 private fun Metadata.asClassHeader(): KotlinClassHeader {
103   return KotlinClassHeader(
104     kind = kind,
105     metadataVersion = metadataVersion,
106     data1 = data1,
107     data2 = data2,
108     extraString = extraString,
109     packageName = packageName,
110     extraInt = extraInt,
111   )
112 }
113