• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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.turbine
18 
19 import com.android.tools.metalava.model.ClassTypeItem
20 import com.android.tools.metalava.model.PrimitiveTypeItem
21 import com.android.tools.metalava.model.ReferenceTypeItem
22 import com.android.tools.metalava.model.TypeArgumentTypeItem
23 import com.android.tools.metalava.model.TypeItem
24 import com.android.tools.metalava.model.TypeModifiers
25 import com.android.tools.metalava.model.TypeParameterScope
26 import com.android.tools.metalava.model.item.DefaultCodebase
27 import com.android.tools.metalava.model.type.ContextNullability
28 import com.android.tools.metalava.model.type.DefaultArrayTypeItem
29 import com.android.tools.metalava.model.type.DefaultClassTypeItem
30 import com.android.tools.metalava.model.type.DefaultPrimitiveTypeItem
31 import com.android.tools.metalava.model.type.DefaultTypeItemFactory
32 import com.android.tools.metalava.model.type.DefaultTypeModifiers
33 import com.android.tools.metalava.model.type.DefaultVariableTypeItem
34 import com.android.tools.metalava.model.type.DefaultWildcardTypeItem
35 import com.google.turbine.model.TurbineConstantTypeKind
36 import com.google.turbine.type.AnnoInfo
37 import com.google.turbine.type.Type
38 import javax.lang.model.element.Element
39 import javax.lang.model.element.TypeElement
40 import javax.lang.model.type.TypeKind
41 
42 /** Creates [TypeItem]s from [Type]s. */
43 internal class TurbineTypeItemFactory(
44     private val initializer: TurbineCodebaseInitialiser,
45     private val annotationFactory: TurbineAnnotationFactory,
46     typeParameterScope: TypeParameterScope,
47 ) : DefaultTypeItemFactory<Type, TurbineTypeItemFactory>(typeParameterScope) {
48 
49     private val codebase: DefaultCodebase = initializer.codebase
50 
51     override fun self() = this
52 
53     override fun createNestedFactory(scope: TypeParameterScope) =
54         TurbineTypeItemFactory(initializer, annotationFactory, scope)
55 
56     override fun getType(
57         underlyingType: Type,
58         contextNullability: ContextNullability,
59         isVarArg: Boolean,
60     ) = createType(underlyingType, isVarArg, contextNullability)
61 
62     private fun createModifiers(
63         annos: List<AnnoInfo>,
64         contextNullability: ContextNullability,
65     ): TypeModifiers {
66         val typeAnnotations = annotationFactory.createAnnotations(annos)
67         // Compute the nullability, factoring in any context nullability and type annotations.
68         // Turbine does not support kotlin so the kotlin nullability is always null.
69         val nullability = contextNullability.compute(null, typeAnnotations)
70         return DefaultTypeModifiers.create(typeAnnotations, nullability)
71     }
72 
73     internal fun createType(
74         type: Type,
75         isVarArg: Boolean,
76         contextNullability: ContextNullability = ContextNullability.none,
77     ): TypeItem {
78         return when (val kind = type.tyKind()) {
79             Type.TyKind.PRIM_TY -> {
80                 type as Type.PrimTy
81                 // Primitives are always non-null.
82                 val modifiers = createModifiers(type.annos(), ContextNullability.forceNonNull)
83                 when (type.primkind()) {
84                     TurbineConstantTypeKind.BOOLEAN ->
85                         DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.BOOLEAN)
86                     TurbineConstantTypeKind.BYTE ->
87                         DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.BYTE)
88                     TurbineConstantTypeKind.CHAR ->
89                         DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.CHAR)
90                     TurbineConstantTypeKind.DOUBLE ->
91                         DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.DOUBLE)
92                     TurbineConstantTypeKind.FLOAT ->
93                         DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.FLOAT)
94                     TurbineConstantTypeKind.INT ->
95                         DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.INT)
96                     TurbineConstantTypeKind.LONG ->
97                         DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.LONG)
98                     TurbineConstantTypeKind.SHORT ->
99                         DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.SHORT)
100                     else ->
101                         throw IllegalStateException("Invalid primitive type in API surface: $type")
102                 }
103             }
104             Type.TyKind.ARRAY_TY -> {
105                 createArrayType(type as Type.ArrayTy, isVarArg, contextNullability)
106             }
107             Type.TyKind.CLASS_TY -> {
108                 type as Type.ClassTy
109                 var outerClass: ClassTypeItem? = null
110                 // A ClassTy is represented by list of SimpleClassTY each representing a nested
111                 // class. e.g. , Outer.Inner.Inner1 will be represented by three simple classes
112                 // Outer, Outer.Inner and Outer.Inner.Inner1
113                 val iterator = type.classes().iterator()
114                 while (iterator.hasNext()) {
115                     val simpleClass = iterator.next()
116 
117                     // Select the ContextNullability. If there is another SimpleClassTy after this
118                     // then this is an outer class which can never be null, so force it to be
119                     // non-null. Otherwise, this is the nested class so use the supplied
120                     // ContextNullability.
121                     val actualContextNullability =
122                         if (iterator.hasNext()) {
123                             // For all outer class types, set the nullability to non-null.
124                             ContextNullability.forceNonNull
125                         } else {
126                             // Use the supplied ContextNullability.
127                             contextNullability
128                         }
129 
130                     outerClass =
131                         createNestedClassType(simpleClass, outerClass, actualContextNullability)
132                 }
133                 outerClass!!
134             }
135             Type.TyKind.TY_VAR -> {
136                 type as Type.TyVar
137                 val modifiers = createModifiers(type.annos(), contextNullability)
138                 val typeParameter = typeParameterScope.getTypeParameter(type.sym().name())
139                 DefaultVariableTypeItem(modifiers, typeParameter)
140             }
141             Type.TyKind.WILD_TY -> {
142                 type as Type.WildTy
143                 // Wildcards themselves don't have a defined nullability.
144                 val modifiers =
145                     createModifiers(type.annotations(), ContextNullability.forceUndefined)
146                 when (type.boundKind()) {
147                     Type.WildTy.BoundKind.UPPER -> {
148                         val upperBound = createWildcardBound(type.bound())
149                         DefaultWildcardTypeItem(modifiers, upperBound, null)
150                     }
151                     Type.WildTy.BoundKind.LOWER -> {
152                         // LowerBounded types have java.lang.Object as upper bound
153                         val upperBound = createWildcardBound(Type.ClassTy.OBJECT)
154                         val lowerBound = createWildcardBound(type.bound())
155                         DefaultWildcardTypeItem(modifiers, upperBound, lowerBound)
156                     }
157                     Type.WildTy.BoundKind.NONE -> {
158                         // Unbounded types have java.lang.Object as upper bound
159                         val upperBound = createWildcardBound(Type.ClassTy.OBJECT)
160                         DefaultWildcardTypeItem(modifiers, upperBound, null)
161                     }
162                     else ->
163                         throw IllegalStateException("Invalid wildcard type in API surface: $type")
164                 }
165             }
166             Type.TyKind.VOID_TY ->
167                 DefaultPrimitiveTypeItem(
168                     // Primitives are always non-null.
169                     createModifiers(emptyList(), ContextNullability.forceNonNull),
170                     PrimitiveTypeItem.Primitive.VOID
171                 )
172             Type.TyKind.NONE_TY ->
173                 DefaultPrimitiveTypeItem(
174                     // Primitives are always non-null.
175                     DefaultTypeModifiers.emptyNonNullModifiers,
176                     PrimitiveTypeItem.Primitive.VOID
177                 )
178             Type.TyKind.ERROR_TY -> {
179                 // This is case of unresolved superclass or implemented interface
180                 type as Type.ErrorTy
181                 DefaultClassTypeItem(
182                     codebase,
183                     DefaultTypeModifiers.emptyUndefinedModifiers,
184                     type.name(),
185                     emptyList(),
186                     null,
187                 )
188             }
189             else -> throw IllegalStateException("Invalid type in API surface: $kind")
190         }
191     }
192 
193     private fun createWildcardBound(type: Type) = getGeneralType(type) as ReferenceTypeItem
194 
195     private fun createArrayType(
196         type: Type.ArrayTy,
197         isVarArg: Boolean,
198         contextNullability: ContextNullability,
199     ): TypeItem {
200         // For Turbine's ArrayTy, due to a bug in Turbine, the annotations for multidimensional
201         // arrays are in the wrong order so this works around the issue.
202 
203         // First, traverse from the outermost array to the innermost component type and add the
204         // [AnnoInfo]s to the list. Ending up with the innermost component type. Due to the bug the
205         // list contains [AnnoInfo]s from the innermost component type to the outermost types.
206         val annosList = mutableListOf<List<AnnoInfo>>()
207         var curr: Type = type
208         while (curr.tyKind() == Type.TyKind.ARRAY_TY) {
209             curr as Type.ArrayTy
210             annosList.add(curr.annos())
211             curr = curr.elementType()
212         }
213 
214         // Then, get the type for the innermost component, it has the correct annotations. Pass
215         // in the [ContextNullability.forComponentType] just in case this is the return type of an
216         // annotation method, or in other words the type of an annotation attribute.
217         val componentType = getType(curr, contextNullability.forComponentType())
218 
219         // Finally, traverse over the annotations from the innermost component type to the outermost
220         // array and construct a [DefaultArrayTypeItem] around the inner component type using its
221         // `List<AnnoInfo>`. The last `List<AnnoInfo>` is for the outermost array, and it needs to
222         // be tagged with the [isVarArg] value and [contextNullability].
223         val lastIndex = annosList.size - 1
224         return annosList.foldIndexed(componentType) { index, typeItem, annos ->
225             val (arrayContextNullability, arrayVarArg) =
226                 if (index == lastIndex) {
227                     // Outermost array. Should be called with correct value of isVarArg and
228                     // the contextual nullability.
229                     Pair(contextNullability, isVarArg)
230                 } else {
231                     Pair(ContextNullability.none, false)
232                 }
233 
234             val modifiers = createModifiers(annos, arrayContextNullability)
235             DefaultArrayTypeItem(modifiers, typeItem, arrayVarArg)
236         }
237     }
238 
239     /**
240      * Retrieves the `ClassTypeItem` representation of the outer class associated with a given
241      * nested class type. Intended for types that are not explicitly mentioned within the source
242      * code.
243      *
244      * @param type The `Type.ClassTy.SimpleClassTy` object representing the nested class.
245      * @return The `ClassTypeItem` representing the outer class.
246      */
247     private fun getOuterClassType(type: Type.ClassTy.SimpleClassTy): ClassTypeItem {
248         val className = type.sym().qualifiedName
249         val classTypeElement = initializer.getTypeElement(className)!!
250         return createOuterClassType(classTypeElement.enclosingElement!!)!!
251     }
252 
253     /**
254      * Constructs a `ClassTypeItem` representation from a type element. Intended for types that are
255      * not explicitly mentioned within the source code.
256      *
257      * @param element The `Element` object representing the type.
258      * @return The corresponding `ClassTypeItem`, or null if the `element` does not represent a
259      *   declared type.
260      */
261     private fun createOuterClassType(element: Element): ClassTypeItem? {
262         if (element.asType().kind != TypeKind.DECLARED) return null
263 
264         val outerClassElement = element.enclosingElement!!
265         val outerClassTypeItem = createOuterClassType(outerClassElement)
266 
267         element as TypeElement
268 
269         // Since this type was never part of source , it won't have any annotation or arguments
270         val modifiers = DefaultTypeModifiers.emptyNonNullModifiers
271         val classTypeItem =
272             DefaultClassTypeItem(
273                 codebase,
274                 modifiers,
275                 element.qualifiedName.toString(), // Assuming qualifiedName is available on element
276                 emptyList(),
277                 outerClassTypeItem
278             )
279         return classTypeItem
280     }
281 
282     private fun createNestedClassType(
283         type: Type.ClassTy.SimpleClassTy,
284         outerClass: ClassTypeItem?,
285         contextNullability: ContextNullability,
286     ): ClassTypeItem {
287         val sym = type.sym()
288         val outerClassItem =
289             if (sym.binaryName().contains("$") && outerClass == null) {
290                 getOuterClassType(type)
291             } else {
292                 outerClass
293             }
294 
295         val modifiers = createModifiers(type.annos(), contextNullability)
296         val qualifiedName = sym.qualifiedName
297         val parameters = type.targs().map { getGeneralType(it) as TypeArgumentTypeItem }
298         return DefaultClassTypeItem(codebase, modifiers, qualifiedName, parameters, outerClassItem)
299     }
300 }
301