1 /*
<lambda>null2  * Copyright (C) 2021 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.metadata.classinspectors
17 
18 import com.google.auto.common.MoreElements
19 import com.google.auto.common.MoreTypes
20 import com.google.auto.common.Visibility
21 import com.google.common.collect.LinkedHashMultimap
22 import com.google.common.collect.SetMultimap
23 import com.squareup.kotlinpoet.AnnotationSpec
24 import com.squareup.kotlinpoet.AnnotationSpec.UseSiteTarget.FILE
25 import com.squareup.kotlinpoet.ClassName
26 import com.squareup.kotlinpoet.CodeBlock
27 import com.squareup.kotlinpoet.DelicateKotlinPoetApi
28 import com.squareup.kotlinpoet.TypeName
29 import com.squareup.kotlinpoet.asClassName
30 import com.squareup.kotlinpoet.asTypeName
31 import com.squareup.kotlinpoet.metadata.classinspectors.ClassInspectorUtil.JAVA_DEPRECATED
32 import com.squareup.kotlinpoet.metadata.classinspectors.ClassInspectorUtil.JVM_NAME
33 import com.squareup.kotlinpoet.metadata.classinspectors.ClassInspectorUtil.filterOutNullabilityAnnotations
34 import com.squareup.kotlinpoet.metadata.isDeclaration
35 import com.squareup.kotlinpoet.metadata.readKotlinClassMetadata
36 import com.squareup.kotlinpoet.metadata.specs.ClassData
37 import com.squareup.kotlinpoet.metadata.specs.ClassInspector
38 import com.squareup.kotlinpoet.metadata.specs.ConstructorData
39 import com.squareup.kotlinpoet.metadata.specs.ContainerData
40 import com.squareup.kotlinpoet.metadata.specs.EnumEntryData
41 import com.squareup.kotlinpoet.metadata.specs.FieldData
42 import com.squareup.kotlinpoet.metadata.specs.FileData
43 import com.squareup.kotlinpoet.metadata.specs.JvmFieldModifier
44 import com.squareup.kotlinpoet.metadata.specs.JvmFieldModifier.TRANSIENT
45 import com.squareup.kotlinpoet.metadata.specs.JvmFieldModifier.VOLATILE
46 import com.squareup.kotlinpoet.metadata.specs.JvmMethodModifier
47 import com.squareup.kotlinpoet.metadata.specs.JvmMethodModifier.DEFAULT
48 import com.squareup.kotlinpoet.metadata.specs.JvmMethodModifier.STATIC
49 import com.squareup.kotlinpoet.metadata.specs.JvmMethodModifier.SYNCHRONIZED
50 import com.squareup.kotlinpoet.metadata.specs.KM_CONSTRUCTOR_COMPARATOR
51 import com.squareup.kotlinpoet.metadata.specs.KM_FUNCTION_COMPARATOR
52 import com.squareup.kotlinpoet.metadata.specs.KM_PROPERTY_COMPARATOR
53 import com.squareup.kotlinpoet.metadata.specs.MethodData
54 import com.squareup.kotlinpoet.metadata.specs.PropertyData
55 import com.squareup.kotlinpoet.metadata.toKmClass
56 import java.util.TreeMap
57 import java.util.concurrent.ConcurrentHashMap
58 import javax.lang.model.element.Element
59 import javax.lang.model.element.ElementKind.INTERFACE
60 import javax.lang.model.element.ExecutableElement
61 import javax.lang.model.element.PackageElement
62 import javax.lang.model.element.TypeElement
63 import javax.lang.model.element.VariableElement
64 import javax.lang.model.type.TypeKind
65 import javax.lang.model.util.ElementFilter
66 import javax.lang.model.util.Elements
67 import javax.lang.model.util.Types
68 import kotlin.LazyThreadSafetyMode.NONE
69 import kotlin.metadata.ClassKind
70 import kotlin.metadata.KmClass
71 import kotlin.metadata.KmDeclarationContainer
72 import kotlin.metadata.KmPackage
73 import kotlin.metadata.hasAnnotations
74 import kotlin.metadata.hasConstant
75 import kotlin.metadata.isConst
76 import kotlin.metadata.isValue
77 import kotlin.metadata.jvm.JvmFieldSignature
78 import kotlin.metadata.jvm.JvmMethodSignature
79 import kotlin.metadata.jvm.KotlinClassMetadata
80 import kotlin.metadata.jvm.fieldSignature
81 import kotlin.metadata.jvm.getterSignature
82 import kotlin.metadata.jvm.setterSignature
83 import kotlin.metadata.jvm.signature
84 import kotlin.metadata.jvm.syntheticMethodForAnnotations
85 import kotlin.metadata.kind
86 
87 private typealias ElementsModifier = javax.lang.model.element.Modifier
88 
89 /**
90  * An [Elements]-based implementation of [ClassInspector].
91  */
92 public class ElementsClassInspector private constructor(
93   private val lenient: Boolean,
94   private val elements: Elements,
95   private val types: Types,
96 ) : ClassInspector {
97   private val typeElementCache = ConcurrentHashMap<ClassName, Optional<TypeElement>>()
98   private val methodCache = ConcurrentHashMap<Pair<TypeElement, String>, Optional<ExecutableElement>>()
99   private val variableElementCache = ConcurrentHashMap<Pair<TypeElement, String>, Optional<VariableElement>>()
100   private val jvmNameType = elements.getTypeElement(JVM_NAME.canonicalName)
101   private val jvmNameName = ElementFilter.methodsIn(jvmNameType.enclosedElements)
102     .first { it.simpleName.toString() == "name" }
103 
104   private fun lookupTypeElement(className: ClassName): TypeElement? {
105     return typeElementCache.getOrPut(className) {
106       elements.getTypeElement(className.canonicalName).toOptional()
107     }.nullableValue
108   }
109 
110   override val supportsNonRuntimeRetainedAnnotations: Boolean = true
111 
112   override fun declarationContainerFor(className: ClassName): KmDeclarationContainer {
113     val typeElement = lookupTypeElement(className)
114       ?: error("No type element found for: $className.")
115 
116     val metadata = typeElement.getAnnotation(Metadata::class.java)
117     return when (val kotlinClassMetadata = metadata.readKotlinClassMetadata(lenient)) {
118       is KotlinClassMetadata.Class -> kotlinClassMetadata.kmClass
119       is KotlinClassMetadata.FileFacade -> kotlinClassMetadata.kmPackage
120       else -> TODO("Not implemented yet: ${kotlinClassMetadata.javaClass.simpleName}")
121     }
122   }
123 
124   override fun isInterface(className: ClassName): Boolean {
125     if (className in ClassInspectorUtil.KOTLIN_INTRINSIC_INTERFACES) {
126       return true
127     }
128     return lookupTypeElement(className)?.kind == INTERFACE
129   }
130 
131   private fun TypeElement.lookupField(fieldSignature: JvmFieldSignature): VariableElement? {
132     val signatureString = fieldSignature.toString()
133     return variableElementCache.getOrPut(this to signatureString) {
134       ElementFilter.fieldsIn(enclosedElements)
135         .find { signatureString == it.jvmFieldSignature(types) }.toOptional()
136     }.nullableValue
137   }
138 
139   private fun lookupMethod(
140     className: ClassName,
141     methodSignature: JvmMethodSignature,
142     elementFilter: (Iterable<Element>) -> List<ExecutableElement>,
143   ): ExecutableElement? {
144     return lookupTypeElement(className)?.lookupMethod(methodSignature, elementFilter)
145   }
146 
147   private fun TypeElement.lookupMethod(
148     methodSignature: JvmMethodSignature,
149     elementFilter: (Iterable<Element>) -> List<ExecutableElement>,
150   ): ExecutableElement? {
151     val signatureString = methodSignature.toString()
152     return methodCache.getOrPut(this to signatureString) {
153       elementFilter(enclosedElements)
154         .find { signatureString == it.jvmMethodSignature(types) }.toOptional()
155     }.nullableValue
156   }
157 
158   private fun VariableElement.jvmModifiers(isJvmField: Boolean): Set<JvmFieldModifier> {
159     return modifiers.mapNotNullTo(mutableSetOf()) {
160       when {
161         it == ElementsModifier.TRANSIENT -> TRANSIENT
162         it == ElementsModifier.VOLATILE -> VOLATILE
163         !isJvmField && it == ElementsModifier.STATIC -> JvmFieldModifier.STATIC
164         else -> null
165       }
166     }
167   }
168 
169   @OptIn(DelicateKotlinPoetApi::class)
170   private fun VariableElement.annotationSpecs(): List<AnnotationSpec> {
171     return filterOutNullabilityAnnotations(
172       annotationMirrors.map { AnnotationSpec.get(it) },
173     )
174   }
175 
176   private fun ExecutableElement.jvmModifiers(): Set<JvmMethodModifier> {
177     return modifiers.mapNotNullTo(mutableSetOf()) {
178       when (it) {
179         ElementsModifier.SYNCHRONIZED -> SYNCHRONIZED
180         ElementsModifier.STATIC -> STATIC
181         ElementsModifier.DEFAULT -> DEFAULT
182         else -> null
183       }
184     }
185   }
186 
187   @OptIn(DelicateKotlinPoetApi::class)
188   private fun ExecutableElement.annotationSpecs(): List<AnnotationSpec> {
189     return filterOutNullabilityAnnotations(
190       annotationMirrors.map { AnnotationSpec.get(it) },
191     )
192   }
193 
194   @OptIn(DelicateKotlinPoetApi::class)
195   private fun ExecutableElement.exceptionTypeNames(): List<TypeName> {
196     return thrownTypes.map { it.asTypeName() }
197   }
198 
199   override fun enumEntry(enumClassName: ClassName, memberName: String): EnumEntryData {
200     val enumType = lookupTypeElement(enumClassName)
201       ?: error("No type element found for: $enumClassName.")
202     val enumTypeAsType = enumType.asType()
203     val member = typeElementCache.getOrPut(enumClassName.nestedClass(memberName)) {
204       ElementFilter.typesIn(enumType.enclosedElements)
205         .asSequence()
206         .filter { types.isSubtype(enumTypeAsType, it.superclass) }
207         .find { it.simpleName.contentEquals(memberName) }.toOptional()
208     }.nullableValue
209     val declarationContainer = member?.getAnnotation(Metadata::class.java)?.toKmClass(lenient)
210 
211     val entry = ElementFilter.fieldsIn(enumType.enclosedElements)
212       .find { it.simpleName.contentEquals(memberName) }
213       ?: error("Could not find the enum entry for: $enumClassName")
214 
215     return EnumEntryData(
216       declarationContainer = declarationContainer,
217       annotations = entry.annotationSpecs(),
218     )
219   }
220 
221   private fun VariableElement.constantValue(): CodeBlock? {
222     return constantValue?.let(ClassInspectorUtil::codeLiteralOf)
223   }
224 
225   override fun methodExists(className: ClassName, methodSignature: JvmMethodSignature): Boolean {
226     return lookupMethod(className, methodSignature, ElementFilter::methodsIn) != null
227   }
228 
229   /**
230    * Detects whether [this] given method is overridden in [type].
231    *
232    * Adapted and simplified from AutoCommon's private
233    * [MoreElements.getLocalAndInheritedMethods] methods implementations for detecting
234    * overrides.
235    */
236   private fun ExecutableElement.isOverriddenIn(type: TypeElement): Boolean {
237     val methodMap = LinkedHashMultimap.create<String, ExecutableElement>()
238     type.getAllMethods(MoreElements.getPackage(type), methodMap)
239     // Find methods that are overridden using `Elements.overrides`. We reduce the performance
240     // impact by:
241     //   (a) grouping methods by name, since a method cannot override another method with a
242     //       different name. Since we know the target name, we just inspect the methods with
243     //       that name.
244     //   (b) making sure that methods in ancestor types precede those in descendant types,
245     //       which means we only have to check a method against the ones that follow it in
246     //       that order. Below, this means we just need to find the index of our target method
247     //       and compare against only preceding ones.
248     val methodList = methodMap.asMap()[simpleName.toString()]?.toList()
249       ?: return false
250     val signature = jvmMethodSignature(types)
251     return methodList.asSequence()
252       .filter { it.jvmMethodSignature(types) == signature }
253       .take(1)
254       .any { elements.overrides(this, it, type) }
255   }
256 
257   /**
258    * Add to [methodsAccumulator] the instance methods from [this] that are visible to code in
259    * the package [pkg]. This means all the instance methods from [this] itself and all
260    * instance methods it inherits from its ancestors, except private methods and
261    * package-private methods in other packages. This method does not take overriding into
262    * account, so it will add both an ancestor method and a descendant method that overrides
263    * it. [methodsAccumulator] is a multimap from a method name to all of the methods with
264    * that name, including methods that override or overload one another. Within those
265    * methods, those in ancestor types always precede those in descendant types.
266    *
267    * Adapted from AutoCommon's private [MoreElements.getLocalAndInheritedMethods] methods'
268    * implementations, before overridden methods are stripped.
269    */
270   private fun TypeElement.getAllMethods(
271     pkg: PackageElement,
272     methodsAccumulator: SetMultimap<String, ExecutableElement>,
273   ) {
274     for (superInterface in interfaces) {
275       MoreTypes.asTypeElement(superInterface).getAllMethods(pkg, methodsAccumulator)
276     }
277     if (superclass.kind != TypeKind.NONE) {
278       // Visit the superclass after superinterfaces so we will always see the implementation of a
279       // method after any interfaces that declared it.
280       MoreTypes.asTypeElement(superclass).getAllMethods(pkg, methodsAccumulator)
281     }
282     for (method in ElementFilter.methodsIn(enclosedElements)) {
283       if (ElementsModifier.STATIC !in method.modifiers &&
284         ElementsModifier.FINAL !in method.modifiers &&
285         ElementsModifier.PRIVATE !in method.modifiers &&
286         method.isVisibleFrom(pkg)
287       ) {
288         methodsAccumulator.put(method.simpleName.toString(), method)
289       }
290     }
291   }
292 
293   private fun ExecutableElement.isVisibleFrom(pkg: PackageElement): Boolean {
294     // We use Visibility.ofElement rather than [MoreElements.effectiveVisibilityOfElement]
295     // because it doesn't really matter whether the containing class is visible. If you
296     // inherit a public method then you have a public method, regardless of whether you
297     // inherit it from a public class.
298     return when (Visibility.ofElement(this)) {
299       Visibility.PRIVATE -> false
300       Visibility.DEFAULT -> MoreElements.getPackage(this) == pkg
301       else -> true
302     }
303   }
304 
305   @OptIn(DelicateKotlinPoetApi::class)
306   override fun containerData(
307     declarationContainer: KmDeclarationContainer,
308     className: ClassName,
309     parentClassName: ClassName?,
310   ): ContainerData {
311     val typeElement: TypeElement = lookupTypeElement(className) ?: error("No class found for: $className.")
312     val isCompanionObject = when (declarationContainer) {
313       is KmClass -> {
314         declarationContainer.kind == ClassKind.COMPANION_OBJECT
315       }
316       is KmPackage -> {
317         false
318       }
319       else -> TODO("Not implemented yet: ${declarationContainer.javaClass.simpleName}")
320     }
321 
322     // Should only be called if parentName has been null-checked
323     val classIfCompanion by lazy(NONE) {
324       if (isCompanionObject && parentClassName != null) {
325         lookupTypeElement(parentClassName)
326           ?: error("No class found for: $parentClassName.")
327       } else {
328         typeElement
329       }
330     }
331 
332     val propertyData = declarationContainer.properties
333       .asSequence()
334       .filter { it.kind.isDeclaration }
335       .associateWithTo(TreeMap(KM_PROPERTY_COMPARATOR)) { property ->
336         val isJvmField = ClassInspectorUtil.computeIsJvmField(
337           property = property,
338           classInspector = this,
339           isCompanionObject = isCompanionObject,
340           hasGetter = property.getterSignature != null,
341           hasSetter = property.setterSignature != null,
342           hasField = property.fieldSignature != null,
343         )
344 
345         val fieldData = property.fieldSignature?.let fieldDataLet@{ fieldSignature ->
346           // Check the field in the parent first. For const/static/jvmField elements, these only
347           // exist in the parent and we want to check that if necessary to avoid looking up a
348           // non-existent field in the companion.
349           val parentModifiers = if (isCompanionObject && parentClassName != null) {
350             classIfCompanion.lookupField(fieldSignature)?.jvmModifiers(isJvmField).orEmpty()
351           } else {
352             emptySet()
353           }
354 
355           val isStatic = JvmFieldModifier.STATIC in parentModifiers
356 
357           // TODO we looked up field once, let's reuse it
358           val classForOriginalField = typeElement.takeUnless {
359             isCompanionObject &&
360               (property.isConst || isJvmField || isStatic)
361           } ?: classIfCompanion
362 
363           val field = classForOriginalField.lookupField(fieldSignature)
364             ?: return@fieldDataLet FieldData.SYNTHETIC
365           val constant = if (property.hasConstant) {
366             val fieldWithConstant = classIfCompanion.takeIf { it != typeElement }?.let {
367               if (it.kind.isInterface) {
368                 field
369               } else {
370                 // const properties are relocated to the enclosing class
371                 it.lookupField(fieldSignature)
372                   ?: return@fieldDataLet FieldData.SYNTHETIC
373               }
374             } ?: field
375             fieldWithConstant.constantValue()
376           } else {
377             null
378           }
379 
380           val jvmModifiers = field.jvmModifiers(isJvmField) + parentModifiers
381 
382           FieldData(
383             annotations = field.annotationSpecs(),
384             isSynthetic = false,
385             jvmModifiers = jvmModifiers.filterNotTo(mutableSetOf()) {
386               // JvmField companion objects don't need JvmStatic, it's implicit
387               isCompanionObject && isJvmField && it == JvmFieldModifier.STATIC
388             },
389             constant = constant,
390           )
391         }
392 
393         val getterData = property.getterSignature?.let { getterSignature ->
394           val method = classIfCompanion.lookupMethod(getterSignature, ElementFilter::methodsIn)
395           method?.methodData(
396             typeElement = typeElement,
397             hasAnnotations = property.getter.hasAnnotations,
398             jvmInformationMethod = classIfCompanion.takeIf { it != typeElement }
399               ?.lookupMethod(getterSignature, ElementFilter::methodsIn)
400               ?: method,
401           )
402             ?: return@let MethodData.SYNTHETIC
403         }
404 
405         val setterData = property.setterSignature?.let { setterSignature ->
406           val method = classIfCompanion.lookupMethod(setterSignature, ElementFilter::methodsIn)
407           method?.methodData(
408             typeElement = typeElement,
409             hasAnnotations = property.setter?.hasAnnotations ?: false,
410             jvmInformationMethod = classIfCompanion.takeIf { it != typeElement }
411               ?.lookupMethod(setterSignature, ElementFilter::methodsIn)
412               ?: method,
413             knownIsOverride = getterData?.isOverride,
414           )
415             ?: return@let MethodData.SYNTHETIC
416         }
417 
418         val annotations = mutableListOf<AnnotationSpec>()
419         if (property.hasAnnotations) {
420           property.syntheticMethodForAnnotations?.let { annotationsHolderSignature ->
421             val method = typeElement.lookupMethod(annotationsHolderSignature, ElementFilter::methodsIn)
422               ?: return@let MethodData.SYNTHETIC
423             annotations += method.annotationSpecs()
424               // Cover for https://github.com/square/kotlinpoet/issues/1046
425               .filterNot { it.typeName == JAVA_DEPRECATED }
426           }
427         }
428 
429         // If a field is static in a companion object, remove the modifier and add the annotation
430         // directly on the top level. Otherwise this will generate `@field:JvmStatic`, which is
431         // not legal
432         var finalFieldData = fieldData
433         fieldData?.jvmModifiers?.let { modifiers ->
434           if (isCompanionObject && JvmFieldModifier.STATIC in modifiers) {
435             finalFieldData = fieldData.copy(
436               jvmModifiers = fieldData.jvmModifiers
437                 .filterNotTo(LinkedHashSet()) { it == JvmFieldModifier.STATIC },
438             )
439             annotations += AnnotationSpec.builder(
440               JVM_STATIC,
441             ).build()
442           }
443         }
444 
445         PropertyData(
446           annotations = annotations,
447           fieldData = finalFieldData,
448           getterData = getterData,
449           setterData = setterData,
450           isJvmField = isJvmField,
451         )
452       }
453 
454     val methodData = declarationContainer.functions
455       .associateWithTo(TreeMap(KM_FUNCTION_COMPARATOR)) { kmFunction ->
456         val signature = kmFunction.signature
457         if (signature != null) {
458           val method = typeElement.lookupMethod(signature, ElementFilter::methodsIn)
459           method?.methodData(
460             typeElement = typeElement,
461             hasAnnotations = kmFunction.hasAnnotations,
462             jvmInformationMethod = classIfCompanion.takeIf { it != typeElement }
463               ?.lookupMethod(signature, ElementFilter::methodsIn)
464               ?: method,
465           )
466             ?: return@associateWithTo MethodData.SYNTHETIC
467         } else {
468           MethodData.EMPTY
469         }
470       }
471 
472     when (declarationContainer) {
473       is KmClass -> {
474         val constructorData = declarationContainer.constructors
475           .associateWithTo(TreeMap(KM_CONSTRUCTOR_COMPARATOR)) { kmConstructor ->
476             if (declarationContainer.kind == ClassKind.ANNOTATION_CLASS || declarationContainer.isValue) {
477               //
478               // Annotations are interfaces in bytecode, but kotlin metadata will still report a
479               // constructor signature
480               //
481               // Inline classes have no constructors at runtime
482               //
483               return@associateWithTo ConstructorData.EMPTY
484             }
485             val signature = kmConstructor.signature
486             if (signature != null) {
487               val constructor = typeElement.lookupMethod(signature, ElementFilter::constructorsIn)
488                 ?: return@associateWithTo ConstructorData.EMPTY
489               ConstructorData(
490                 annotations = if (kmConstructor.hasAnnotations) {
491                   constructor.annotationSpecs()
492                 } else {
493                   emptyList()
494                 },
495                 parameterAnnotations = constructor.parameters.indexedAnnotationSpecs(),
496                 isSynthetic = false,
497                 jvmModifiers = constructor.jvmModifiers(),
498                 exceptions = constructor.exceptionTypeNames(),
499               )
500             } else {
501               ConstructorData.EMPTY
502             }
503           }
504         return ClassData(
505           declarationContainer = declarationContainer,
506           className = className,
507           annotations = if (declarationContainer.hasAnnotations) {
508             ClassInspectorUtil.createAnnotations {
509               addAll(typeElement.annotationMirrors.map { AnnotationSpec.get(it) })
510             }
511           } else {
512             emptyList()
513           },
514           properties = propertyData,
515           constructors = constructorData,
516           methods = methodData,
517         )
518       }
519       is KmPackage -> {
520         // There's no flag for checking if there are annotations, so we just eagerly check in this
521         // case. All annotations on this class are file: site targets in source. This includes
522         // @JvmName.
523         var jvmName: String? = null
524         val fileAnnotations = ClassInspectorUtil.createAnnotations(FILE) {
525           addAll(
526             typeElement.annotationMirrors.map {
527               if (it.annotationType == jvmNameType) {
528                 val nameValue = requireNotNull(it.elementValues[jvmNameName]) {
529                   "No name property found on $it"
530                 }
531                 jvmName = nameValue.value as String
532               }
533               AnnotationSpec.get(it)
534             },
535           )
536         }
537         return FileData(
538           declarationContainer = declarationContainer,
539           annotations = fileAnnotations,
540           properties = propertyData,
541           methods = methodData,
542           className = className,
543           jvmName = jvmName,
544         )
545       }
546       else -> TODO("Not implemented yet: ${declarationContainer.javaClass.simpleName}")
547     }
548   }
549 
550   private fun List<VariableElement>.indexedAnnotationSpecs(): Map<Int, Collection<AnnotationSpec>> {
551     return withIndex().associate { (index, parameter) ->
552       index to ClassInspectorUtil.createAnnotations { addAll(parameter.annotationSpecs()) }
553     }
554   }
555 
556   private fun ExecutableElement.methodData(
557     typeElement: TypeElement,
558     hasAnnotations: Boolean,
559     jvmInformationMethod: ExecutableElement = this,
560     knownIsOverride: Boolean? = null,
561   ): MethodData {
562     return MethodData(
563       annotations = if (hasAnnotations) annotationSpecs() else emptyList(),
564       parameterAnnotations = parameters.indexedAnnotationSpecs(),
565       isSynthetic = false,
566       jvmModifiers = jvmInformationMethod.jvmModifiers(),
567       isOverride = knownIsOverride ?: isOverriddenIn(typeElement),
568       exceptions = exceptionTypeNames(),
569     )
570   }
571 
572   public companion object {
573     /**
574      * @param lenient see docs on [KotlinClassMetadata.readStrict] and [KotlinClassMetadata.readLenient] for more details.
575      * @return an [Elements]-based implementation of [ClassInspector].
576      */
577     @JvmStatic
578     public fun create(lenient: Boolean, elements: Elements, types: Types): ClassInspector {
579       return ElementsClassInspector(lenient, elements, types)
580     }
581 
582     private val JVM_STATIC = JvmStatic::class.asClassName()
583   }
584 }
585