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