• 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 
18 package com.squareup.kotlinpoet.metadata
19 
20 import javax.lang.model.element.TypeElement
21 import kotlin.annotation.AnnotationTarget.CLASS
22 import kotlin.annotation.AnnotationTarget.FUNCTION
23 import kotlin.annotation.AnnotationTarget.PROPERTY
24 import kotlin.reflect.KClass
25 import kotlinx.metadata.KmClass
26 import kotlinx.metadata.jvm.KotlinClassMetadata
27 import kotlinx.metadata.jvm.Metadata
28 
29 /**
30  * Indicates that a given API is part of the experimental KotlinPoet metadata support. This exists
31  * because kotlinx-metadata is not a stable API, and will remain in place until it is.
32  */
33 @RequiresOptIn
34 @Retention(AnnotationRetention.BINARY)
35 @Target(CLASS, FUNCTION, PROPERTY)
36 public annotation class KotlinPoetMetadataPreview
37 
38 /** @return a new [KmClass] representation of the Kotlin metadata for [this] class. */
39 @KotlinPoetMetadataPreview
toKmClassnull40 public fun KClass<*>.toKmClass(): KmClass = java.toKmClass()
41 
42 /** @return a new [KmClass] representation of the Kotlin metadata for [this] class. */
43 @KotlinPoetMetadataPreview
44 public fun Class<*>.toKmClass(): KmClass = readMetadata(::getAnnotation).toKmClass()
45 
46 /** @return a new [KmClass] representation of the Kotlin metadata for [this] type. */
47 @KotlinPoetMetadataPreview
48 public fun TypeElement.toKmClass(): KmClass = readMetadata(::getAnnotation).toKmClass()
49 
50 @KotlinPoetMetadataPreview
51 public fun Metadata.toKmClass(): KmClass {
52   return toKotlinClassMetadata<KotlinClassMetadata.Class>()
53     .kmClass
54 }
55 
56 @KotlinPoetMetadataPreview
toKotlinClassMetadatanull57 public inline fun <reified T : KotlinClassMetadata> Metadata.toKotlinClassMetadata(): T {
58   val expectedType = T::class
59   val metadata = readKotlinClassMetadata()
60   return when (expectedType) {
61     KotlinClassMetadata.Class::class -> {
62       check(metadata is KotlinClassMetadata.Class)
63       metadata as T
64     }
65     KotlinClassMetadata.FileFacade::class -> {
66       check(metadata is KotlinClassMetadata.FileFacade)
67       metadata as T
68     }
69     KotlinClassMetadata.SyntheticClass::class ->
70       throw UnsupportedOperationException("SyntheticClass isn't supported yet!")
71     KotlinClassMetadata.MultiFileClassFacade::class ->
72       throw UnsupportedOperationException("MultiFileClassFacade isn't supported yet!")
73     KotlinClassMetadata.MultiFileClassPart::class ->
74       throw UnsupportedOperationException("MultiFileClassPart isn't supported yet!")
75     KotlinClassMetadata.Unknown::class ->
76       throw RuntimeException("Recorded unknown metadata type! $metadata")
77     else -> TODO("Unrecognized KotlinClassMetadata type: $expectedType")
78   }
79 }
80 
81 /**
82  * Returns the [KotlinClassMetadata] this represents. In general you should only use this function
83  * when you don't know what the underlying [KotlinClassMetadata] subtype is, otherwise you should
84  * use one of the more direct functions like [toKmClass].
85  */
86 @KotlinPoetMetadataPreview
readKotlinClassMetadatanull87 public fun Metadata.readKotlinClassMetadata(): KotlinClassMetadata {
88   val metadata = KotlinClassMetadata.read(asClassHeader())
89   checkNotNull(metadata) {
90     "Could not parse metadata! Try bumping kotlinpoet and/or kotlinx-metadata version."
91   }
92   return metadata
93 }
94 
readMetadatanull95 private inline fun readMetadata(lookup: ((Class<Metadata>) -> Metadata?)): Metadata {
96   return checkNotNull(lookup.invoke(Metadata::class.java)) {
97     "No Metadata annotation found! Must be Kotlin code built with the standard library on the classpath."
98   }
99 }
100 
asClassHeadernull101 private fun Metadata.asClassHeader(): Metadata {
102   return Metadata(
103     kind = kind,
104     metadataVersion = metadataVersion,
105     data1 = data1,
106     data2 = data2,
107     extraString = extraString,
108     packageName = packageName,
109     extraInt = extraInt,
110   )
111 }
112