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