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