xref: /aosp_15_r20/external/kotlinpoet/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/TypeSpec.kt (revision 3c321d951dd070fb96f8ba59e952ffc3131379a0)
1 /*
<lambda>null2  * 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 package com.squareup.kotlinpoet
17 
18 import com.squareup.kotlinpoet.KModifier.ABSTRACT
19 import com.squareup.kotlinpoet.KModifier.ANNOTATION
20 import com.squareup.kotlinpoet.KModifier.COMPANION
21 import com.squareup.kotlinpoet.KModifier.ENUM
22 import com.squareup.kotlinpoet.KModifier.EXPECT
23 import com.squareup.kotlinpoet.KModifier.EXTERNAL
24 import com.squareup.kotlinpoet.KModifier.FUN
25 import com.squareup.kotlinpoet.KModifier.INLINE
26 import com.squareup.kotlinpoet.KModifier.INTERNAL
27 import com.squareup.kotlinpoet.KModifier.PRIVATE
28 import com.squareup.kotlinpoet.KModifier.PROTECTED
29 import com.squareup.kotlinpoet.KModifier.PUBLIC
30 import com.squareup.kotlinpoet.KModifier.SEALED
31 import com.squareup.kotlinpoet.KModifier.VALUE
32 import java.lang.reflect.Type
33 import javax.lang.model.element.Element
34 import kotlin.DeprecationLevel.ERROR
35 import kotlin.reflect.KClass
36 
37 /** A generated class, interface, or enum declaration. */
38 @OptIn(ExperimentalKotlinPoetApi::class)
39 public class TypeSpec private constructor(
40   builder: Builder,
41   private val tagMap: TagMap = builder.buildTagMap(),
42   private val delegateOriginatingElements: OriginatingElementsHolder = builder.originatingElements
43     .plus(builder.typeSpecs.flatMap(TypeSpec::originatingElements))
44     .buildOriginatingElements(),
45   private val contextReceivers: ContextReceivers = builder.buildContextReceivers(),
46 ) : Taggable by tagMap,
47   OriginatingElementsHolder by delegateOriginatingElements,
48   ContextReceivable by contextReceivers,
49   Annotatable,
50   Documentable,
51   TypeSpecHolder,
52   MemberSpecHolder {
53   public val kind: Kind = builder.kind
54   public val name: String? = builder.name
55   override val kdoc: CodeBlock = builder.kdoc.build()
56   override val annotations: List<AnnotationSpec> = builder.annotations.toImmutableList()
57   public val modifiers: Set<KModifier> = builder.modifiers.toImmutableSet()
58   public val typeVariables: List<TypeVariableName> = builder.typeVariables.toImmutableList()
59   public val primaryConstructor: FunSpec? = builder.primaryConstructor
60   public val superclass: TypeName = builder.superclass
61   public val superclassConstructorParameters: List<CodeBlock> =
62     builder.superclassConstructorParameters.toImmutableList()
63 
64   public val isEnum: Boolean = builder.isEnum
65   public val isAnnotation: Boolean = builder.isAnnotation
66   public val isCompanion: Boolean = builder.isCompanion
67   public val isAnonymousClass: Boolean = builder.isAnonymousClass
68   public val isFunctionalInterface: Boolean = builder.isFunInterface
69 
70   /**
71    * Map of superinterfaces - entries with a null value represent a regular superinterface (with
72    * no delegation), while non-null [CodeBlock] values represent delegates
73    * for the corresponding [TypeSpec] interface (key) value
74    */
75   public val superinterfaces: Map<TypeName, CodeBlock?> = builder.superinterfaces.toImmutableMap()
76   public val enumConstants: Map<String, TypeSpec> = builder.enumConstants.toImmutableMap()
77   override val propertySpecs: List<PropertySpec> = builder.propertySpecs.toImmutableList()
78   public val initializerBlock: CodeBlock = builder.initializerBlock.build()
79   public val initializerIndex: Int = builder.initializerIndex
80   override val funSpecs: List<FunSpec> = builder.funSpecs.toImmutableList()
81   public override val typeSpecs: List<TypeSpec> = builder.typeSpecs.toImmutableList()
82   internal val nestedTypesSimpleNames = typeSpecs.map { it.name }.toImmutableSet()
83 
84   @Deprecated("Use annotations property", ReplaceWith("annotations"), ERROR)
85   public val annotationSpecs: List<AnnotationSpec> get() = annotations
86 
87   @JvmOverloads
88   public fun toBuilder(kind: Kind = this.kind, name: String? = this.name): Builder {
89     val builder = Builder(kind, name)
90     builder.modifiers += modifiers
91     builder.kdoc.add(kdoc)
92     builder.annotations += annotations
93     builder.typeVariables += typeVariables
94     builder.superclass = superclass
95     builder.superclassConstructorParameters += superclassConstructorParameters
96     builder.enumConstants += enumConstants
97     builder.propertySpecs += propertySpecs
98     builder.funSpecs += funSpecs
99     builder.typeSpecs += typeSpecs
100     builder.initializerBlock.add(initializerBlock)
101     builder.initializerIndex = initializerIndex
102     builder.superinterfaces.putAll(superinterfaces)
103     builder.primaryConstructor = primaryConstructor
104     builder.tags += tagMap.tags
105     builder.originatingElements += originatingElements
106     builder.contextReceiverTypes += contextReceiverTypes
107     return builder
108   }
109 
110   internal fun emit(
111     codeWriter: CodeWriter,
112     enumName: String?,
113     implicitModifiers: Set<KModifier> = emptySet(),
114     isNestedExternal: Boolean = false,
115   ) {
116     // Types.
117     val areNestedExternal = EXTERNAL in modifiers || isNestedExternal
118 
119     // Nested classes interrupt wrapped line indentation. Stash the current wrapping state and put
120     // it back afterwards when this type is complete.
121     val previousStatementLine = codeWriter.statementLine
122     codeWriter.statementLine = -1
123 
124     val constructorProperties: Map<String, PropertySpec> = constructorProperties()
125     val superclassConstructorParametersBlock = superclassConstructorParameters.joinToCode()
126 
127     try {
128       if (enumName != null) {
129         codeWriter.emitKdoc(kdocWithConstructorDocs())
130         codeWriter.emitAnnotations(annotations, false)
131         codeWriter.emitCode("%N", enumName)
132         if (superclassConstructorParametersBlock.isNotEmpty()) {
133           codeWriter.emit("(")
134           codeWriter.emitCode(superclassConstructorParametersBlock)
135           codeWriter.emit(")")
136         }
137         if (hasNoBody) {
138           return // Avoid unnecessary braces "{}".
139         }
140         codeWriter.emit(" {\n")
141       } else if (isAnonymousClass) {
142         codeWriter.emitCode("object")
143         val supertype = if (superclass != ANY) {
144           if (!areNestedExternal && !modifiers.contains(EXPECT)) {
145             listOf(CodeBlock.of(" %T(%L)", superclass, superclassConstructorParametersBlock))
146           } else {
147             listOf(CodeBlock.of(" %T", superclass))
148           }
149         } else {
150           listOf()
151         }
152 
153         val allSuperTypes = supertype + if (superinterfaces.isNotEmpty()) {
154           superinterfaces.keys.map { CodeBlock.of(" %T", it) }
155         } else {
156           emptyList()
157         }
158 
159         if (allSuperTypes.isNotEmpty()) {
160           codeWriter.emitCode(" :")
161           codeWriter.emitCode(allSuperTypes.joinToCode(","))
162         }
163         if (hasNoBody) {
164           codeWriter.emit(" {\n}")
165           return
166         }
167         codeWriter.emit(" {\n")
168       } else {
169         codeWriter.emitKdoc(kdocWithConstructorDocs())
170         codeWriter.emitContextReceivers(contextReceiverTypes, suffix = "\n")
171         codeWriter.emitAnnotations(annotations, false)
172         codeWriter.emitModifiers(
173           modifiers,
174           if (isNestedExternal) setOf(PUBLIC, EXTERNAL) else setOf(PUBLIC),
175         )
176         codeWriter.emit(kind.declarationKeyword)
177         if (name != null) {
178           codeWriter.emitCode(" %N", this)
179         }
180         codeWriter.emitTypeVariables(typeVariables)
181 
182         var wrapSupertypes = false
183         primaryConstructor?.let {
184           codeWriter.pushType(this) // avoid name collisions when emitting primary constructor
185           val emittedAnnotations = it.annotations.isNotEmpty()
186           val useKeyword = it.annotations.isNotEmpty() || it.modifiers.isNotEmpty()
187 
188           if (it.annotations.isNotEmpty()) {
189             codeWriter.emit(" ")
190             codeWriter.emitAnnotations(it.annotations, true)
191           }
192 
193           if (it.modifiers.isNotEmpty()) {
194             if (!emittedAnnotations) codeWriter.emit(" ")
195             codeWriter.emitModifiers(it.modifiers)
196           }
197 
198           if (useKeyword) {
199             codeWriter.emit("constructor")
200           }
201 
202           it.parameters.emit(codeWriter, forceNewLines = true) { param ->
203             wrapSupertypes = true
204 
205             val property = constructorProperties[param.name]
206             if (property != null) {
207               property.emit(
208                 codeWriter,
209                 setOf(PUBLIC),
210                 withInitializer = false,
211                 inline = true,
212                 inlineAnnotations = false,
213               )
214               param.emitDefaultValue(codeWriter)
215             } else {
216               param.emit(codeWriter, inlineAnnotations = false)
217             }
218           }
219 
220           codeWriter.popType()
221         }
222 
223         val types = listOf(superclass).filter { it != ANY }.map {
224           if (primaryConstructor != null || funSpecs.none(FunSpec::isConstructor)) {
225             if (!areNestedExternal && !modifiers.contains(EXPECT)) {
226               CodeBlock.of("%T(%L)", it, superclassConstructorParametersBlock)
227             } else {
228               CodeBlock.of("%T", it)
229             }
230           } else {
231             CodeBlock.of("%T", it)
232           }
233         }
234         val superTypes = types + superinterfaces.entries.map { (type, init) ->
235           if (init == null) CodeBlock.of("%T", type) else CodeBlock.of("%T by %L", type, init)
236         }
237 
238         if (superTypes.isNotEmpty()) {
239           val separator = if (wrapSupertypes) ",\n    " else ", "
240           codeWriter.emitCode(superTypes.joinToCode(separator = separator, prefix = " : "))
241         }
242 
243         codeWriter.emitWhereBlock(typeVariables)
244 
245         if (hasNoBody) {
246           codeWriter.emit("\n")
247           return // Avoid unnecessary braces "{}".
248         }
249         codeWriter.emit(" {\n")
250       }
251 
252       codeWriter.pushType(this)
253       codeWriter.indent()
254       var firstMember = true
255       for ((key, value) in enumConstants.entries) {
256         if (!firstMember) codeWriter.emit("\n")
257         value.emit(codeWriter, key)
258         codeWriter.emit(",")
259         firstMember = false
260       }
261       if (isEnum) {
262         if (!firstMember) {
263           codeWriter.emit("\n")
264         }
265         if (propertySpecs.isNotEmpty() || funSpecs.isNotEmpty() || typeSpecs.isNotEmpty()) {
266           codeWriter.emit(";\n")
267         }
268       }
269 
270       val cachedHasInitializer = hasInitializer
271       var initializerEmitted = false
272       fun possiblyEmitInitializer() {
273         if (initializerEmitted) return
274         initializerEmitted = true
275         if (cachedHasInitializer) {
276           if (!firstMember) codeWriter.emit("\n")
277           codeWriter.emitCode(initializerBlock)
278           firstMember = false
279         }
280       }
281 
282       // Properties and initializer block.
283       for ((index, propertySpec) in propertySpecs.withIndex()) {
284         // Initializer block.
285         if (index == initializerIndex) {
286           possiblyEmitInitializer()
287         }
288         if (constructorProperties.containsKey(propertySpec.name)) {
289           continue
290         }
291         if (!firstMember) codeWriter.emit("\n")
292         propertySpec.emit(codeWriter, kind.implicitPropertyModifiers(modifiers))
293         firstMember = false
294       }
295 
296       // One last try in case the initializer index is after all properties
297       possiblyEmitInitializer()
298 
299       if (primaryConstructor != null && primaryConstructor.body.isNotEmpty()) {
300         codeWriter.emit("init {\n")
301         codeWriter.indent()
302         codeWriter.emitCode(primaryConstructor.body)
303         codeWriter.unindent()
304         codeWriter.emit("}\n")
305       }
306 
307       // Constructors.
308       for (funSpec in funSpecs) {
309         if (!funSpec.isConstructor) continue
310         if (!firstMember) codeWriter.emit("\n")
311         funSpec.emit(codeWriter, name, kind.implicitFunctionModifiers(modifiers + implicitModifiers), false)
312         firstMember = false
313       }
314 
315       // Functions.
316       for (funSpec in funSpecs) {
317         if (funSpec.isConstructor) continue
318         if (!firstMember) codeWriter.emit("\n")
319         funSpec.emit(codeWriter, name, kind.implicitFunctionModifiers(modifiers + implicitModifiers), true)
320         firstMember = false
321       }
322 
323       for (typeSpec in typeSpecs) {
324         if (!firstMember) codeWriter.emit("\n")
325         typeSpec.emit(codeWriter, null, kind.implicitTypeModifiers(modifiers + implicitModifiers), isNestedExternal = areNestedExternal)
326         firstMember = false
327       }
328 
329       codeWriter.unindent()
330       codeWriter.popType()
331 
332       codeWriter.emit("}")
333       if (enumName == null && !isAnonymousClass) {
334         codeWriter.emit("\n") // If this type isn't also a value, include a trailing newline.
335       }
336     } finally {
337       codeWriter.statementLine = previousStatementLine
338     }
339   }
340 
341   /** Returns the properties that can be declared inline as constructor parameters. */
342   private fun constructorProperties(): Map<String, PropertySpec> {
343     if (primaryConstructor == null) return emptyMap()
344 
345     // Properties added after the initializer are not permitted to be inlined into the constructor
346     // due to ordering concerns.
347     val range = if (hasInitializer) {
348       0..<initializerIndex
349     } else {
350       propertySpecs.indices
351     }
352     val result: MutableMap<String, PropertySpec> = LinkedHashMap()
353     for (propertyIndex in range) {
354       val property = propertySpecs[propertyIndex]
355       if (property.getter != null || property.setter != null) continue
356       val parameter = primaryConstructor.parameter(property.name) ?: continue
357       if (parameter.type != property.type) continue
358       if (!isPropertyInitializerConstructorParameter(property, parameter)) {
359         continue
360       }
361 
362       result[property.name] = property.fromPrimaryConstructorParameter(parameter)
363     }
364     return result
365   }
366 
367   /**
368    * Returns true if the property can be declared inline as a constructor parameter
369    */
370   private fun isPropertyInitializerConstructorParameter(
371     property: PropertySpec,
372     parameter: ParameterSpec,
373   ): Boolean {
374     val parameterName = CodeBlock.of("%N", parameter).toString()
375     val initializerCode = property.initializer.toString().escapeIfNecessary(validate = false)
376     return parameterName == initializerCode
377   }
378 
379   /**
380    * Returns KDoc comments including those of the primary constructor and its parameters.
381    *
382    * Parameters' KDocs, if present, will always be printed in the type header.
383    */
384   private fun kdocWithConstructorDocs(): CodeBlock {
385     val classKdoc = kdoc.ensureEndsWithNewLine()
386     val constructorKdoc = buildCodeBlock {
387       if (primaryConstructor != null) {
388         if (primaryConstructor.kdoc.isNotEmpty()) {
389           add("@constructor %L", primaryConstructor.kdoc.ensureEndsWithNewLine())
390         }
391         primaryConstructor.parameters.forEach { parameter ->
392           if (parameter.kdoc.isNotEmpty()) {
393             add("@param %L %L", parameter.name, parameter.kdoc.ensureEndsWithNewLine())
394           }
395         }
396       }
397     }
398     return listOf(classKdoc, constructorKdoc)
399       .filter(CodeBlock::isNotEmpty)
400       .joinToCode(separator = "\n")
401   }
402 
403   private val hasInitializer: Boolean get() = initializerIndex != -1 && initializerBlock.isNotEmpty()
404 
405   private val hasNoBody: Boolean
406     get() {
407       if (propertySpecs.isNotEmpty()) {
408         val constructorProperties = constructorProperties()
409         for (propertySpec in propertySpecs) {
410           if (!constructorProperties.containsKey(propertySpec.name)) {
411             return false
412           }
413         }
414       }
415       return enumConstants.isEmpty() &&
416         initializerBlock.isEmpty() &&
417         (primaryConstructor?.body?.isEmpty() ?: true) &&
418         funSpecs.isEmpty() &&
419         typeSpecs.isEmpty()
420     }
421 
422   override fun equals(other: Any?): Boolean {
423     if (this === other) return true
424     if (other == null) return false
425     if (javaClass != other.javaClass) return false
426     return toString() == other.toString()
427   }
428 
429   override fun hashCode(): Int = toString().hashCode()
430 
431   override fun toString(): String = buildCodeString { emit(this, null) }
432 
433   public enum class Kind(
434     internal val declarationKeyword: String,
435     internal val defaultImplicitPropertyModifiers: Set<KModifier>,
436     internal val defaultImplicitFunctionModifiers: Set<KModifier>,
437     internal val defaultImplicitTypeModifiers: Set<KModifier>,
438   ) {
439     CLASS("class", setOf(PUBLIC), setOf(PUBLIC), setOf()),
440     OBJECT("object", setOf(PUBLIC), setOf(PUBLIC), setOf()),
441     INTERFACE("interface", setOf(PUBLIC, ABSTRACT), setOf(PUBLIC, ABSTRACT), setOf()),
442     ;
443 
444     internal fun implicitPropertyModifiers(modifiers: Set<KModifier>): Set<KModifier> {
445       return defaultImplicitPropertyModifiers + when {
446         ANNOTATION in modifiers -> emptySet()
447         EXPECT in modifiers -> setOf(EXPECT)
448         EXTERNAL in modifiers -> setOf(EXTERNAL)
449         else -> emptySet()
450       }
451     }
452 
453     internal fun implicitFunctionModifiers(modifiers: Set<KModifier> = setOf()): Set<KModifier> {
454       return defaultImplicitFunctionModifiers + when {
455         EXPECT in modifiers -> setOf(EXPECT)
456         EXTERNAL in modifiers -> setOf(EXTERNAL)
457         else -> emptySet()
458       }
459     }
460 
461     internal fun implicitTypeModifiers(modifiers: Set<KModifier> = setOf()): Set<KModifier> {
462       return defaultImplicitTypeModifiers + when {
463         EXPECT in modifiers -> setOf(EXPECT)
464         EXTERNAL in modifiers -> setOf(EXTERNAL)
465         else -> emptySet()
466       }
467     }
468   }
469 
470   public class Builder internal constructor(
471     internal var kind: Kind,
472     internal val name: String?,
473     vararg modifiers: KModifier,
474   ) : Taggable.Builder<Builder>,
475     OriginatingElementsHolder.Builder<Builder>,
476     ContextReceivable.Builder<Builder>,
477     Annotatable.Builder<Builder>,
478     Documentable.Builder<Builder>,
479     TypeSpecHolder.Builder<Builder>,
480     MemberSpecHolder.Builder<Builder> {
481     internal var primaryConstructor: FunSpec? = null
482     internal var superclass: TypeName = ANY
483     internal val initializerBlock = CodeBlock.builder()
484     public var initializerIndex: Int = -1
485     internal val isAnonymousClass get() = name == null && kind == Kind.CLASS
486     internal val isExternal get() = EXTERNAL in modifiers
487     internal val isEnum get() = kind == Kind.CLASS && ENUM in modifiers
488     internal val isAnnotation get() = kind == Kind.CLASS && ANNOTATION in modifiers
489     internal val isCompanion get() = kind == Kind.OBJECT && COMPANION in modifiers
490     internal val isInlineOrValClass get() = kind == Kind.CLASS &&
491       (INLINE in modifiers || VALUE in modifiers)
492     internal val isSimpleClass get() = kind == Kind.CLASS && !isEnum && !isAnnotation
493     internal val isFunInterface get() = kind == Kind.INTERFACE && FUN in modifiers
494 
495     override val tags: MutableMap<KClass<*>, Any> = mutableMapOf()
496     override val kdoc: CodeBlock.Builder = CodeBlock.builder()
497     override val originatingElements: MutableList<Element> = mutableListOf()
498     override val annotations: MutableList<AnnotationSpec> = mutableListOf()
499 
500     @ExperimentalKotlinPoetApi
501     override val contextReceiverTypes: MutableList<TypeName> = mutableListOf()
502     public val modifiers: MutableSet<KModifier> = mutableSetOf(*modifiers)
503     public val superinterfaces: MutableMap<TypeName, CodeBlock?> = mutableMapOf()
504     public val enumConstants: MutableMap<String, TypeSpec> = mutableMapOf()
505     public val typeVariables: MutableList<TypeVariableName> = mutableListOf()
506     public val superclassConstructorParameters: MutableList<CodeBlock> = mutableListOf()
507     public val propertySpecs: MutableList<PropertySpec> = mutableListOf()
508     public val funSpecs: MutableList<FunSpec> = mutableListOf()
509     public val typeSpecs: MutableList<TypeSpec> = mutableListOf()
510 
511     @Deprecated("Use annotations property", ReplaceWith("annotations"), ERROR)
512     public val annotationSpecs: MutableList<AnnotationSpec> get() = annotations
513 
514     public fun addModifiers(vararg modifiers: KModifier): Builder = apply {
515       check(!isAnonymousClass) { "forbidden on anonymous types." }
516       this.modifiers += modifiers
517     }
518 
519     public fun addModifiers(modifiers: Iterable<KModifier>): Builder = apply {
520       check(!isAnonymousClass) { "forbidden on anonymous types." }
521       this.modifiers += modifiers
522     }
523 
524     public fun addTypeVariables(typeVariables: Iterable<TypeVariableName>): Builder = apply {
525       this.typeVariables += typeVariables
526     }
527 
528     public fun addTypeVariable(typeVariable: TypeVariableName): Builder = apply {
529       typeVariables += typeVariable
530     }
531 
532     public fun primaryConstructor(primaryConstructor: FunSpec?): Builder = apply {
533       check(kind == Kind.CLASS) {
534         "$kind can't have a primary constructor"
535       }
536       if (primaryConstructor != null) {
537         require(primaryConstructor.isConstructor) {
538           "expected a constructor but was ${primaryConstructor.name}"
539         }
540 
541         if (isInlineOrValClass) {
542           check(primaryConstructor.parameters.size == 1) {
543             "value/inline classes must have 1 parameter in constructor"
544           }
545         }
546 
547         require(
548           primaryConstructor.delegateConstructor == null &&
549             primaryConstructor.delegateConstructorArguments.isEmpty(),
550         ) {
551           "primary constructor can't delegate to other constructors"
552         }
553       }
554       this.primaryConstructor = primaryConstructor
555     }
556 
557     public fun superclass(superclass: TypeName): Builder = apply {
558       checkCanHaveSuperclass()
559       check(this.superclass === ANY) { "superclass already set to ${this.superclass}" }
560       this.superclass = superclass
561     }
562 
563     private fun checkCanHaveSuperclass() {
564       check(isSimpleClass || kind == Kind.OBJECT) {
565         "only classes can have super classes, not $kind"
566       }
567       check(!isInlineOrValClass) {
568         "value/inline classes cannot have super classes"
569       }
570     }
571 
572     private fun checkCanHaveInitializerBlocks() {
573       check(isSimpleClass || isEnum || kind == Kind.OBJECT) {
574         "$kind can't have initializer blocks"
575       }
576       check(EXPECT !in modifiers) {
577         "expect $kind can't have initializer blocks"
578       }
579     }
580 
581     @DelicateKotlinPoetApi(
582       message = "Java reflection APIs don't give complete information on Kotlin types. Consider " +
583         "using the kotlinpoet-metadata APIs instead.",
584     )
585     public fun superclass(superclass: Type): Builder = superclass(superclass.asTypeName())
586 
587     public fun superclass(superclass: KClass<*>): Builder = superclass(superclass.asTypeName())
588 
589     public fun addSuperclassConstructorParameter(
590       format: String,
591       vararg args: Any,
592     ): Builder = apply {
593       addSuperclassConstructorParameter(CodeBlock.of(format, *args))
594     }
595 
596     public fun addSuperclassConstructorParameter(codeBlock: CodeBlock): Builder = apply {
597       checkCanHaveSuperclass()
598       this.superclassConstructorParameters += codeBlock
599     }
600 
601     public fun addSuperinterfaces(superinterfaces: Iterable<TypeName>): Builder = apply {
602       this.superinterfaces.putAll(superinterfaces.map { it to null })
603     }
604 
605     public fun addSuperinterface(
606       superinterface: TypeName,
607       delegate: CodeBlock = CodeBlock.EMPTY,
608     ): Builder = apply {
609       if (delegate.isEmpty()) {
610         this.superinterfaces[superinterface] = null
611       } else {
612         require(isSimpleClass || kind == Kind.OBJECT) {
613           "delegation only allowed for classes and objects (found $kind '$name')"
614         }
615         require(!superinterface.isNullable) {
616           "expected non-nullable type but was '${superinterface.copy(nullable = false)}'"
617         }
618         require(this.superinterfaces[superinterface] == null) {
619           "'$name' can not delegate to $superinterface by $delegate with existing declaration by " +
620             "${this.superinterfaces[superinterface]}"
621         }
622         this.superinterfaces[superinterface] = delegate
623       }
624     }
625 
626     @DelicateKotlinPoetApi(
627       message = "Java reflection APIs don't give complete information on Kotlin types. Consider " +
628         "using the kotlinpoet-metadata APIs instead.",
629     )
630     public fun addSuperinterface(
631       superinterface: Type,
632       delegate: CodeBlock = CodeBlock.EMPTY,
633     ): Builder = addSuperinterface(superinterface.asTypeName(), delegate)
634 
635     public fun addSuperinterface(
636       superinterface: KClass<*>,
637       delegate: CodeBlock = CodeBlock.EMPTY,
638     ): Builder = addSuperinterface(superinterface.asTypeName(), delegate)
639 
640     public fun addSuperinterface(
641       superinterface: KClass<*>,
642       constructorParameterName: String,
643     ): Builder = addSuperinterface(superinterface.asTypeName(), constructorParameterName)
644 
645     public fun addSuperinterface(
646       superinterface: TypeName,
647       constructorParameter: String,
648     ): Builder = apply {
649       requireNotNull(primaryConstructor) {
650         "delegating to constructor parameter requires not-null constructor"
651       }
652       val parameter = primaryConstructor?.parameter(constructorParameter)
653       requireNotNull(parameter) {
654         "no such constructor parameter '$constructorParameter' to delegate to for type '$name'"
655       }
656       addSuperinterface(superinterface, CodeBlock.of(constructorParameter))
657     }
658 
659     @JvmOverloads public fun addEnumConstant(
660       name: String,
661       typeSpec: TypeSpec = anonymousClassBuilder().build(),
662     ): Builder = apply {
663       require(name != "name" && name != "ordinal") {
664         "constant with name \"$name\" conflicts with a supertype member with the same name"
665       }
666       enumConstants[name] = typeSpec
667     }
668 
669     override fun addProperty(propertySpec: PropertySpec): Builder = apply {
670       if (EXPECT in modifiers) {
671         require(propertySpec.initializer == null) {
672           "properties in expect classes can't have initializers"
673         }
674         require(propertySpec.getter == null && propertySpec.setter == null) {
675           "properties in expect classes can't have getters and setters"
676         }
677       }
678       if (isEnum) {
679         require(propertySpec.name != "name" && propertySpec.name != "ordinal") {
680           "${propertySpec.name} is a final supertype member and can't be redeclared or overridden"
681         }
682       }
683       propertySpecs += propertySpec
684     }
685 
686     public fun addInitializerBlock(block: CodeBlock): Builder = apply {
687       checkCanHaveInitializerBlocks()
688       // Set index to however many properties we have
689       // All properties added after this point are declared as such, including any that initialize
690       // to a constructor param.
691       initializerIndex = propertySpecs.size
692       initializerBlock.add("init {\n")
693         .indent()
694         .add(block)
695         .unindent()
696         .add("}\n")
697     }
698 
699     override fun addFunction(funSpec: FunSpec): Builder = apply {
700       funSpecs += funSpec
701     }
702 
703     override fun addType(typeSpec: TypeSpec): Builder = apply {
704       typeSpecs += typeSpec
705     }
706 
707     @ExperimentalKotlinPoetApi
708     override fun contextReceivers(receiverTypes: Iterable<TypeName>): Builder = apply {
709       check(isSimpleClass) { "contextReceivers can only be applied on simple classes" }
710       contextReceiverTypes += receiverTypes
711     }
712 
713     //region Overrides for binary compatibility
714     @Suppress("RedundantOverride")
715     override fun addAnnotation(annotationSpec: AnnotationSpec): Builder = super.addAnnotation(annotationSpec)
716 
717     @Suppress("RedundantOverride")
718     override fun addAnnotations(annotationSpecs: Iterable<AnnotationSpec>): Builder =
719       super.addAnnotations(annotationSpecs)
720 
721     @Suppress("RedundantOverride")
722     override fun addAnnotation(annotation: ClassName): Builder = super.addAnnotation(annotation)
723 
724     @DelicateKotlinPoetApi(
725       message = "Java reflection APIs don't give complete information on Kotlin types. Consider " +
726         "using the kotlinpoet-metadata APIs instead.",
727     )
728     override fun addAnnotation(annotation: Class<*>): Builder = super.addAnnotation(annotation)
729 
730     @Suppress("RedundantOverride")
731     override fun addAnnotation(annotation: KClass<*>): Builder = super.addAnnotation(annotation)
732 
733     @Suppress("RedundantOverride")
734     override fun addKdoc(format: String, vararg args: Any): Builder = super.addKdoc(format, *args)
735 
736     @Suppress("RedundantOverride")
737     override fun addKdoc(block: CodeBlock): Builder = super.addKdoc(block)
738 
739     @Suppress("RedundantOverride")
740     override fun addTypes(typeSpecs: Iterable<TypeSpec>): Builder = super.addTypes(typeSpecs)
741 
742     @Suppress("RedundantOverride")
743     override fun addProperties(propertySpecs: Iterable<PropertySpec>): Builder =
744       super.addProperties(propertySpecs)
745 
746     @Suppress("RedundantOverride")
747     override fun addProperty(name: String, type: TypeName, vararg modifiers: KModifier): Builder =
748       super.addProperty(name, type, *modifiers)
749 
750     @DelicateKotlinPoetApi(
751       message = "Java reflection APIs don't give complete information on Kotlin types. Consider " +
752         "using the kotlinpoet-metadata APIs instead.",
753     )
754     override fun addProperty(name: String, type: Type, vararg modifiers: KModifier): Builder =
755       super.addProperty(name, type, *modifiers)
756 
757     @Suppress("RedundantOverride")
758     override fun addProperty(name: String, type: KClass<*>, vararg modifiers: KModifier): Builder =
759       super.addProperty(name, type, *modifiers)
760 
761     @Suppress("RedundantOverride")
762     override fun addProperty(name: String, type: TypeName, modifiers: Iterable<KModifier>): Builder =
763       super.addProperty(name, type, modifiers)
764 
765     @DelicateKotlinPoetApi(
766       message = "Java reflection APIs don't give complete information on Kotlin types. Consider " +
767         "using the kotlinpoet-metadata APIs instead.",
768     )
769     override fun addProperty(name: String, type: Type, modifiers: Iterable<KModifier>): Builder =
770       super.addProperty(name, type, modifiers)
771 
772     @Suppress("RedundantOverride")
773     override fun addProperty(name: String, type: KClass<*>, modifiers: Iterable<KModifier>): Builder =
774       super.addProperty(name, type, modifiers)
775 
776     @Suppress("RedundantOverride")
777     override fun addFunctions(funSpecs: Iterable<FunSpec>): Builder = super.addFunctions(funSpecs)
778     //endregion
779 
780     public fun build(): TypeSpec {
781       if (enumConstants.isNotEmpty()) {
782         check(isEnum) { "$name is not an enum and cannot have enum constants" }
783       }
784 
785       if (superclassConstructorParameters.isNotEmpty()) {
786         checkCanHaveSuperclass()
787 
788         check(!isExternal) {
789           "delegated constructor call in external class is not allowed"
790         }
791       }
792       check(!(isExternal && funSpecs.any { it.delegateConstructor != null })) {
793         "delegated constructor call in external class is not allowed"
794       }
795 
796       check(!(isAnonymousClass && typeVariables.isNotEmpty())) {
797         "typevariables are forbidden on anonymous types"
798       }
799 
800       val isAbstract = ABSTRACT in modifiers || SEALED in modifiers || kind == Kind.INTERFACE || isEnum
801       for (funSpec in funSpecs) {
802         require(isAbstract || ABSTRACT !in funSpec.modifiers) {
803           "non-abstract type $name cannot declare abstract function ${funSpec.name}"
804         }
805         when {
806           kind == Kind.INTERFACE -> {
807             requireNoneOf(funSpec.modifiers, INTERNAL, PROTECTED)
808             requireNoneOrOneOf(funSpec.modifiers, ABSTRACT, PRIVATE)
809           }
810           isAnnotation -> {
811             throw IllegalArgumentException("annotation class $name cannot declare member function ${funSpec.name}")
812           }
813           EXPECT in modifiers -> require(funSpec.body.isEmpty()) {
814             "functions in expect classes can't have bodies"
815           }
816         }
817       }
818 
819       for (propertySpec in propertySpecs) {
820         require(isAbstract || ABSTRACT !in propertySpec.modifiers) {
821           "non-abstract type $name cannot declare abstract property ${propertySpec.name}"
822         }
823         if (propertySpec.contextReceiverTypes.isNotEmpty()) {
824           if (ABSTRACT !in kind.implicitPropertyModifiers(modifiers) + propertySpec.modifiers) {
825             requireNotNull(propertySpec.getter) { "non-abstract properties with context receivers require a ${FunSpec.GETTER}" }
826             if (propertySpec.mutable) {
827               requireNotNull(propertySpec.setter) { "non-abstract mutable properties with context receivers require a ${FunSpec.SETTER}" }
828             }
829           }
830         }
831       }
832 
833       if (isAnnotation) {
834         primaryConstructor?.let {
835           requireNoneOf(it.modifiers, INTERNAL, PROTECTED, PRIVATE, ABSTRACT)
836         }
837       }
838 
839       if (primaryConstructor == null) {
840         require(funSpecs.none { it.isConstructor } || superclassConstructorParameters.isEmpty()) {
841           "types without a primary constructor cannot specify secondary constructors and " +
842             "superclass constructor parameters"
843         }
844       }
845 
846       if (isInlineOrValClass) {
847         primaryConstructor?.let {
848           check(it.parameters.size == 1) {
849             "value/inline classes must have 1 parameter in constructor"
850           }
851         }
852 
853         check(propertySpecs.size > 0) {
854           "value/inline classes must have at least 1 property"
855         }
856 
857         val constructorParamName = primaryConstructor?.parameters?.firstOrNull()?.name
858         constructorParamName?.let { paramName ->
859           val underlyingProperty = propertySpecs.find { it.name == paramName }
860           requireNotNull(underlyingProperty) {
861             "value/inline classes must have a single read-only (val) property parameter."
862           }
863           check(!underlyingProperty.mutable) {
864             "value/inline classes must have a single read-only (val) property parameter."
865           }
866         }
867         check(superclass == Any::class.asTypeName()) {
868           "value/inline classes cannot have super classes"
869         }
870       }
871 
872       if (isFunInterface) {
873         // Note: Functional interfaces can contain any number of non-abstract functions.
874         val abstractFunSpecs = funSpecs.filter { ABSTRACT in it.modifiers }
875         check(abstractFunSpecs.size == 1) {
876           "Functional interfaces must have exactly one abstract function. Contained " +
877             "${abstractFunSpecs.size}: ${abstractFunSpecs.map { it.name }}"
878         }
879       }
880 
881       when (typeSpecs.count { it.isCompanion }) {
882         0 -> Unit
883         1 -> {
884           require(isSimpleClass || kind == Kind.INTERFACE || isEnum || isAnnotation) {
885             "$kind types can't have a companion object"
886           }
887         }
888         else -> {
889           throw IllegalArgumentException("Multiple companion objects are present but only one is allowed.")
890         }
891       }
892 
893       return TypeSpec(this)
894     }
895   }
896 
897   public companion object {
898     @JvmStatic public fun classBuilder(name: String): Builder = Builder(Kind.CLASS, name)
899 
900     @JvmStatic public fun classBuilder(className: ClassName): Builder = classBuilder(className.simpleName)
901 
902     @Deprecated(
903       "Use classBuilder() instead. This function will be removed in KotlinPoet 2.0.",
904       ReplaceWith("TypeSpec.classBuilder(name).addModifiers(KModifier.EXPECT)"),
905     )
906     @JvmStatic
907     public fun expectClassBuilder(name: String): Builder = Builder(Kind.CLASS, name, EXPECT)
908 
909     @Deprecated(
910       "Use classBuilder() instead. This function will be removed in KotlinPoet 2.0.",
911       ReplaceWith("TypeSpec.classBuilder(className).addModifiers(KModifier.EXPECT)"),
912     )
913     @JvmStatic
914     public fun expectClassBuilder(className: ClassName): Builder = classBuilder(className.simpleName).addModifiers(EXPECT)
915 
916     @Deprecated(
917       "Use classBuilder() instead. This function will be removed in KotlinPoet 2.0.",
918       ReplaceWith("TypeSpec.classBuilder(name).addModifiers(KModifier.VALUE)"),
919     )
920     @JvmStatic
921     public fun valueClassBuilder(name: String): Builder = Builder(Kind.CLASS, name, VALUE)
922 
923     @JvmStatic public fun objectBuilder(name: String): Builder = Builder(Kind.OBJECT, name)
924 
925     @JvmStatic public fun objectBuilder(className: ClassName): Builder = objectBuilder(className.simpleName)
926 
927     @JvmStatic @JvmOverloads
928     public fun companionObjectBuilder(name: String? = null): Builder =
929       Builder(Kind.OBJECT, name, COMPANION)
930 
931     @JvmStatic public fun interfaceBuilder(name: String): Builder = Builder(Kind.INTERFACE, name)
932 
933     @JvmStatic public fun interfaceBuilder(className: ClassName): Builder =
934       interfaceBuilder(className.simpleName)
935 
936     @JvmStatic public fun funInterfaceBuilder(name: String): Builder =
937       Builder(Kind.INTERFACE, name, FUN)
938 
939     @JvmStatic public fun funInterfaceBuilder(className: ClassName): Builder =
940       funInterfaceBuilder(className.simpleName)
941 
942     @JvmStatic public fun enumBuilder(name: String): Builder = Builder(Kind.CLASS, name, ENUM)
943 
944     @JvmStatic public fun enumBuilder(className: ClassName): Builder =
945       enumBuilder(className.simpleName)
946 
947     @JvmStatic public fun anonymousClassBuilder(): Builder = Builder(Kind.CLASS, null)
948 
949     @JvmStatic public fun annotationBuilder(name: String): Builder =
950       Builder(Kind.CLASS, name, ANNOTATION)
951 
952     @JvmStatic public fun annotationBuilder(className: ClassName): Builder =
953       annotationBuilder(className.simpleName)
954   }
955 }
956