1 /* <lambda>null2 * Copyright 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 androidx.appfunctions.compiler.core 18 19 import com.google.devtools.ksp.symbol.KSClassDeclaration 20 import com.google.devtools.ksp.symbol.KSTypeArgument 21 import com.google.devtools.ksp.symbol.KSTypeParameter 22 import com.google.devtools.ksp.symbol.KSTypeReference 23 24 /** 25 * Represents a class annotated with [androidx.appfunctions.AppFunctionSerializable] that is 26 * parameterized. 27 * 28 * When the serializable has type parameter (e.g. `SetField<T>`), the type arguments must be 29 * provided as [arguments] to resolve the actual type reference. 30 */ 31 class AnnotatedParameterizedAppFunctionSerializable( 32 private val appFunctionSerializableClass: KSClassDeclaration, 33 private val arguments: List<KSTypeArgument> 34 ) : AnnotatedAppFunctionSerializable(appFunctionSerializableClass) { 35 /** A map of type parameter name to its parameterized type. */ 36 val typeParameterMap: Map<String, KSTypeReference> = buildMap { 37 for ((index, typeParameter) in appFunctionSerializableClass.typeParameters.withIndex()) { 38 val typeParameterName = typeParameter.name.asString() 39 val actualType = 40 arguments.getOrNull(index)?.type 41 ?: throw ProcessingException( 42 "Missing type argument for $typeParameterName", 43 typeParameter 44 ) 45 this[typeParameterName] = actualType 46 } 47 } 48 49 /** 50 * The qualified name of the class being annotated with AppFunctionSerializable with the 51 * parameterized type information included as a suffix. 52 */ 53 override val qualifiedName: String by lazy { 54 val originalQualifiedName = super.qualifiedName 55 buildString { 56 append(originalQualifiedName) 57 58 for ((index, entry) in typeParameterMap.entries.withIndex()) { 59 if (index == 0) { 60 append("<") 61 } 62 63 val (_, typeRef) = entry 64 append(typeRef.toTypeName()) 65 66 if (index != typeParameterMap.size - 1) { 67 append(",") 68 } else { 69 append(">") 70 } 71 } 72 } 73 } 74 75 /** 76 * Returns the annotated class's properties as defined in its primary constructor. 77 * 78 * When the property is generic type, it will try to resolve the actual type reference from 79 * [arguments]. 80 */ 81 override fun getProperties(): List<AppFunctionPropertyDeclaration> { 82 return checkNotNull(appFunctionSerializableClass.primaryConstructor).parameters.map { 83 valueParameter -> 84 val valueTypeDeclaration = valueParameter.type.resolve().declaration 85 if (valueTypeDeclaration is KSTypeParameter) { 86 val actualType = 87 typeParameterMap[valueTypeDeclaration.name.asString()] 88 ?: throw ProcessingException( 89 "Unable to resolve actual type", 90 valueParameter 91 ) 92 AppFunctionPropertyDeclaration( 93 checkNotNull(valueParameter.name).asString(), 94 actualType 95 ) 96 } else { 97 AppFunctionPropertyDeclaration(valueParameter) 98 } 99 } 100 } 101 } 102