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