xref: /aosp_15_r20/external/kotlinpoet/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/TypeName.kt (revision 3c321d951dd070fb96f8ba59e952ffc3131379a0)
1 /*
2  * Copyright (C) 2015 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("TypeNames")
17 
18 package com.squareup.kotlinpoet
19 
20 import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
21 import java.lang.reflect.GenericArrayType
22 import java.lang.reflect.ParameterizedType
23 import java.lang.reflect.Type
24 import java.lang.reflect.TypeVariable
25 import java.lang.reflect.WildcardType
26 import javax.lang.model.element.Modifier
27 import javax.lang.model.element.TypeElement
28 import javax.lang.model.element.TypeParameterElement
29 import javax.lang.model.type.ArrayType
30 import javax.lang.model.type.DeclaredType
31 import javax.lang.model.type.ErrorType
32 import javax.lang.model.type.NoType
33 import javax.lang.model.type.PrimitiveType
34 import javax.lang.model.type.TypeKind
35 import javax.lang.model.type.TypeMirror
36 import javax.lang.model.util.SimpleTypeVisitor8
37 import kotlin.reflect.KClass
38 import kotlin.reflect.typeOf
39 
40 /**
41  * Any type in Kotlin's type system. This class identifies simple types like `Int` and `String`,
42  * nullable types like `Int?`, composite types like `Array<String>` and `Set<String>`, and
43  * unassignable types like `Unit`.
44  *
45  * Type names are dumb identifiers only and do not model the values they name. For example, the
46  * type name for `kotlin.List` doesn't know about the `size()` function, the fact that lists are
47  * collections, or even that it accepts a single type parameter.
48  *
49  * Instances of this class are immutable value objects that implement `equals()` and `hashCode()`
50  * properly.
51  *
52  * Referencing existing types
53  * --------------------------
54  *
55  * In an annotation processor you can get a type name instance for a type mirror by calling
56  * [asTypeName]. In reflection code, you can use [asTypeName].
57 
58  * Defining new types
59  * ------------------
60  *
61  * Create new reference types like `com.example.HelloWorld` with [ClassName.bestGuess]. To build composite
62  * types like `Set<Long>`, use the factory methods on [ParameterizedTypeName], [TypeVariableName],
63  * and [WildcardTypeName].
64  */
65 public sealed class TypeName constructor(
66   public val isNullable: Boolean,
67   annotations: List<AnnotationSpec>,
68   internal val tagMap: TagMap,
69 ) : Taggable by tagMap, Annotatable {
70   override val annotations: List<AnnotationSpec> = annotations.toImmutableList()
71 
72   /** Lazily-initialized toString of this type name.  */
<lambda>null73   private val cachedString: String by lazy {
74     buildCodeString {
75       emitAnnotations(this)
76       emit(this)
77       if (isNullable) emit("?")
78     }
79   }
80 
copynull81   public fun copy(
82     nullable: Boolean = this.isNullable,
83     annotations: List<AnnotationSpec> = this.annotations.toList(),
84   ): TypeName {
85     return copy(nullable, annotations, this.tags)
86   }
87 
copynull88   public abstract fun copy(
89     nullable: Boolean = this.isNullable,
90     annotations: List<AnnotationSpec> = this.annotations.toList(),
91     tags: Map<KClass<*>, Any> = this.tags,
92   ): TypeName
93 
94   public val isAnnotated: Boolean get() = annotations.isNotEmpty()
95 
96   override fun equals(other: Any?): Boolean {
97     if (this === other) return true
98     if (javaClass != other?.javaClass) return false
99 
100     other as TypeName
101 
102     if (isNullable != other.isNullable) return false
103     if (annotations != other.annotations) return false
104     // do not check for equality of tags, these are considered side-channel data
105 
106     return true
107   }
108 
hashCodenull109   override fun hashCode(): Int {
110     var result = isNullable.hashCode()
111     result = 31 * result + annotations.hashCode()
112     return result
113   }
114 
toStringnull115   override fun toString(): String = cachedString
116 
117   internal abstract fun emit(out: CodeWriter): CodeWriter
118 
119   internal fun emitAnnotations(out: CodeWriter) {
120     for (annotation in annotations) {
121       annotation.emit(out, true)
122       out.emit(" ")
123     }
124   }
125 
emitNullablenull126   internal fun emitNullable(out: CodeWriter) {
127     if (isNullable) {
128       out.emit("?")
129     }
130   }
131 
132   public companion object {
getnull133     internal fun get(
134       mirror: TypeMirror,
135       typeVariables: Map<TypeParameterElement, TypeVariableName>,
136     ): TypeName {
137       return mirror.accept(
138         object : SimpleTypeVisitor8<TypeName, Void?>() {
139           override fun visitPrimitive(t: PrimitiveType, p: Void?): TypeName {
140             return when (t.kind) {
141               TypeKind.BOOLEAN -> BOOLEAN
142               TypeKind.BYTE -> BYTE
143               TypeKind.SHORT -> SHORT
144               TypeKind.INT -> INT
145               TypeKind.LONG -> LONG
146               TypeKind.CHAR -> CHAR
147               TypeKind.FLOAT -> FLOAT
148               TypeKind.DOUBLE -> DOUBLE
149               else -> throw AssertionError()
150             }
151           }
152 
153           override fun visitDeclared(t: DeclaredType, p: Void?): TypeName {
154             val rawType: ClassName = (t.asElement() as TypeElement).asClassName()
155             val enclosingType = t.enclosingType
156             val enclosing = if (enclosingType.kind != TypeKind.NONE &&
157               Modifier.STATIC !in t.asElement().modifiers
158             ) {
159               enclosingType.accept(this, null)
160             } else {
161               null
162             }
163             if (t.typeArguments.isEmpty() && enclosing !is ParameterizedTypeName) {
164               return rawType
165             }
166 
167             val typeArgumentNames = mutableListOf<TypeName>()
168             for (typeArgument in t.typeArguments) {
169               typeArgumentNames += get(typeArgument, typeVariables)
170             }
171             return if (enclosing is ParameterizedTypeName) {
172               enclosing.nestedClass(rawType.simpleName, typeArgumentNames)
173             } else {
174               ParameterizedTypeName(null, rawType, typeArgumentNames)
175             }
176           }
177 
178           override fun visitError(t: ErrorType, p: Void?): TypeName {
179             return visitDeclared(t, p)
180           }
181 
182           override fun visitArray(t: ArrayType, p: Void?): ParameterizedTypeName {
183             return ARRAY.parameterizedBy(get(t.componentType, typeVariables))
184           }
185 
186           override fun visitTypeVariable(
187             t: javax.lang.model.type.TypeVariable,
188             p: Void?,
189           ): TypeName {
190             return TypeVariableName.get(t, typeVariables.toMutableMap())
191           }
192 
193           override fun visitWildcard(t: javax.lang.model.type.WildcardType, p: Void?): TypeName {
194             return WildcardTypeName.get(t, typeVariables)
195           }
196 
197           override fun visitNoType(t: NoType, p: Void?): TypeName {
198             if (t.kind == TypeKind.VOID) return UNIT
199             return super.visitUnknown(t, p)
200           }
201 
202           override fun defaultAction(e: TypeMirror?, p: Void?): TypeName {
203             throw IllegalArgumentException("Unexpected type mirror: " + e!!)
204           }
205         },
206         null,
207       )
208     }
209 
getnull210     internal fun get(type: Type, map: MutableMap<Type, TypeVariableName>): TypeName {
211       return when (type) {
212         is Class<*> -> when {
213           type === Void.TYPE -> UNIT
214           type === Boolean::class.javaPrimitiveType -> BOOLEAN
215           type === Byte::class.javaPrimitiveType -> BYTE
216           type === Short::class.javaPrimitiveType -> SHORT
217           type === Int::class.javaPrimitiveType -> INT
218           type === Long::class.javaPrimitiveType -> LONG
219           type === Char::class.javaPrimitiveType -> CHAR
220           type === Float::class.javaPrimitiveType -> FLOAT
221           type === Double::class.javaPrimitiveType -> DOUBLE
222           type.isArray -> ARRAY.parameterizedBy(get(type.componentType, map))
223           else -> type.asClassName()
224         }
225         is ParameterizedType -> ParameterizedTypeName.get(type, map)
226         is WildcardType -> WildcardTypeName.get(type, map)
227         is TypeVariable<*> -> TypeVariableName.get(type, map)
228         is GenericArrayType -> ARRAY.parameterizedBy(get(type.genericComponentType, map))
229         else -> throw IllegalArgumentException("unexpected type: $type")
230       }
231     }
232   }
233 }
234 
235 @JvmField public val ANY: ClassName = ClassName("kotlin", "Any")
236 
237 @JvmField public val ARRAY: ClassName = ClassName("kotlin", "Array")
238 
239 @JvmField public val UNIT: ClassName = ClassName("kotlin", "Unit")
240 
241 @JvmField public val BOOLEAN: ClassName = ClassName("kotlin", "Boolean")
242 
243 @JvmField public val BYTE: ClassName = ClassName("kotlin", "Byte")
244 
245 @JvmField public val SHORT: ClassName = ClassName("kotlin", "Short")
246 
247 @JvmField public val INT: ClassName = ClassName("kotlin", "Int")
248 
249 @JvmField public val LONG: ClassName = ClassName("kotlin", "Long")
250 
251 @JvmField public val CHAR: ClassName = ClassName("kotlin", "Char")
252 
253 @JvmField public val FLOAT: ClassName = ClassName("kotlin", "Float")
254 
255 @JvmField public val DOUBLE: ClassName = ClassName("kotlin", "Double")
256 
257 @JvmField public val STRING: ClassName = ClassName("kotlin", "String")
258 
259 @JvmField public val CHAR_SEQUENCE: ClassName = ClassName("kotlin", "CharSequence")
260 
261 @JvmField public val COMPARABLE: ClassName = ClassName("kotlin", "Comparable")
262 
263 @JvmField public val THROWABLE: ClassName = ClassName("kotlin", "Throwable")
264 
265 @JvmField public val ANNOTATION: ClassName = ClassName("kotlin", "Annotation")
266 
267 @JvmField public val NOTHING: ClassName = ClassName("kotlin", "Nothing")
268 
269 @JvmField public val NUMBER: ClassName = ClassName("kotlin", "Number")
270 
271 @JvmField public val ITERABLE: ClassName = ClassName("kotlin.collections", "Iterable")
272 
273 @JvmField public val COLLECTION: ClassName = ClassName("kotlin.collections", "Collection")
274 
275 @JvmField public val LIST: ClassName = ClassName("kotlin.collections", "List")
276 
277 @JvmField public val SET: ClassName = ClassName("kotlin.collections", "Set")
278 
279 @JvmField public val MAP: ClassName = ClassName("kotlin.collections", "Map")
280 
281 @JvmField public val MAP_ENTRY: ClassName = MAP.nestedClass("Entry")
282 
283 @JvmField public val MUTABLE_ITERABLE: ClassName =
284   ClassName("kotlin.collections", "MutableIterable")
285 
286 @JvmField public val MUTABLE_COLLECTION: ClassName =
287   ClassName("kotlin.collections", "MutableCollection")
288 
289 @JvmField public val MUTABLE_LIST: ClassName = ClassName("kotlin.collections", "MutableList")
290 
291 @JvmField public val MUTABLE_SET: ClassName = ClassName("kotlin.collections", "MutableSet")
292 
293 @JvmField public val MUTABLE_MAP: ClassName = ClassName("kotlin.collections", "MutableMap")
294 
295 @JvmField public val MUTABLE_MAP_ENTRY: ClassName = MUTABLE_MAP.nestedClass("Entry")
296 
297 @JvmField public val BOOLEAN_ARRAY: ClassName = ClassName("kotlin", "BooleanArray")
298 
299 @JvmField public val BYTE_ARRAY: ClassName = ClassName("kotlin", "ByteArray")
300 
301 @JvmField public val CHAR_ARRAY: ClassName = ClassName("kotlin", "CharArray")
302 
303 @JvmField public val SHORT_ARRAY: ClassName = ClassName("kotlin", "ShortArray")
304 
305 @JvmField public val INT_ARRAY: ClassName = ClassName("kotlin", "IntArray")
306 
307 @JvmField public val LONG_ARRAY: ClassName = ClassName("kotlin", "LongArray")
308 
309 @JvmField public val FLOAT_ARRAY: ClassName = ClassName("kotlin", "FloatArray")
310 
311 @JvmField public val DOUBLE_ARRAY: ClassName = ClassName("kotlin", "DoubleArray")
312 
313 @JvmField public val ENUM: ClassName = ClassName("kotlin", "Enum")
314 
315 @JvmField public val U_BYTE: ClassName = ClassName("kotlin", "UByte")
316 
317 @JvmField public val U_SHORT: ClassName = ClassName("kotlin", "UShort")
318 
319 @JvmField public val U_INT: ClassName = ClassName("kotlin", "UInt")
320 
321 @JvmField public val U_LONG: ClassName = ClassName("kotlin", "ULong")
322 
323 @JvmField public val U_BYTE_ARRAY: ClassName = ClassName("kotlin", "UByteArray")
324 
325 @JvmField public val U_SHORT_ARRAY: ClassName = ClassName("kotlin", "UShortArray")
326 
327 @JvmField public val U_INT_ARRAY: ClassName = ClassName("kotlin", "UIntArray")
328 
329 @JvmField public val U_LONG_ARRAY: ClassName = ClassName("kotlin", "ULongArray")
330 
331 /** The wildcard type `*` which is shorthand for `out Any?`. */
332 @JvmField public val STAR: WildcardTypeName = WildcardTypeName.producerOf(ANY.copy(nullable = true))
333 
334 /** [Dynamic] is a singleton `object` type, so this is a shorthand for it in Java. */
335 @JvmField public val DYNAMIC: Dynamic = Dynamic
336 
337 /** Returns a [TypeName] equivalent to this [TypeMirror]. */
338 @DelicateKotlinPoetApi(
339   message = "Mirror APIs don't give complete information on Kotlin types. Consider using" +
340     " the kotlinpoet-metadata APIs instead.",
341 )
342 @JvmName("get")
asTypeNamenull343 public fun TypeMirror.asTypeName(): TypeName = TypeName.get(this, mutableMapOf())
344 
345 /** Returns a [TypeName] equivalent to this [KClass].  */
346 @JvmName("get")
347 public fun KClass<*>.asTypeName(): ClassName = asClassName()
348 
349 /** Returns a [TypeName] equivalent to this [Type].  */
350 @JvmName("get")
351 public fun Type.asTypeName(): TypeName = TypeName.get(this, mutableMapOf())
352 
353 /**
354  * Returns a [TypeName] equivalent of the reified type parameter [T] using reflection, maybe using kotlin-reflect
355  * if required.
356  */
357 public inline fun <reified T> typeNameOf(): TypeName = typeOf<T>().asTypeName()
358