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