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