1 /* <lambda>null2 * Copyright (C) 2018 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 18 19 import com.android.tools.metalava.model.TypeParameterItem.Companion.SOURCE_TYPE_STRING_CONFIGURATION 20 import com.android.tools.metalava.model.item.DefaultTypeParameterItem 21 import com.android.tools.metalava.model.type.TypeItemFactory 22 23 /** 24 * Represents a type parameter list. For example, in class<S, T extends List<String>> the type 25 * parameter list is <S, T extends List<String>> and has type parameters named S and T, and type 26 * parameter T has bounds List<String>. 27 */ 28 interface TypeParameterList : List<TypeParameterItem> { 29 /** 30 * Returns source representation of this type parameter, using fully qualified names (possibly 31 * with java.lang. removed if requested via [configuration]). 32 */ 33 fun toSource(configuration: TypeStringConfiguration = SOURCE_TYPE_STRING_CONFIGURATION): String 34 35 /** 36 * Returns source representation of this type parameter, using fully qualified names (possibly 37 * with java.lang. removed if requested via options) 38 */ 39 override fun toString(): String 40 41 /** Implemented according to the general [java.util.List.equals] contract. */ 42 override fun equals(other: Any?): Boolean 43 44 /** Implemented according to the general [java.util.List.hashCode] contract. */ 45 override fun hashCode(): Int 46 47 companion object { 48 private val emptyListDelegate = emptyList<TypeParameterItem>() 49 50 /** Type parameter list when there are no type parameters */ 51 val NONE: TypeParameterList = 52 object : TypeParameterList, List<TypeParameterItem> by emptyListDelegate { 53 override fun toSource(configuration: TypeStringConfiguration): String { 54 return "" 55 } 56 57 override fun toString() = toSource() 58 59 override fun equals(other: Any?) = emptyListDelegate == other 60 61 override fun hashCode() = emptyListDelegate.hashCode() 62 } 63 } 64 } 65 66 class DefaultTypeParameterList 67 private constructor(private val typeParameters: List<TypeParameterItem>) : 68 TypeParameterList, List<TypeParameterItem> by typeParameters { 69 <lambda>null70 private val toString by lazy(LazyThreadSafetyMode.NONE) { toSource() } 71 <lambda>null72 override fun toSource(configuration: TypeStringConfiguration) = buildString { 73 if (this@DefaultTypeParameterList.isNotEmpty()) { 74 append("<") 75 var first = true 76 for (param in this@DefaultTypeParameterList) { 77 if (!first) { 78 append(", ") 79 } 80 first = false 81 append(param.toSource(configuration)) 82 } 83 append(">") 84 } 85 } 86 toStringnull87 override fun toString(): String { 88 return toString 89 } 90 equalsnull91 override fun equals(other: Any?) = typeParameters == other 92 93 override fun hashCode() = typeParameters.hashCode() 94 95 companion object { 96 97 /** 98 * Create a list of [TypeParameterItem] and a corresponding [TypeItemFactory] from model 99 * specific parameter and bounds information. 100 * 101 * A type parameter list can contain cycles between its type parameters, e.g. 102 * 103 * class Node<L extends Node<L, R>, R extends Node<L, R>> 104 * 105 * Parsing that requires a multi-stage approach. 106 * 1. Separate the list into a mapping from `TypeParameterItem` that have not yet had their 107 * `bounds` property initialized to the model specific parameter. 108 * 2. Create a nested factory of the enclosing factory which includes the type parameters. 109 * That will allow references between them to be resolved. 110 * 3. Complete the initialization by converting each bounds string into a TypeItem. 111 * 112 * @param containingTypeItemFactory the containing factory. 113 * @param scopeDescription the description of the scope that will be created by the factory. 114 * @param inputParams a list of the model specific type parameters. 115 * @param paramFactory a function that will create a [TypeParameterItem] from the model 116 * specified parameter [P]. 117 * @param boundsGetter a function that will create a list of [BoundsTypeItem] from the model 118 * specific bounds which will be stored in [DefaultTypeParameterItem.bounds]. 119 * @param P the type of the underlying model specific type parameter objects. 120 * @param F the type of the model specific [TypeItemFactory]. 121 */ 122 fun <P, F : TypeItemFactory<*, F>> createTypeParameterItemsAndFactory( 123 containingTypeItemFactory: F, 124 scopeDescription: String, 125 inputParams: List<P>, 126 paramFactory: (P) -> DefaultTypeParameterItem, 127 boundsGetter: (F, P) -> List<BoundsTypeItem>, 128 ): TypeParameterListAndFactory<F> { 129 // First, create a Map from [TypeParameterItem] to the model specific parameter. Using 130 // the [paramFactory] to convert the model specific parameter to a [TypeParameterItem]. 131 val typeParameterItemToBounds = inputParams.associateBy { param -> paramFactory(param) } 132 133 // Then, create a [TypeItemFactory] for this list of type parameters. 134 val typeParameters = typeParameterItemToBounds.keys.toList() 135 val typeItemFactory = 136 containingTypeItemFactory.nestedFactory(scopeDescription, typeParameters) 137 138 // Then, create and set the bounds in the [TypeParameterItem] passing in the 139 // [TypeItemFactory] to allow cross-references to type parameters to be resolved. 140 for ((typeParameter, param) in typeParameterItemToBounds) { 141 val boundsTypeItems = boundsGetter(typeItemFactory, param) 142 typeParameter.bounds = boundsTypeItems 143 } 144 145 // Pair the list up with the [TypeItemFactory] so that the latter can be reused. 146 val typeParameterList = DefaultTypeParameterList(typeParameters) 147 return TypeParameterListAndFactory(typeParameterList, typeItemFactory) 148 } 149 } 150 } 151 152 /** 153 * Group up [typeParameterList] and the [factory] that was used to resolve references when creating 154 * their [BoundsTypeItem]s. 155 */ 156 data class TypeParameterListAndFactory<F : TypeItemFactory<*, F>>( 157 val typeParameterList: TypeParameterList, 158 val factory: F, 159 ) 160