1 /* <lambda>null2 * Copyright (C) 2025 The Android Open Source Project 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 * http://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 17 package com.android.tools.metalava.model.turbine 18 19 import com.android.tools.metalava.model.AnnotationItem 20 import com.android.tools.metalava.model.BoundsTypeItem 21 import com.android.tools.metalava.model.CallableItem 22 import com.android.tools.metalava.model.ClassItem 23 import com.android.tools.metalava.model.ClassKind 24 import com.android.tools.metalava.model.ClassOrigin 25 import com.android.tools.metalava.model.DefaultTypeParameterList 26 import com.android.tools.metalava.model.ExceptionTypeItem 27 import com.android.tools.metalava.model.FixedFieldValue 28 import com.android.tools.metalava.model.ItemDocumentation.Companion.toItemDocumentationFactory 29 import com.android.tools.metalava.model.ItemDocumentationFactory 30 import com.android.tools.metalava.model.ModifierFlags.Companion.ABSTRACT 31 import com.android.tools.metalava.model.ModifierFlags.Companion.DEFAULT 32 import com.android.tools.metalava.model.ModifierFlags.Companion.FINAL 33 import com.android.tools.metalava.model.ModifierFlags.Companion.NATIVE 34 import com.android.tools.metalava.model.ModifierFlags.Companion.PRIVATE 35 import com.android.tools.metalava.model.ModifierFlags.Companion.PROTECTED 36 import com.android.tools.metalava.model.ModifierFlags.Companion.PUBLIC 37 import com.android.tools.metalava.model.ModifierFlags.Companion.SEALED 38 import com.android.tools.metalava.model.ModifierFlags.Companion.STATIC 39 import com.android.tools.metalava.model.ModifierFlags.Companion.STRICT_FP 40 import com.android.tools.metalava.model.ModifierFlags.Companion.SYNCHRONIZED 41 import com.android.tools.metalava.model.ModifierFlags.Companion.TRANSIENT 42 import com.android.tools.metalava.model.ModifierFlags.Companion.VARARG 43 import com.android.tools.metalava.model.ModifierFlags.Companion.VOLATILE 44 import com.android.tools.metalava.model.MutableModifierList 45 import com.android.tools.metalava.model.ParameterItem 46 import com.android.tools.metalava.model.TypeParameterList 47 import com.android.tools.metalava.model.TypeParameterListAndFactory 48 import com.android.tools.metalava.model.VisibilityLevel 49 import com.android.tools.metalava.model.addDefaultRetentionPolicyAnnotation 50 import com.android.tools.metalava.model.createMutableModifiers 51 import com.android.tools.metalava.model.hasAnnotation 52 import com.android.tools.metalava.model.item.DefaultClassItem 53 import com.android.tools.metalava.model.item.DefaultTypeParameterItem 54 import com.android.tools.metalava.model.item.FieldValue 55 import com.android.tools.metalava.model.item.ParameterDefaultValue 56 import com.android.tools.metalava.model.type.MethodFingerprint 57 import com.android.tools.metalava.reporter.FileLocation 58 import com.google.common.collect.ImmutableList 59 import com.google.common.collect.ImmutableMap 60 import com.google.turbine.binder.bound.SourceTypeBoundClass 61 import com.google.turbine.binder.bound.TypeBoundClass 62 import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo 63 import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo 64 import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo 65 import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo 66 import com.google.turbine.binder.sym.ClassSymbol 67 import com.google.turbine.binder.sym.TyVarSymbol 68 import com.google.turbine.model.TurbineFlag 69 import com.google.turbine.model.TurbineTyKind 70 import com.google.turbine.tree.Tree 71 import com.google.turbine.tree.Tree.Anno 72 import com.google.turbine.tree.Tree.AnnoExpr 73 import com.google.turbine.tree.Tree.Expression 74 import com.google.turbine.tree.Tree.Literal 75 import com.google.turbine.tree.Tree.MethDecl 76 import com.google.turbine.tree.Tree.TyDecl 77 import com.google.turbine.tree.Tree.VarDecl 78 import com.google.turbine.type.AnnoInfo 79 import com.google.turbine.type.Type 80 81 /** 82 * Responsible for creating [ClassItem]s from either source or binary [ClassSymbol] and 83 * [TypeBoundClass] pairs. 84 * 85 * @param globalContext provides access to various pieces of data that apply across all classes. 86 * @param classSymbol the unique identifier for the [TypeBoundClass]. 87 * @param typeBoundClass the definition of the class as recorded by Turbine. 88 */ 89 internal class TurbineClassBuilder( 90 private val globalContext: TurbineGlobalContext, 91 private val classSymbol: ClassSymbol, 92 private val typeBoundClass: TypeBoundClass, 93 ) : TurbineGlobalContext by globalContext { 94 /** The [SourceTypeBoundClass] if this is a source class. */ 95 private val sourceTypeBoundClass = typeBoundClass as? SourceTypeBoundClass 96 97 /** 98 * The [TurbineFieldResolver] used for resolving [Tree.ConstVarName] to 99 * [TypeBoundClass.FieldInfo]. 100 */ 101 private var fieldResolver: TurbineFieldResolver? 102 103 init { 104 if (sourceTypeBoundClass == null) { 105 // Only source classes need to resolve fields. 106 fieldResolver = null 107 } else { 108 // Source files need 109 fieldResolver = createFieldResolver(classSymbol, sourceTypeBoundClass) 110 } 111 } 112 113 /** 114 * Create a [ClassItem] for the [classSymbol]/[typeBoundClass] pair. 115 * 116 * @param containingClassItem the containing [DefaultClassItem] to which the created [ClassItem] 117 * will belong, if any. 118 * @param enclosingClassTypeItemFactory the [TurbineTypeItemFactory] that is used to create 119 * [TypeItem]s and tracks the in scope type parameters. 120 */ 121 internal fun createClass( 122 containingClassItem: DefaultClassItem?, 123 enclosingClassTypeItemFactory: TurbineTypeItemFactory, 124 origin: ClassOrigin, 125 ): ClassItem { 126 val decl = sourceTypeBoundClass?.decl() 127 128 // Get the package item 129 val pkgName = classSymbol.dotSeparatedPackageName 130 val pkgItem = codebase.findOrCreatePackage(pkgName) 131 132 // Create the sourcefile 133 val sourceFile = 134 if (sourceTypeBoundClass != null) { 135 sourceFileCache.turbineSourceFile(sourceTypeBoundClass.source()) 136 } else null 137 val fileLocation = 138 when { 139 sourceFile != null -> TurbineFileLocation.forTree(sourceFile, decl) 140 containingClassItem != null -> 141 TurbineFileLocation.forTree(containingClassItem, decl) 142 else -> FileLocation.UNKNOWN 143 } 144 145 // Create class 146 val qualifiedName = classSymbol.qualifiedName 147 val documentation = javadoc(decl) 148 val modifierItem = 149 createModifiers( 150 typeBoundClass.access(), 151 typeBoundClass.annotations(), 152 ) 153 val (typeParameters, classTypeItemFactory) = 154 createTypeParameters( 155 typeBoundClass.typeParameterTypes(), 156 enclosingClassTypeItemFactory, 157 "class $qualifiedName", 158 ) 159 val classKind = getClassKind(typeBoundClass.kind()) 160 161 modifierItem.setSynchronized(false) // A class can not be synchronized in java 162 163 if (classKind == ClassKind.ANNOTATION_TYPE) { 164 if (!modifierItem.hasAnnotation(AnnotationItem::isRetention)) { 165 modifierItem.addDefaultRetentionPolicyAnnotation(codebase, isKotlin = false) 166 } 167 } 168 169 // Set up the SuperClass 170 val superClassType = 171 when (classKind) { 172 // Normal classes and enums have a non-null super class type. 173 ClassKind.CLASS, 174 ClassKind.ENUM -> 175 typeBoundClass.superClassType()?.let { 176 classTypeItemFactory.getSuperClassType(it) 177 } 178 // Interfaces and annotations (which are a form of interface) do not. 179 ClassKind.INTERFACE, 180 ClassKind.ANNOTATION_TYPE -> null 181 } 182 183 // Set interface types 184 val interfaceTypes = 185 typeBoundClass.interfaceTypes().map { classTypeItemFactory.getInterfaceType(it) } 186 187 val classItem = 188 itemFactory.createClassItem( 189 fileLocation = fileLocation, 190 modifiers = modifierItem, 191 documentationFactory = getCommentedDoc(documentation), 192 source = sourceFile, 193 classKind = classKind, 194 containingClass = containingClassItem, 195 containingPackage = pkgItem, 196 qualifiedName = qualifiedName, 197 typeParameterList = typeParameters, 198 origin = origin, 199 superClassType = superClassType, 200 interfaceTypes = interfaceTypes, 201 ) 202 203 // Create fields 204 createFields(classItem, typeBoundClass.fields(), classTypeItemFactory) 205 206 // Create methods 207 createMethods(classItem, typeBoundClass.methods(), classTypeItemFactory) 208 209 // Create constructors 210 createConstructors(classItem, typeBoundClass.methods(), classTypeItemFactory) 211 212 // Create InnerClasses. 213 val children = typeBoundClass.children() 214 createNestedClasses(classItem, children.values.asList(), classTypeItemFactory) 215 216 return classItem 217 } 218 219 private fun createModifiers(flag: Int, annoInfos: List<AnnoInfo>): MutableModifierList { 220 val annotations = annotationFactory.createAnnotations(annoInfos) 221 val modifierItem = 222 when (flag) { 223 0 -> { // No Modifier. Default modifier is PACKAGE_PRIVATE in such case 224 createMutableModifiers( 225 visibility = VisibilityLevel.PACKAGE_PRIVATE, 226 annotations = annotations, 227 ) 228 } 229 else -> { 230 createMutableModifiers(computeFlag(flag), annotations) 231 } 232 } 233 modifierItem.setDeprecated(isDeprecated(annotations)) 234 return modifierItem 235 } 236 237 /** 238 * Given flag value corresponding to Turbine modifiers compute the equivalent flag in Metalava. 239 */ 240 private fun computeFlag(flag: Int): Int { 241 // If no visibility flag is provided, result remains 0, implying a 'package-private' default 242 // state. 243 var result = 0 244 245 if (flag and TurbineFlag.ACC_STATIC != 0) { 246 result = result or STATIC 247 } 248 if (flag and TurbineFlag.ACC_ABSTRACT != 0) { 249 result = result or ABSTRACT 250 } 251 if (flag and TurbineFlag.ACC_FINAL != 0) { 252 result = result or FINAL 253 } 254 if (flag and TurbineFlag.ACC_NATIVE != 0) { 255 result = result or NATIVE 256 } 257 if (flag and TurbineFlag.ACC_SYNCHRONIZED != 0) { 258 result = result or SYNCHRONIZED 259 } 260 if (flag and TurbineFlag.ACC_STRICT != 0) { 261 result = result or STRICT_FP 262 } 263 if (flag and TurbineFlag.ACC_TRANSIENT != 0) { 264 result = result or TRANSIENT 265 } 266 if (flag and TurbineFlag.ACC_VOLATILE != 0) { 267 result = result or VOLATILE 268 } 269 if (flag and TurbineFlag.ACC_DEFAULT != 0) { 270 result = result or DEFAULT 271 } 272 if (flag and TurbineFlag.ACC_SEALED != 0) { 273 result = result or SEALED 274 } 275 if (flag and TurbineFlag.ACC_VARARGS != 0) { 276 result = result or VARARG 277 } 278 279 // Visibility Modifiers 280 if (flag and TurbineFlag.ACC_PUBLIC != 0) { 281 result = result or PUBLIC 282 } 283 if (flag and TurbineFlag.ACC_PRIVATE != 0) { 284 result = result or PRIVATE 285 } 286 if (flag and TurbineFlag.ACC_PROTECTED != 0) { 287 result = result or PROTECTED 288 } 289 290 return result 291 } 292 293 private fun isDeprecated(annotations: List<AnnotationItem>?): Boolean { 294 return annotations?.any { it.qualifiedName == "java.lang.Deprecated" } ?: false 295 } 296 297 private fun getClassKind(type: TurbineTyKind): ClassKind { 298 return when (type) { 299 TurbineTyKind.INTERFACE -> ClassKind.INTERFACE 300 TurbineTyKind.ENUM -> ClassKind.ENUM 301 TurbineTyKind.ANNOTATION -> ClassKind.ANNOTATION_TYPE 302 else -> ClassKind.CLASS 303 } 304 } 305 306 private fun createTypeParameters( 307 tyParams: ImmutableMap<TyVarSymbol, TyVarInfo>, 308 enclosingClassTypeItemFactory: TurbineTypeItemFactory, 309 description: String, 310 ): TypeParameterListAndFactory<TurbineTypeItemFactory> { 311 312 if (tyParams.isEmpty()) 313 return TypeParameterListAndFactory( 314 TypeParameterList.NONE, 315 enclosingClassTypeItemFactory 316 ) 317 318 // Create a list of [TypeParameterItem]s from turbine specific classes. 319 return DefaultTypeParameterList.createTypeParameterItemsAndFactory( 320 enclosingClassTypeItemFactory, 321 description, 322 tyParams.toList(), 323 { (sym, tyParam) -> createTypeParameter(sym, tyParam) }, 324 { typeItemFactory, (_, tParam) -> createTypeParameterBounds(tParam, typeItemFactory) }, 325 ) 326 } 327 328 /** 329 * Create the [DefaultTypeParameterItem] without any bounds and register it so that any uses of 330 * it within the type bounds, e.g. `<E extends Enum<E>>`, or from other type parameters within 331 * the same [TypeParameterList] can be resolved. 332 */ 333 private fun createTypeParameter(sym: TyVarSymbol, param: TyVarInfo): DefaultTypeParameterItem { 334 val modifiers = createModifiers(0, param.annotations()) 335 val typeParamItem = 336 itemFactory.createTypeParameterItem( 337 modifiers, 338 name = sym.name(), 339 // Java does not supports reified generics 340 isReified = false, 341 ) 342 return typeParamItem 343 } 344 345 /** Create the bounds of a [DefaultTypeParameterItem]. */ 346 private fun createTypeParameterBounds( 347 param: TyVarInfo, 348 typeItemFactory: TurbineTypeItemFactory, 349 ): List<BoundsTypeItem> { 350 val typeBounds = mutableListOf<BoundsTypeItem>() 351 val upperBounds = param.upperBound() 352 353 upperBounds.bounds().mapTo(typeBounds) { typeItemFactory.getBoundsType(it) } 354 param.lowerBound()?.let { typeBounds.add(typeItemFactory.getBoundsType(it)) } 355 356 return typeBounds.toList() 357 } 358 359 /** This method sets up the nested class hierarchy. */ 360 private fun createNestedClasses( 361 classItem: DefaultClassItem, 362 nestedClasses: ImmutableList<ClassSymbol>, 363 enclosingClassTypeItemFactory: TurbineTypeItemFactory, 364 ) { 365 for (nestedClassSymbol in nestedClasses) { 366 val nestedTypeBoundClass = typeBoundClassForSymbol(nestedClassSymbol) 367 val nestedClassBuilder = 368 TurbineClassBuilder( 369 globalContext = globalContext, 370 classSymbol = nestedClassSymbol, 371 typeBoundClass = nestedTypeBoundClass, 372 ) 373 nestedClassBuilder.createClass( 374 containingClassItem = classItem, 375 enclosingClassTypeItemFactory = enclosingClassTypeItemFactory, 376 origin = classItem.origin, 377 ) 378 } 379 } 380 381 /** This method creates and sets the fields of a class */ 382 private fun createFields( 383 classItem: DefaultClassItem, 384 fields: ImmutableList<FieldInfo>, 385 typeItemFactory: TurbineTypeItemFactory, 386 ) { 387 for (field in fields) { 388 val flags = field.access() 389 val decl = field.decl() 390 val fieldModifierItem = 391 createModifiers( 392 flags, 393 field.annotations(), 394 ) 395 val isEnumConstant = (flags and TurbineFlag.ACC_ENUM) != 0 396 val fieldValue = createInitialValue(field) 397 val type = 398 typeItemFactory.getFieldType( 399 underlyingType = field.type(), 400 itemAnnotations = fieldModifierItem.annotations(), 401 isEnumConstant = isEnumConstant, 402 isFinal = fieldModifierItem.isFinal(), 403 isInitialValueNonNull = { 404 // The initial value is non-null if the value is a literal which is not 405 // null. 406 fieldValue.initialValue(false) != null 407 } 408 ) 409 410 val documentation = javadoc(decl) 411 val fieldItem = 412 itemFactory.createFieldItem( 413 fileLocation = TurbineFileLocation.forTree(classItem, decl), 414 modifiers = fieldModifierItem, 415 documentationFactory = getCommentedDoc(documentation), 416 name = field.name(), 417 containingClass = classItem, 418 type = type, 419 isEnumConstant = isEnumConstant, 420 fieldValue = fieldValue, 421 ) 422 423 classItem.addField(fieldItem) 424 } 425 } 426 427 private fun createMethods( 428 classItem: DefaultClassItem, 429 methods: List<MethodInfo>, 430 enclosingClassTypeItemFactory: TurbineTypeItemFactory, 431 ) { 432 for (method in methods) { 433 // Ignore constructors. 434 if (method.sym().name() == "<init>") continue 435 436 val decl: MethDecl? = method.decl() 437 val methodModifierItem = 438 createModifiers( 439 method.access(), 440 method.annotations(), 441 ) 442 val name = method.name() 443 val (typeParams, methodTypeItemFactory) = 444 createTypeParameters( 445 method.tyParams(), 446 enclosingClassTypeItemFactory, 447 name, 448 ) 449 val documentation = javadoc(decl) 450 val defaultValueExpr = getAnnotationDefaultExpression(method) 451 val defaultValue = 452 method.defaultValue()?.let { defaultConst -> 453 TurbineValue(defaultConst, defaultValueExpr, fieldResolver) 454 .getSourceForMethodDefault() 455 } 456 ?: "" 457 458 val parameters = method.parameters() 459 val fingerprint = MethodFingerprint(name, parameters.size) 460 val isAnnotationElement = classItem.isAnnotationType() && !methodModifierItem.isStatic() 461 val returnType = 462 methodTypeItemFactory.getMethodReturnType( 463 underlyingReturnType = method.returnType(), 464 itemAnnotations = methodModifierItem.annotations(), 465 fingerprint = fingerprint, 466 isAnnotationElement = isAnnotationElement, 467 ) 468 469 val methodItem = 470 itemFactory.createMethodItem( 471 fileLocation = TurbineFileLocation.forTree(classItem, decl), 472 modifiers = methodModifierItem, 473 documentationFactory = getCommentedDoc(documentation), 474 name = name, 475 containingClass = classItem, 476 typeParameterList = typeParams, 477 returnType = returnType, 478 parameterItemsFactory = { containingCallable -> 479 createParameters( 480 containingCallable, 481 decl?.params(), 482 parameters, 483 methodTypeItemFactory, 484 ) 485 }, 486 throwsTypes = getThrowsList(method.exceptions(), methodTypeItemFactory), 487 annotationDefault = defaultValue, 488 ) 489 490 // Ignore enum synthetic methods. 491 if (methodItem.isEnumSyntheticMethod()) continue 492 493 classItem.addMethod(methodItem) 494 } 495 } 496 497 private fun createParameters( 498 containingCallable: CallableItem, 499 parameterDecls: List<VarDecl>?, 500 parameters: List<ParamInfo>, 501 typeItemFactory: TurbineTypeItemFactory, 502 ): List<ParameterItem> { 503 val fingerprint = MethodFingerprint(containingCallable.name(), parameters.size) 504 // Some parameters in [parameters] are implicit parameters that do not have a corresponding 505 // entry in the [parameterDecls] list. The number of implicit parameters is the total 506 // number of [parameters] minus the number of declared parameters [parameterDecls]. The 507 // implicit parameters are always at the beginning so the offset from the declared parameter 508 // in [parameterDecls] to the corresponding parameter in [parameters] is simply the number 509 // of the implicit parameters. 510 val declaredParameterOffset = parameters.size - (parameterDecls?.size ?: 0) 511 return parameters.mapIndexed { idx, parameter -> 512 val parameterModifierItem = 513 createModifiers(parameter.access(), parameter.annotations()).toImmutable() 514 val type = 515 typeItemFactory.getMethodParameterType( 516 underlyingParameterType = parameter.type(), 517 itemAnnotations = parameterModifierItem.annotations(), 518 fingerprint = fingerprint, 519 parameterIndex = idx, 520 isVarArg = parameterModifierItem.isVarArg(), 521 ) 522 // Get the [Tree.VarDecl] corresponding to the [ParamInfo], if available. 523 val decl = 524 if (parameterDecls != null && idx >= declaredParameterOffset) 525 parameterDecls.get(idx - declaredParameterOffset) 526 else null 527 528 val fileLocation = 529 TurbineFileLocation.forTree(containingCallable.containingClass(), decl) 530 val parameterItem = 531 itemFactory.createParameterItem( 532 fileLocation = fileLocation, 533 modifiers = parameterModifierItem, 534 name = parameter.name(), 535 publicNameProvider = { null }, 536 containingCallable = containingCallable, 537 parameterIndex = idx, 538 type = type, 539 defaultValueFactory = { ParameterDefaultValue.NONE }, 540 ) 541 parameterItem 542 } 543 } 544 545 private fun createConstructors( 546 classItem: DefaultClassItem, 547 methods: List<MethodInfo>, 548 enclosingClassTypeItemFactory: TurbineTypeItemFactory, 549 ) { 550 for (constructor in methods) { 551 // Skip real methods. 552 if (constructor.sym().name() != "<init>") continue 553 554 val decl: MethDecl? = constructor.decl() 555 val constructorModifierItem = 556 createModifiers( 557 constructor.access(), 558 constructor.annotations(), 559 ) 560 val (typeParams, constructorTypeItemFactory) = 561 createTypeParameters( 562 constructor.tyParams(), 563 enclosingClassTypeItemFactory, 564 constructor.name(), 565 ) 566 val isImplicitDefaultConstructor = 567 (constructor.access() and TurbineFlag.ACC_SYNTH_CTOR) != 0 568 val name = classItem.simpleName() 569 val documentation = javadoc(decl) 570 val constructorItem = 571 itemFactory.createConstructorItem( 572 fileLocation = TurbineFileLocation.forTree(classItem, decl), 573 modifiers = constructorModifierItem, 574 documentationFactory = getCommentedDoc(documentation), 575 // Turbine's Binder gives return type of constructors as void but the 576 // model expects it to the type of object being created. So, use the 577 // containing [ClassItem]'s type as the constructor return type. 578 name = name, 579 containingClass = classItem, 580 typeParameterList = typeParams, 581 returnType = classItem.type(), 582 parameterItemsFactory = { constructorItem -> 583 createParameters( 584 constructorItem, 585 decl?.params(), 586 constructor.parameters(), 587 constructorTypeItemFactory, 588 ) 589 }, 590 throwsTypes = 591 getThrowsList(constructor.exceptions(), constructorTypeItemFactory), 592 implicitConstructor = isImplicitDefaultConstructor, 593 ) 594 595 classItem.addConstructor(constructorItem) 596 } 597 } 598 599 private fun javadoc(item: TyDecl?): String { 600 if (!allowReadingComments) return "" 601 return item?.javadoc() ?: "" 602 } 603 604 private fun javadoc(item: VarDecl?): String { 605 if (!allowReadingComments) return "" 606 return item?.javadoc() ?: "" 607 } 608 609 private fun javadoc(item: MethDecl?): String { 610 if (!allowReadingComments) return "" 611 return item?.javadoc() ?: "" 612 } 613 614 private fun getThrowsList( 615 throwsTypes: List<Type>, 616 enclosingTypeItemFactory: TurbineTypeItemFactory 617 ): List<ExceptionTypeItem> { 618 return throwsTypes.map { type -> enclosingTypeItemFactory.getExceptionType(type) } 619 } 620 621 private fun getCommentedDoc(doc: String): ItemDocumentationFactory { 622 return buildString { 623 if (doc != "") { 624 append("/**") 625 append(doc) 626 append("*/") 627 } 628 } 629 .toItemDocumentationFactory() 630 } 631 632 private fun createInitialValue(field: FieldInfo): FieldValue { 633 val optExpr = field.decl()?.init() 634 val expr = if (optExpr != null && optExpr.isPresent()) optExpr.get() else null 635 val constantValue = field.value()?.getValue() 636 637 val initialValueWithoutRequiredConstant = 638 when { 639 constantValue != null -> constantValue 640 expr == null -> null 641 else -> 642 when (expr.kind()) { 643 Tree.Kind.LITERAL -> { 644 (expr as Literal).value().underlyingValue 645 } 646 // Class Type 647 Tree.Kind.CLASS_LITERAL -> { 648 expr 649 } 650 else -> { 651 null 652 } 653 } 654 } 655 656 return FixedFieldValue(constantValue, initialValueWithoutRequiredConstant) 657 } 658 659 /** 660 * Extracts the expression corresponding to the default value of a given annotation method. If 661 * the method does not have a default value, returns null. 662 */ 663 private fun getAnnotationDefaultExpression(method: MethodInfo) = 664 method.decl()?.defaultValue()?.orElse(null)?.let { defaultTree -> 665 666 // Turbine stores the default value as a Tree not an Expression so that it can use an 667 // Anno class (which is not an Expression). It could wrap the Anno in an AnnoExpr but 668 // does not, presumably as an optimization. However, this does wrap it in an AnnoExpr 669 // as it allows for more consistent handling. 670 when (defaultTree) { 671 is Expression -> defaultTree 672 is Anno -> AnnoExpr(defaultTree.position(), defaultTree) 673 else -> error("unknown default value type (${defaultTree.javaClass}: $defaultTree") 674 } 675 } 676 } 677