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.metadata.KmClass 22 import kotlin.metadata.jvm.KotlinClassMetadata 23 import kotlin.metadata.jvm.Metadata 24 import kotlin.reflect.KClass 25 26 /** 27 * @param lenient see docs on [KotlinClassMetadata.readStrict] and [KotlinClassMetadata.readLenient] for more details. 28 * @return a new [KmClass] representation of the Kotlin metadata for [this] class. 29 */ toKmClassnull30internal fun KClass<*>.toKmClass(lenient: Boolean): KmClass = java.toKmClass(lenient) 31 32 /** 33 * @param lenient see docs on [KotlinClassMetadata.readStrict] and [KotlinClassMetadata.readLenient] for more details. 34 * @return a new [KmClass] representation of the Kotlin metadata for [this] class. 35 */ 36 internal fun Class<*>.toKmClass(lenient: Boolean): KmClass = readMetadata(::getAnnotation).toKmClass(lenient) 37 38 /** 39 * @param lenient see docs on [KotlinClassMetadata.readStrict] and [KotlinClassMetadata.readLenient] for more details. 40 * @return a new [KmClass] representation of the Kotlin metadata for [this] type. 41 */ 42 internal fun TypeElement.toKmClass(lenient: Boolean): KmClass = readMetadata(::getAnnotation).toKmClass(lenient) 43 44 /** 45 * @param lenient see docs on [KotlinClassMetadata.readStrict] and [KotlinClassMetadata.readLenient] for more details. 46 */ 47 internal fun Metadata.toKmClass(lenient: Boolean): KmClass { 48 return toKotlinClassMetadata<KotlinClassMetadata.Class>(lenient) 49 .kmClass 50 } 51 52 /** 53 * @param lenient see docs on [KotlinClassMetadata.readStrict] and [KotlinClassMetadata.readLenient] for more details. 54 */ toKotlinClassMetadatanull55internal inline fun <reified T : KotlinClassMetadata> Metadata.toKotlinClassMetadata( 56 lenient: Boolean, 57 ): T { 58 val expectedType = T::class 59 val metadata = readKotlinClassMetadata(lenient) 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 * @param lenient see docs on [KotlinClassMetadata.readStrict] and [KotlinClassMetadata.readLenient] for more details. 87 */ readKotlinClassMetadatanull88internal fun Metadata.readKotlinClassMetadata(lenient: Boolean): KotlinClassMetadata { 89 return if (lenient) { 90 KotlinClassMetadata.readLenient(this) 91 } else { 92 KotlinClassMetadata.readStrict(this) 93 } 94 } 95 readMetadatanull96private 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