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