xref: /aosp_15_r20/external/kotlinpoet/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/FunSpec.kt (revision 3c321d951dd070fb96f8ba59e952ffc3131379a0)
1 /*
<lambda>null2  * Copyright (C) 2015 Square, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.squareup.kotlinpoet
17 
18 import com.squareup.kotlinpoet.KModifier.ABSTRACT
19 import com.squareup.kotlinpoet.KModifier.EXPECT
20 import com.squareup.kotlinpoet.KModifier.EXTERNAL
21 import com.squareup.kotlinpoet.KModifier.INLINE
22 import com.squareup.kotlinpoet.KModifier.VARARG
23 import java.lang.reflect.Type
24 import javax.lang.model.element.Element
25 import javax.lang.model.element.ExecutableElement
26 import javax.lang.model.element.Modifier
27 import javax.lang.model.type.DeclaredType
28 import javax.lang.model.type.ExecutableType
29 import javax.lang.model.type.TypeVariable
30 import javax.lang.model.util.Types
31 import kotlin.DeprecationLevel.WARNING
32 import kotlin.reflect.KClass
33 
34 /** A generated function declaration. */
35 @OptIn(ExperimentalKotlinPoetApi::class)
36 public class FunSpec private constructor(
37   builder: Builder,
38   private val tagMap: TagMap = builder.buildTagMap(),
39   private val delegateOriginatingElementsHolder: OriginatingElementsHolder = builder.buildOriginatingElements(),
40   private val contextReceivers: ContextReceivers = builder.buildContextReceivers(),
41 ) : Taggable by tagMap,
42   OriginatingElementsHolder by delegateOriginatingElementsHolder,
43   ContextReceivable by contextReceivers,
44   Annotatable,
45   Documentable {
46   public val name: String = builder.name
47   override val kdoc: CodeBlock = builder.kdoc.build()
48   public val returnKdoc: CodeBlock = builder.returnKdoc
49   public val receiverKdoc: CodeBlock = builder.receiverKdoc
50   override val annotations: List<AnnotationSpec> = builder.annotations.toImmutableList()
51   public val modifiers: Set<KModifier> = builder.modifiers.toImmutableSet()
52   public val typeVariables: List<TypeVariableName> = builder.typeVariables.toImmutableList()
53   public val receiverType: TypeName? = builder.receiverType
54 
55   public val returnType: TypeName = builder.returnType
56   public val parameters: List<ParameterSpec> = builder.parameters.toImmutableList()
57   public val delegateConstructor: String? = builder.delegateConstructor
58   public val delegateConstructorArguments: List<CodeBlock> =
59     builder.delegateConstructorArguments.toImmutableList()
60   public val body: CodeBlock = builder.body.build()
61   private val isExternalGetter = name == GETTER && builder.modifiers.contains(EXTERNAL)
62   private val isEmptySetter = name == SETTER && parameters.isEmpty()
63 
64   init {
65     require(body.isEmpty() || !builder.modifiers.containsAnyOf(ABSTRACT, EXPECT)) {
66       "abstract or expect function ${builder.name} cannot have code"
67     }
68     if (name == GETTER) {
69       require(!isExternalGetter || body.isEmpty()) {
70         "external getter cannot have code"
71       }
72     } else if (name == SETTER) {
73       require(parameters.size <= 1) {
74         "$name can have at most one parameter"
75       }
76       require(parameters.isNotEmpty() || body.isEmpty()) {
77         "parameterless setter cannot have code"
78       }
79     }
80     require(INLINE in modifiers || typeVariables.none { it.isReified }) {
81       "only type parameters of inline functions can be reified!"
82     }
83   }
84 
85   internal fun parameter(name: String) = parameters.firstOrNull { it.name == name }
86 
87   internal fun emit(
88     codeWriter: CodeWriter,
89     enclosingName: String?,
90     implicitModifiers: Set<KModifier>,
91     includeKdocTags: Boolean = false,
92   ) {
93     if (includeKdocTags) {
94       codeWriter.emitKdoc(kdocWithTags())
95     } else {
96       codeWriter.emitKdoc(kdoc.ensureEndsWithNewLine())
97     }
98     codeWriter.emitContextReceivers(contextReceiverTypes, suffix = "\n")
99     codeWriter.emitAnnotations(annotations, false)
100     codeWriter.emitModifiers(modifiers, implicitModifiers)
101 
102     if (!isConstructor && !name.isAccessor) {
103       codeWriter.emitCode("fun·")
104     }
105 
106     if (typeVariables.isNotEmpty()) {
107       codeWriter.emitTypeVariables(typeVariables)
108       codeWriter.emit(" ")
109     }
110     emitSignature(codeWriter, enclosingName)
111     codeWriter.emitWhereBlock(typeVariables)
112 
113     if (shouldOmitBody(implicitModifiers)) {
114       codeWriter.emit("\n")
115       return
116     }
117 
118     val asExpressionBody = body.asExpressionBody()
119 
120     if (asExpressionBody != null) {
121       codeWriter.emitCode(CodeBlock.of(" = %L", asExpressionBody), ensureTrailingNewline = true)
122     } else if (!isEmptySetter) {
123       codeWriter.emitCode("·{\n")
124       codeWriter.indent()
125       codeWriter.emitCode(body.returnsWithoutLinebreak(), ensureTrailingNewline = true)
126       codeWriter.unindent()
127       codeWriter.emit("}\n")
128     } else {
129       codeWriter.emit("\n")
130     }
131   }
132 
133   private fun shouldOmitBody(implicitModifiers: Set<KModifier>): Boolean {
134     if (canNotHaveBody(implicitModifiers)) {
135       check(body.isEmpty()) { "function $name cannot have code" }
136       return true
137     }
138     return canBodyBeOmitted(implicitModifiers) && body.isEmpty()
139   }
140 
141   private fun canNotHaveBody(implicitModifiers: Set<KModifier>) =
142     ABSTRACT in modifiers || EXPECT in modifiers + implicitModifiers
143 
144   private fun canBodyBeOmitted(implicitModifiers: Set<KModifier>) = isConstructor ||
145     EXTERNAL in (modifiers + implicitModifiers) ||
146     ABSTRACT in modifiers
147 
148   private fun emitSignature(codeWriter: CodeWriter, enclosingName: String?) {
149     if (isConstructor) {
150       codeWriter.emitCode("constructor", enclosingName)
151     } else if (name == GETTER) {
152       codeWriter.emitCode("get")
153     } else if (name == SETTER) {
154       codeWriter.emitCode("set")
155     } else {
156       if (receiverType != null) {
157         if (receiverType is LambdaTypeName) {
158           codeWriter.emitCode("(%T).", receiverType)
159         } else {
160           codeWriter.emitCode("%T.", receiverType)
161         }
162       }
163       codeWriter.emitCode("%N", this)
164     }
165 
166     if (!isEmptySetter && !isExternalGetter) {
167       parameters.emit(codeWriter) { param ->
168         param.emit(codeWriter, includeType = name != SETTER)
169       }
170     }
171 
172     if (returnType != UNIT || emitUnitReturnType()) {
173       codeWriter.emitCode(": %T", returnType)
174     }
175 
176     if (delegateConstructor != null) {
177       codeWriter.emitCode(
178         delegateConstructorArguments
179           .joinToCode(prefix = " : $delegateConstructor(", suffix = ")"),
180       )
181     }
182   }
183 
184   public val isConstructor: Boolean get() = name.isConstructor
185 
186   public val isAccessor: Boolean get() = name.isAccessor
187 
188   private fun kdocWithTags(): CodeBlock {
189     return with(kdoc.ensureEndsWithNewLine().toBuilder()) {
190       var newLineAdded = false
191       val isNotEmpty = isNotEmpty()
192       if (receiverKdoc.isNotEmpty()) {
193         if (isNotEmpty) {
194           add("\n")
195           newLineAdded = true
196         }
197         add("@receiver %L", receiverKdoc.ensureEndsWithNewLine())
198       }
199       parameters.forEachIndexed { index, parameterSpec ->
200         if (parameterSpec.kdoc.isNotEmpty()) {
201           if (!newLineAdded && index == 0 && isNotEmpty) {
202             add("\n")
203             newLineAdded = true
204           }
205           add("@param %L %L", parameterSpec.name, parameterSpec.kdoc.ensureEndsWithNewLine())
206         }
207       }
208       if (returnKdoc.isNotEmpty()) {
209         if (!newLineAdded && isNotEmpty) {
210           add("\n")
211           newLineAdded = true
212         }
213         add("@return %L", returnKdoc.ensureEndsWithNewLine())
214       }
215       build()
216     }
217   }
218 
219   /**
220    * Returns whether [Unit] should be emitted as the return type.
221    *
222    * [Unit] is emitted as return type on a function only if it is an expression body.
223    */
224   private fun emitUnitReturnType(): Boolean {
225     if (isConstructor) {
226       return false
227     }
228     if (name == GETTER || name == SETTER) {
229       // Getter/setters don't emit return types
230       return false
231     }
232 
233     return body.asExpressionBody() != null
234   }
235 
236   private fun CodeBlock.asExpressionBody(): CodeBlock? {
237     val codeBlock = this.trim()
238     val asReturnExpressionBody = codeBlock.withoutPrefix(RETURN_EXPRESSION_BODY_PREFIX_SPACE)
239       ?: codeBlock.withoutPrefix(RETURN_EXPRESSION_BODY_PREFIX_NBSP)
240     if (asReturnExpressionBody != null) {
241       return asReturnExpressionBody
242     }
243     if (codeBlock.withoutPrefix(THROW_EXPRESSION_BODY_PREFIX_SPACE) != null ||
244       codeBlock.withoutPrefix(THROW_EXPRESSION_BODY_PREFIX_NBSP) != null
245     ) {
246       return codeBlock
247     }
248     return null
249   }
250 
251   private fun CodeBlock.returnsWithoutLinebreak(): CodeBlock {
252     val returnWithSpace = RETURN_EXPRESSION_BODY_PREFIX_SPACE.formatParts[0]
253     val returnWithNbsp = RETURN_EXPRESSION_BODY_PREFIX_NBSP.formatParts[0]
254     var originCodeBlockBuilder: CodeBlock.Builder? = null
255     for ((i, formatPart) in formatParts.withIndex()) {
256       if (formatPart.startsWith(returnWithSpace)) {
257         val builder = originCodeBlockBuilder ?: toBuilder()
258         originCodeBlockBuilder = builder
259         builder.formatParts[i] = formatPart.replaceFirst(returnWithSpace, returnWithNbsp)
260       }
261     }
262     return originCodeBlockBuilder?.build() ?: this
263   }
264 
265   override fun equals(other: Any?): Boolean {
266     if (this === other) return true
267     if (other == null) return false
268     if (javaClass != other.javaClass) return false
269     return toString() == other.toString()
270   }
271 
272   override fun hashCode(): Int = toString().hashCode()
273 
274   override fun toString(): String = buildCodeString {
275     emit(
276       codeWriter = this,
277       enclosingName = "Constructor",
278       implicitModifiers = TypeSpec.Kind.CLASS.implicitFunctionModifiers(),
279       includeKdocTags = true,
280     )
281   }
282 
283   @JvmOverloads
284   public fun toBuilder(name: String = this.name): Builder {
285     val builder = Builder(name)
286     builder.kdoc.add(kdoc)
287     builder.returnKdoc = returnKdoc
288     builder.receiverKdoc = receiverKdoc
289     builder.annotations += annotations
290     builder.modifiers += modifiers
291     builder.typeVariables += typeVariables
292     builder.returnType = returnType
293     builder.parameters += parameters
294     builder.delegateConstructor = delegateConstructor
295     builder.delegateConstructorArguments += delegateConstructorArguments
296     builder.body.add(body)
297     builder.receiverType = receiverType
298     builder.tags += tagMap.tags
299     builder.originatingElements += originatingElements
300     builder.contextReceiverTypes += contextReceiverTypes
301     return builder
302   }
303 
304   public class Builder internal constructor(
305     internal val name: String,
306   ) : Taggable.Builder<Builder>,
307     OriginatingElementsHolder.Builder<Builder>,
308     ContextReceivable.Builder<Builder>,
309     Annotatable.Builder<Builder>,
310     Documentable.Builder<Builder> {
311     internal var returnKdoc = CodeBlock.EMPTY
312     internal var receiverKdoc = CodeBlock.EMPTY
313     internal var receiverType: TypeName? = null
314     internal var returnType: TypeName = UNIT
315     internal var delegateConstructor: String? = null
316     internal var delegateConstructorArguments = listOf<CodeBlock>()
317     internal val body = CodeBlock.builder()
318     override val kdoc: CodeBlock.Builder = CodeBlock.builder()
319     override val annotations: MutableList<AnnotationSpec> = mutableListOf()
320     public val modifiers: MutableList<KModifier> = mutableListOf()
321     public val typeVariables: MutableList<TypeVariableName> = mutableListOf()
322     public val parameters: MutableList<ParameterSpec> = mutableListOf()
323     override val tags: MutableMap<KClass<*>, Any> = mutableMapOf()
324     override val originatingElements: MutableList<Element> = mutableListOf()
325 
326     @ExperimentalKotlinPoetApi
327     override val contextReceiverTypes: MutableList<TypeName> = mutableListOf()
328 
329     public fun addModifiers(vararg modifiers: KModifier): Builder = apply {
330       this.modifiers += modifiers
331     }
332 
333     public fun addModifiers(modifiers: Iterable<KModifier>): Builder = apply {
334       this.modifiers += modifiers
335     }
336 
337     public fun jvmModifiers(modifiers: Iterable<Modifier>) {
338       var visibility = KModifier.INTERNAL
339       for (modifier in modifiers) {
340         when (modifier) {
341           Modifier.PUBLIC -> visibility = KModifier.PUBLIC
342           Modifier.PROTECTED -> visibility = KModifier.PROTECTED
343           Modifier.PRIVATE -> visibility = KModifier.PRIVATE
344           Modifier.ABSTRACT -> this.modifiers += KModifier.ABSTRACT
345           Modifier.FINAL -> this.modifiers += KModifier.FINAL
346           Modifier.NATIVE -> this.modifiers += KModifier.EXTERNAL
347           Modifier.DEFAULT -> Unit
348           Modifier.STATIC -> addAnnotation(JvmStatic::class)
349           Modifier.SYNCHRONIZED -> addAnnotation(Synchronized::class)
350           Modifier.STRICTFP -> addAnnotation(Strictfp::class)
351           else -> throw IllegalArgumentException("unexpected fun modifier $modifier")
352         }
353       }
354       this.modifiers += visibility
355     }
356 
357     public fun addTypeVariables(typeVariables: Iterable<TypeVariableName>): Builder = apply {
358       this.typeVariables += typeVariables
359     }
360 
361     public fun addTypeVariable(typeVariable: TypeVariableName): Builder = apply {
362       typeVariables += typeVariable
363     }
364 
365     @ExperimentalKotlinPoetApi
366     override fun contextReceivers(receiverTypes: Iterable<TypeName>): Builder = apply {
367       check(!name.isConstructor) { "constructors cannot have context receivers" }
368       check(!name.isAccessor) { "$name cannot have context receivers" }
369       contextReceiverTypes += receiverTypes
370     }
371 
372     @JvmOverloads public fun receiver(
373       receiverType: TypeName,
374       kdoc: CodeBlock = CodeBlock.EMPTY,
375     ): Builder = apply {
376       check(!name.isConstructor) { "$name cannot have receiver type" }
377       this.receiverType = receiverType
378       this.receiverKdoc = kdoc
379     }
380 
381     @JvmOverloads public fun receiver(
382       receiverType: Type,
383       kdoc: CodeBlock = CodeBlock.EMPTY,
384     ): Builder = receiver(receiverType.asTypeName(), kdoc)
385 
386     public fun receiver(
387       receiverType: Type,
388       kdoc: String,
389       vararg args: Any,
390     ): Builder = receiver(receiverType, CodeBlock.of(kdoc, args))
391 
392     @JvmOverloads public fun receiver(
393       receiverType: KClass<*>,
394       kdoc: CodeBlock = CodeBlock.EMPTY,
395     ): Builder = receiver(receiverType.asTypeName(), kdoc)
396 
397     public fun receiver(
398       receiverType: KClass<*>,
399       kdoc: String,
400       vararg args: Any,
401     ): Builder = receiver(receiverType, CodeBlock.of(kdoc, args))
402 
403     @JvmOverloads public fun returns(
404       returnType: TypeName,
405       kdoc: CodeBlock = CodeBlock.EMPTY,
406     ): Builder = apply {
407       check(!name.isConstructor && !name.isAccessor) { "$name cannot have a return type" }
408       this.returnType = returnType
409       this.returnKdoc = kdoc
410     }
411 
412     @JvmOverloads public fun returns(returnType: Type, kdoc: CodeBlock = CodeBlock.EMPTY): Builder =
413       returns(returnType.asTypeName(), kdoc)
414 
415     public fun returns(returnType: Type, kdoc: String, vararg args: Any): Builder =
416       returns(returnType.asTypeName(), CodeBlock.of(kdoc, args))
417 
418     @JvmOverloads public fun returns(
419       returnType: KClass<*>,
420       kdoc: CodeBlock = CodeBlock.EMPTY,
421     ): Builder = returns(returnType.asTypeName(), kdoc)
422 
423     public fun returns(returnType: KClass<*>, kdoc: String, vararg args: Any): Builder =
424       returns(returnType.asTypeName(), CodeBlock.of(kdoc, args))
425 
426     public fun addParameters(parameterSpecs: Iterable<ParameterSpec>): Builder = apply {
427       for (parameterSpec in parameterSpecs) {
428         addParameter(parameterSpec)
429       }
430     }
431 
432     public fun addParameter(parameterSpec: ParameterSpec): Builder = apply {
433       parameters += parameterSpec
434     }
435 
436     public fun callThisConstructor(args: List<CodeBlock>): Builder = apply {
437       callConstructor("this", args)
438     }
439 
440     public fun callThisConstructor(args: Iterable<CodeBlock>): Builder = apply {
441       callConstructor("this", args.toList())
442     }
443 
444     public fun callThisConstructor(vararg args: String): Builder = apply {
445       callConstructor("this", args.map { CodeBlock.of(it) })
446     }
447 
448     public fun callThisConstructor(vararg args: CodeBlock = emptyArray()): Builder = apply {
449       callConstructor("this", args.toList())
450     }
451 
452     public fun callSuperConstructor(args: Iterable<CodeBlock>): Builder = apply {
453       callConstructor("super", args.toList())
454     }
455 
456     public fun callSuperConstructor(args: List<CodeBlock>): Builder = apply {
457       callConstructor("super", args)
458     }
459 
460     public fun callSuperConstructor(vararg args: String): Builder = apply {
461       callConstructor("super", args.map { CodeBlock.of(it) })
462     }
463 
464     public fun callSuperConstructor(vararg args: CodeBlock = emptyArray()): Builder = apply {
465       callConstructor("super", args.toList())
466     }
467 
468     private fun callConstructor(constructor: String, args: List<CodeBlock>) {
469       check(name.isConstructor) { "only constructors can delegate to other constructors!" }
470       delegateConstructor = constructor
471       delegateConstructorArguments = args
472     }
473 
474     public fun addParameter(name: String, type: TypeName, vararg modifiers: KModifier): Builder =
475       addParameter(ParameterSpec.builder(name, type, *modifiers).build())
476 
477     public fun addParameter(name: String, type: Type, vararg modifiers: KModifier): Builder =
478       addParameter(name, type.asTypeName(), *modifiers)
479 
480     public fun addParameter(name: String, type: KClass<*>, vararg modifiers: KModifier): Builder =
481       addParameter(name, type.asTypeName(), *modifiers)
482 
483     public fun addParameter(name: String, type: TypeName, modifiers: Iterable<KModifier>): Builder =
484       addParameter(ParameterSpec.builder(name, type, modifiers).build())
485 
486     public fun addParameter(name: String, type: Type, modifiers: Iterable<KModifier>): Builder =
487       addParameter(name, type.asTypeName(), modifiers)
488 
489     public fun addParameter(
490       name: String,
491       type: KClass<*>,
492       modifiers: Iterable<KModifier>,
493     ): Builder = addParameter(name, type.asTypeName(), modifiers)
494 
495     public fun addCode(format: String, vararg args: Any?): Builder = apply {
496       body.add(format, *args)
497     }
498 
499     public fun addNamedCode(format: String, args: Map<String, *>): Builder = apply {
500       body.addNamed(format, args)
501     }
502 
503     public fun addCode(codeBlock: CodeBlock): Builder = apply {
504       body.add(codeBlock)
505     }
506 
507     public fun addComment(format: String, vararg args: Any): Builder = apply {
508       body.add("//·${format.replace(' ', '·')}\n", *args)
509     }
510 
511     /**
512      * @param controlFlow the control flow construct and its code, such as "if (foo == 5)".
513      * * Shouldn't contain braces or newline characters.
514      */
515     public fun beginControlFlow(controlFlow: String, vararg args: Any): Builder = apply {
516       body.beginControlFlow(controlFlow, *args)
517     }
518 
519     /**
520      * @param controlFlow the control flow construct and its code, such as "else if (foo == 10)".
521      * *     Shouldn't contain braces or newline characters.
522      */
523     public fun nextControlFlow(controlFlow: String, vararg args: Any): Builder = apply {
524       body.nextControlFlow(controlFlow, *args)
525     }
526 
527     public fun endControlFlow(): Builder = apply {
528       body.endControlFlow()
529     }
530 
531     public fun addStatement(format: String, vararg args: Any): Builder = apply {
532       body.addStatement(format, *args)
533     }
534 
535     public fun clearBody(): Builder = apply {
536       body.clear()
537     }
538 
539     //region Overrides for binary compatibility
540     @Suppress("RedundantOverride")
541     override fun addAnnotation(annotationSpec: AnnotationSpec): Builder = super.addAnnotation(annotationSpec)
542 
543     @Suppress("RedundantOverride")
544     override fun addAnnotations(annotationSpecs: Iterable<AnnotationSpec>): Builder =
545       super.addAnnotations(annotationSpecs)
546 
547     @Suppress("RedundantOverride")
548     override fun addAnnotation(annotation: ClassName): Builder = super.addAnnotation(annotation)
549 
550     @DelicateKotlinPoetApi(
551       message = "Java reflection APIs don't give complete information on Kotlin types. Consider " +
552         "using the kotlinpoet-metadata APIs instead.",
553     )
554     override fun addAnnotation(annotation: Class<*>): Builder = super.addAnnotation(annotation)
555 
556     @Suppress("RedundantOverride")
557     override fun addAnnotation(annotation: KClass<*>): Builder = super.addAnnotation(annotation)
558 
559     @Suppress("RedundantOverride")
560     override fun addKdoc(format: String, vararg args: Any): Builder = super.addKdoc(format, *args)
561 
562     @Suppress("RedundantOverride")
563     override fun addKdoc(block: CodeBlock): Builder = super.addKdoc(block)
564     //endregion
565 
566     public fun build(): FunSpec {
567       check(typeVariables.isEmpty() || !name.isAccessor) { "$name cannot have type variables" }
568       check(!(name == GETTER && parameters.isNotEmpty())) { "$name cannot have parameters" }
569       check(!(name == SETTER && parameters.size > 1)) { "$name can have at most one parameter" }
570       return FunSpec(this)
571     }
572   }
573 
574   public companion object {
575     private const val CONSTRUCTOR = "constructor()"
576     internal const val GETTER = "get()"
577     internal const val SETTER = "set()"
578 
579     internal val String.isConstructor get() = this == CONSTRUCTOR
580     internal val String.isAccessor get() = this.isOneOf(GETTER, SETTER)
581 
582     private val RETURN_EXPRESSION_BODY_PREFIX_SPACE = CodeBlock.of("return ")
583     private val RETURN_EXPRESSION_BODY_PREFIX_NBSP = CodeBlock.of("return·")
584     private val THROW_EXPRESSION_BODY_PREFIX_SPACE = CodeBlock.of("throw ")
585     private val THROW_EXPRESSION_BODY_PREFIX_NBSP = CodeBlock.of("throw·")
586 
587     @JvmStatic public fun builder(name: String): Builder = Builder(name)
588 
589     /** Create a new function builder from [MemberName.simpleName] */
590     @JvmStatic public fun builder(memberName: MemberName): Builder = Builder(memberName.simpleName)
591 
592     @JvmStatic public fun constructorBuilder(): Builder = Builder(CONSTRUCTOR)
593 
594     @JvmStatic public fun getterBuilder(): Builder = Builder(GETTER)
595 
596     @JvmStatic public fun setterBuilder(): Builder = Builder(SETTER)
597 
598     @DelicateKotlinPoetApi(
599       message = "Element APIs don't give complete information on Kotlin types. Consider using" +
600         " the kotlinpoet-metadata APIs instead.",
601     )
602     @JvmStatic
603     public fun overriding(method: ExecutableElement): Builder {
604       var modifiers: Set<Modifier> = method.modifiers
605       require(
606         Modifier.PRIVATE !in modifiers &&
607           Modifier.FINAL !in modifiers &&
608           Modifier.STATIC !in modifiers,
609       ) {
610         "cannot override method with modifiers: $modifiers"
611       }
612 
613       val methodName = method.simpleName.toString()
614       val funBuilder = builder(methodName)
615 
616       funBuilder.addModifiers(KModifier.OVERRIDE)
617 
618       modifiers = modifiers.toMutableSet()
619       modifiers.remove(Modifier.ABSTRACT)
620       funBuilder.jvmModifiers(modifiers)
621 
622       method.typeParameters
623         .map { it.asType() as TypeVariable }
624         .map { it.asTypeVariableName() }
625         .forEach { funBuilder.addTypeVariable(it) }
626 
627       funBuilder.returns(method.returnType.asTypeName())
628       funBuilder.addParameters(ParameterSpec.parametersOf(method))
629       if (method.isVarArgs) {
630         funBuilder.parameters[funBuilder.parameters.lastIndex] = funBuilder.parameters.last()
631           .toBuilder()
632           .addModifiers(VARARG)
633           .build()
634       }
635 
636       if (method.thrownTypes.isNotEmpty()) {
637         val throwsValueString = method.thrownTypes.joinToString { "%T::class" }
638         funBuilder.addAnnotation(
639           AnnotationSpec.builder(Throws::class)
640             .addMember(throwsValueString, *method.thrownTypes.toTypedArray())
641             .build(),
642         )
643       }
644 
645       return funBuilder
646     }
647 
648     @Deprecated(
649       message = "Element APIs don't give complete information on Kotlin types. Consider using" +
650         " the kotlinpoet-metadata APIs instead.",
651       level = WARNING,
652     )
653     @JvmStatic
654     public fun overriding(
655       method: ExecutableElement,
656       enclosing: DeclaredType,
657       types: Types,
658     ): Builder {
659       val executableType = types.asMemberOf(enclosing, method) as ExecutableType
660       val resolvedParameterTypes = executableType.parameterTypes
661       val resolvedReturnType = executableType.returnType
662 
663       val builder = overriding(method)
664       builder.returns(resolvedReturnType.asTypeName())
665       var i = 0
666       val size = builder.parameters.size
667       while (i < size) {
668         val parameter = builder.parameters[i]
669         val type = resolvedParameterTypes[i].asTypeName()
670         builder.parameters[i] = parameter.toBuilder(parameter.name, type).build()
671         i++
672       }
673 
674       return builder
675     }
676   }
677 }
678