| /* |
| * Copyright (C) 2015 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 |
| * |
| * http://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("TypeNames") |
| |
| package com.squareup.kotlinpoet |
| |
| import java.lang.reflect.GenericArrayType |
| import java.lang.reflect.ParameterizedType |
| import java.lang.reflect.Type |
| import java.lang.reflect.TypeVariable |
| import java.lang.reflect.WildcardType |
| import javax.lang.model.element.Modifier |
| import javax.lang.model.element.TypeElement |
| import javax.lang.model.element.TypeParameterElement |
| import javax.lang.model.type.ArrayType |
| import javax.lang.model.type.DeclaredType |
| import javax.lang.model.type.ErrorType |
| import javax.lang.model.type.NoType |
| import javax.lang.model.type.PrimitiveType |
| import javax.lang.model.type.TypeKind |
| import javax.lang.model.type.TypeMirror |
| import javax.lang.model.util.SimpleTypeVisitor7 |
| import kotlin.reflect.KClass |
| |
| /** |
| * Any type in Kotlin's type system. This class identifies simple types like `Int` and `String`, |
| * nullable types like `Int?`, composite types like `Array<String>` and `Set<String>`, and |
| * unassignable types like `Unit`. |
| * |
| * Type names are dumb identifiers only and do not model the values they name. For example, the |
| * type name for `kotlin.List` doesn't know about the `size()` function, the fact that lists are |
| * collections, or even that it accepts a single type parameter. |
| * |
| * Instances of this class are immutable value objects that implement `equals()` and `hashCode()` |
| * properly. |
| * |
| * Referencing existing types |
| * -------------------------- |
| * |
| * In an annotation processor you can get a type name instance for a type mirror by calling |
| * [asTypeName]. In reflection code, you can use [asTypeName]. |
| |
| * Defining new types |
| * ------------------ |
| * |
| * Create new reference types like `com.example.HelloWorld` with [ClassName.bestGuess]. To build composite |
| * types like `Set<Long>`, use the factory methods on [ParameterizedTypeName], [TypeVariableName], |
| * and [WildcardTypeName]. |
| */ |
| abstract class TypeName internal constructor( |
| val nullable: Boolean, annotations: List<AnnotationSpec> |
| ) { |
| val annotations = annotations.toImmutableList() |
| |
| /** Lazily-initialized toString of this type name. */ |
| private val cachedString: String by lazy { |
| buildString { |
| val codeWriter = CodeWriter(this) |
| emitAnnotations(codeWriter) |
| emit(codeWriter) |
| if (nullable) append("?") |
| } |
| } |
| |
| fun annotated(vararg annotations: AnnotationSpec) = annotated(annotations.toList()) |
| |
| abstract fun asNullable(): TypeName |
| |
| abstract fun asNonNullable(): TypeName |
| |
| abstract fun annotated(annotations: List<AnnotationSpec>): TypeName |
| |
| abstract fun withoutAnnotations(): TypeName |
| |
| val isAnnotated get() = annotations.isNotEmpty() |
| |
| override fun equals(other: Any?): Boolean { |
| if (this === other) return true |
| if (other == null) return false |
| if (javaClass != other.javaClass) return false |
| return toString() == other.toString() |
| } |
| |
| override fun hashCode() = toString().hashCode() |
| |
| override fun toString() = cachedString |
| |
| internal abstract fun emit(out: CodeWriter): CodeWriter |
| |
| internal fun emitAnnotations(out: CodeWriter) { |
| for (annotation in annotations) { |
| annotation.emit(out, true) |
| out.emit(" ") |
| } |
| } |
| |
| internal fun emitNullable(out: CodeWriter) { |
| if (nullable) { |
| out.emit("?") |
| } |
| } |
| |
| companion object { |
| internal fun get( |
| mirror: TypeMirror, |
| typeVariables: MutableMap<TypeParameterElement, TypeVariableName> |
| ): TypeName { |
| return mirror.accept(object : SimpleTypeVisitor7<TypeName, Void?>() { |
| override fun visitPrimitive(t: PrimitiveType, p: Void?): TypeName { |
| return when (t.kind) { |
| TypeKind.BOOLEAN -> BOOLEAN |
| TypeKind.BYTE -> BYTE |
| TypeKind.SHORT -> SHORT |
| TypeKind.INT -> INT |
| TypeKind.LONG -> LONG |
| TypeKind.CHAR -> CHAR |
| TypeKind.FLOAT -> FLOAT |
| TypeKind.DOUBLE -> DOUBLE |
| else -> throw AssertionError() |
| } |
| } |
| |
| override fun visitDeclared(t: DeclaredType, p: Void?): TypeName { |
| val rawType: ClassName = (t.asElement() as TypeElement).asClassName() |
| val enclosingType = t.enclosingType |
| val enclosing = if (enclosingType.kind != TypeKind.NONE |
| && !t.asElement().modifiers.contains(Modifier.STATIC)) |
| enclosingType.accept(this, null) else |
| null |
| if (t.typeArguments.isEmpty() && enclosing !is ParameterizedTypeName) { |
| return rawType |
| } |
| |
| val typeArgumentNames = mutableListOf<TypeName>() |
| for (typeArgument in t.typeArguments) { |
| typeArgumentNames += get(typeArgument, typeVariables) |
| } |
| return if (enclosing is ParameterizedTypeName) |
| enclosing.nestedClass(rawType.simpleName(), typeArgumentNames) else |
| ParameterizedTypeName(null, rawType, typeArgumentNames) |
| } |
| |
| override fun visitError(t: ErrorType, p: Void?): TypeName { |
| return visitDeclared(t, p) |
| } |
| |
| override fun visitArray(t: ArrayType, p: Void?): ParameterizedTypeName { |
| return ParameterizedTypeName.get(ARRAY, TypeName.get(t.componentType, typeVariables)) |
| } |
| |
| override fun visitTypeVariable(t: javax.lang.model.type.TypeVariable, p: Void?): TypeName { |
| return TypeVariableName.get(t, typeVariables.toMutableMap()) |
| } |
| |
| override fun visitWildcard(t: javax.lang.model.type.WildcardType, p: Void?): TypeName { |
| return WildcardTypeName.get(t, typeVariables) |
| } |
| |
| override fun visitNoType(t: NoType, p: Void?): TypeName { |
| if (t.kind == TypeKind.VOID) return UNIT |
| return super.visitUnknown(t, p) |
| } |
| |
| override fun defaultAction(e: TypeMirror?, p: Void?): TypeName { |
| throw IllegalArgumentException("Unexpected type mirror: " + e!!) |
| } |
| }, null) |
| } |
| |
| internal fun get(type: Type, map: MutableMap<Type, TypeVariableName>): TypeName { |
| return when (type) { |
| is Class<*> -> when { |
| type === Void.TYPE -> UNIT |
| type === Boolean::class.javaPrimitiveType -> BOOLEAN |
| type === Byte::class.javaPrimitiveType -> BYTE |
| type === Short::class.javaPrimitiveType -> SHORT |
| type === Int::class.javaPrimitiveType -> INT |
| type === Long::class.javaPrimitiveType -> LONG |
| type === Char::class.javaPrimitiveType -> CHAR |
| type === Float::class.javaPrimitiveType -> FLOAT |
| type === Double::class.javaPrimitiveType -> DOUBLE |
| type.isArray -> ParameterizedTypeName.get(ARRAY, get(type.componentType, map)) |
| else -> type.asClassName() |
| } |
| is ParameterizedType -> ParameterizedTypeName.get(type, map) |
| is WildcardType -> WildcardTypeName.get(type, map) |
| is TypeVariable<*> -> TypeVariableName.get(type, map) |
| is GenericArrayType -> ParameterizedTypeName.get(ARRAY, get(type.genericComponentType, map)) |
| else -> throw IllegalArgumentException("unexpected type: " + type) |
| } |
| } |
| } |
| } |
| |
| @JvmField val ANY = ClassName("kotlin", "Any") |
| @JvmField val ARRAY = ClassName("kotlin", "Array") |
| @JvmField val UNIT = Unit::class.asClassName() |
| @JvmField val BOOLEAN = ClassName("kotlin", "Boolean") |
| @JvmField val BYTE = ClassName("kotlin", "Byte") |
| @JvmField val SHORT = ClassName("kotlin", "Short") |
| @JvmField val INT = ClassName("kotlin", "Int") |
| @JvmField val LONG = ClassName("kotlin", "Long") |
| @JvmField val CHAR = ClassName("kotlin", "Char") |
| @JvmField val FLOAT = ClassName("kotlin", "Float") |
| @JvmField val DOUBLE = ClassName("kotlin", "Double") |
| |
| @JvmField val DYNAMIC = object : TypeName(false, emptyList()) { |
| |
| override fun asNullable() = |
| throw UnsupportedOperationException("dynamic can't be nullable") |
| |
| override fun asNonNullable() = |
| throw UnsupportedOperationException("dynamic can't be non-nullable") |
| |
| override fun annotated(annotations: List<AnnotationSpec>) = |
| throw UnsupportedOperationException("dynamic can't have annotations") |
| |
| override fun withoutAnnotations() = |
| throw UnsupportedOperationException("dynamic can't have annotations") |
| |
| override fun emit(out: CodeWriter) = out.apply { |
| emit("dynamic") |
| } |
| } |
| |
| /** Returns a [TypeName] equivalent to this [TypeMirror]. */ |
| @JvmName("get") |
| fun TypeMirror.asTypeName() = TypeName.get(this, mutableMapOf()) |
| |
| /** Returns a [TypeName] equivalent to this [KClass]. */ |
| @JvmName("get") |
| fun KClass<*>.asTypeName() = asClassName() |
| |
| /** Returns a [TypeName] equivalent to this [Type]. */ |
| @JvmName("get") |
| fun Type.asTypeName() = TypeName.get(this, mutableMapOf()) |