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