1 /* 2 * Copyright (C) 2017 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 package com.squareup.kotlinpoet 17 18 import com.squareup.kotlinpoet.KModifier.ACTUAL 19 import com.squareup.kotlinpoet.KModifier.INTERNAL 20 import com.squareup.kotlinpoet.KModifier.PRIVATE 21 import com.squareup.kotlinpoet.KModifier.PUBLIC 22 import java.lang.reflect.Type 23 import kotlin.reflect.KClass 24 25 /** A generated typealias declaration */ 26 public class TypeAliasSpec private constructor( 27 builder: Builder, 28 private val tagMap: TagMap = builder.buildTagMap(), 29 ) : Taggable by tagMap, Annotatable, Documentable { 30 public val name: String = builder.name 31 public val type: TypeName = builder.type 32 public val modifiers: Set<KModifier> = builder.modifiers.toImmutableSet() 33 public val typeVariables: List<TypeVariableName> = builder.typeVariables.toImmutableList() 34 override val kdoc: CodeBlock = builder.kdoc.build() 35 override val annotations: List<AnnotationSpec> = builder.annotations.toImmutableList() 36 emitnull37 internal fun emit(codeWriter: CodeWriter) { 38 codeWriter.emitKdoc(kdoc.ensureEndsWithNewLine()) 39 codeWriter.emitAnnotations(annotations, false) 40 codeWriter.emitModifiers(modifiers, setOf(PUBLIC)) 41 codeWriter.emitCode("typealias %N", name) 42 codeWriter.emitTypeVariables(typeVariables) 43 codeWriter.emitCode(" = %T", type) 44 codeWriter.emit("\n") 45 } 46 equalsnull47 override fun equals(other: Any?): Boolean { 48 if (this === other) return true 49 if (other == null) return false 50 if (javaClass != other.javaClass) return false 51 return toString() == other.toString() 52 } 53 hashCodenull54 override fun hashCode(): Int = toString().hashCode() 55 56 override fun toString(): String = buildCodeString { emit(this) } 57 58 @JvmOverloads toBuildernull59 public fun toBuilder(name: String = this.name, type: TypeName = this.type): Builder { 60 val builder = Builder(name, type) 61 builder.modifiers += modifiers 62 builder.typeVariables += typeVariables 63 builder.kdoc.add(kdoc) 64 builder.annotations += annotations 65 builder.tags += tagMap.tags 66 return builder 67 } 68 69 public class Builder internal constructor( 70 internal val name: String, 71 internal val type: TypeName, 72 ) : Taggable.Builder<Builder>, Annotatable.Builder<Builder>, Documentable.Builder<Builder> { 73 public val modifiers: MutableSet<KModifier> = mutableSetOf() 74 public val typeVariables: MutableSet<TypeVariableName> = mutableSetOf() 75 override val tags: MutableMap<KClass<*>, Any> = mutableMapOf() 76 override val kdoc: CodeBlock.Builder = CodeBlock.builder() 77 override val annotations: MutableList<AnnotationSpec> = mutableListOf() 78 <lambda>null79 public fun addModifiers(vararg modifiers: KModifier): Builder = apply { 80 modifiers.forEach(this::addModifier) 81 } 82 <lambda>null83 public fun addModifiers(modifiers: Iterable<KModifier>): Builder = apply { 84 modifiers.forEach(this::addModifier) 85 } 86 addModifiernull87 private fun addModifier(modifier: KModifier) { 88 this.modifiers.add(modifier) 89 } 90 <lambda>null91 public fun addTypeVariables(typeVariables: Iterable<TypeVariableName>): Builder = apply { 92 this.typeVariables += typeVariables 93 } 94 addTypeVariablenull95 public fun addTypeVariable(typeVariable: TypeVariableName): Builder = apply { 96 typeVariables += typeVariable 97 } 98 99 //region Overrides for binary compatibility 100 @Suppress("RedundantOverride") addAnnotationnull101 override fun addAnnotation(annotationSpec: AnnotationSpec): Builder = super.addAnnotation(annotationSpec) 102 103 @Suppress("RedundantOverride") 104 override fun addAnnotations(annotationSpecs: Iterable<AnnotationSpec>): Builder = 105 super.addAnnotations(annotationSpecs) 106 107 @Suppress("RedundantOverride") 108 override fun addAnnotation(annotation: ClassName): Builder = super.addAnnotation(annotation) 109 110 @DelicateKotlinPoetApi( 111 message = "Java reflection APIs don't give complete information on Kotlin types. Consider " + 112 "using the kotlinpoet-metadata APIs instead.", 113 ) 114 override fun addAnnotation(annotation: Class<*>): Builder = super.addAnnotation(annotation) 115 116 @Suppress("RedundantOverride") 117 override fun addAnnotation(annotation: KClass<*>): Builder = super.addAnnotation(annotation) 118 119 @Suppress("RedundantOverride") 120 override fun addKdoc(format: String, vararg args: Any): Builder = super.addKdoc(format, *args) 121 122 @Suppress("RedundantOverride") 123 override fun addKdoc(block: CodeBlock): Builder = super.addKdoc(block) 124 //endregion 125 126 public fun build(): TypeAliasSpec { 127 for (it in modifiers) { 128 require(it in ALLOWABLE_MODIFIERS) { 129 "unexpected typealias modifier $it" 130 } 131 } 132 return TypeAliasSpec(this) 133 } 134 135 private companion object { 136 private val ALLOWABLE_MODIFIERS = setOf(PUBLIC, INTERNAL, PRIVATE, ACTUAL) 137 } 138 } 139 140 public companion object { buildernull141 @JvmStatic public fun builder(name: String, type: TypeName): Builder = Builder(name, type) 142 143 @DelicateKotlinPoetApi( 144 message = "Java reflection APIs don't give complete information on Kotlin types. Consider " + 145 "using the kotlinpoet-metadata APIs instead.", 146 ) 147 @JvmStatic 148 public fun builder(name: String, type: Type): Builder = 149 builder(name, type.asTypeName()) 150 151 @JvmStatic public fun builder(name: String, type: KClass<*>): Builder = 152 builder(name, type.asTypeName()) 153 } 154 } 155