1 /*
2  * Copyright (C) 2024 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.snapshot
18 
19 import com.android.tools.metalava.model.ArrayTypeItem
20 import com.android.tools.metalava.model.ClassItem
21 import com.android.tools.metalava.model.ClassTypeItem
22 import com.android.tools.metalava.model.Codebase
23 import com.android.tools.metalava.model.LambdaTypeItem
24 import com.android.tools.metalava.model.PrimitiveTypeItem
25 import com.android.tools.metalava.model.TypeItem
26 import com.android.tools.metalava.model.TypeModifiers
27 import com.android.tools.metalava.model.TypeParameterScope
28 import com.android.tools.metalava.model.TypeTransformer
29 import com.android.tools.metalava.model.VariableTypeItem
30 import com.android.tools.metalava.model.WildcardTypeItem
31 import com.android.tools.metalava.model.type.ContextNullability
32 import com.android.tools.metalava.model.type.DefaultArrayTypeItem
33 import com.android.tools.metalava.model.type.DefaultClassTypeItem
34 import com.android.tools.metalava.model.type.DefaultLambdaTypeItem
35 import com.android.tools.metalava.model.type.DefaultPrimitiveTypeItem
36 import com.android.tools.metalava.model.type.DefaultTypeItemFactory
37 import com.android.tools.metalava.model.type.DefaultTypeModifiers
38 import com.android.tools.metalava.model.type.DefaultVariableTypeItem
39 import com.android.tools.metalava.model.type.DefaultWildcardTypeItem
40 
41 /**
42  * A [DefaultTypeItemFactory] whose underlying type is another model's [TypeItem] that this will
43  * snapshot.
44  *
45  * TODO: Optimize by reusing them where possible as they are immutable.
46  */
47 internal class SnapshotTypeItemFactory(
48     private val codebase: Codebase,
49     typeParameterScope: TypeParameterScope = TypeParameterScope.empty,
50 ) : DefaultTypeItemFactory<TypeItem, SnapshotTypeItemFactory>(typeParameterScope), TypeTransformer {
51 
52     /** Construct a [SnapshotTypeItemFactory] suitable for creating types within [classItem]. */
fromnull53     fun from(classItem: ClassItem?): SnapshotTypeItemFactory {
54         val scope = TypeParameterScope.from(classItem)
55         return if (scope.isEmpty()) this else SnapshotTypeItemFactory(codebase, scope)
56     }
57 
selfnull58     override fun self() = this
59 
60     override fun createNestedFactory(scope: TypeParameterScope) =
61         SnapshotTypeItemFactory(codebase, scope)
62 
63     override fun getType(
64         underlyingType: TypeItem,
65         contextNullability: ContextNullability,
66         isVarArg: Boolean
67     ) = underlyingType.transform(this)
68 
69     /**
70      * Take a snapshot of the [TypeModifiers].
71      *
72      * Only the [TypeModifiers.annotations] is model and [Codebase] dependent. All the other parts
73      * are model independent with no connection to a specific [Codebase]. So, this is reused as is
74      * if there are no [TypeModifiers.annotations].
75      */
76     private fun TypeModifiers.snapshot() =
77         if (annotations.isEmpty()) {
78             this
79         } else {
80             DefaultTypeModifiers(
<lambda>null81                 annotations.map { it.snapshot(codebase) },
82                 nullability,
83             )
84         }
85 
transformnull86     override fun transform(typeItem: ArrayTypeItem) =
87         DefaultArrayTypeItem(
88             typeItem.modifiers.snapshot(),
89             typeItem.componentType.transform(this),
90             typeItem.isVarargs,
91         )
92 
93     override fun transform(typeItem: ClassTypeItem) =
94         DefaultClassTypeItem(
95             codebase,
96             typeItem.modifiers.snapshot(),
97             typeItem.qualifiedName,
98             typeItem.arguments.map { it.transform(this) },
99             typeItem.outerClassType?.transform(this),
100         )
101 
transformnull102     override fun transform(typeItem: LambdaTypeItem) =
103         DefaultLambdaTypeItem(
104             codebase,
105             typeItem.modifiers.snapshot(),
106             typeItem.qualifiedName,
107             typeItem.arguments.map { it.transform(this) },
108             typeItem.outerClassType?.transform(this),
109             typeItem.isSuspend,
110             typeItem.receiverType?.transform(this),
<lambda>null111             typeItem.parameterTypes.map { it.transform(this) },
112             typeItem.returnType.transform(this),
113         )
114 
transformnull115     override fun transform(typeItem: PrimitiveTypeItem) =
116         DefaultPrimitiveTypeItem(typeItem.modifiers.snapshot(), typeItem.kind)
117 
118     override fun transform(typeItem: VariableTypeItem) =
119         DefaultVariableTypeItem(
120             typeItem.modifiers.snapshot(),
121             typeParameterScope.getTypeParameter(typeItem.name),
122         )
123 
124     override fun transform(typeItem: WildcardTypeItem) =
125         DefaultWildcardTypeItem(
126             typeItem.modifiers.snapshot(),
127             typeItem.extendsBound?.transform(this),
128             typeItem.superBound?.transform(this),
129         )
130 }
131