1 /* 2 * 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.text 18 19 import com.android.tools.metalava.model.ClassItem 20 import com.android.tools.metalava.model.DefaultModifierList 21 import com.android.tools.metalava.model.TypeParameterItem 22 import com.android.tools.metalava.model.TypeParameterListOwner 23 24 class TextTypeParameterItem( 25 codebase: TextCodebase, 26 private val owner: TypeParameterListOwner?, 27 private val typeParameterString: String, 28 name: String, 29 private var bounds: List<ClassItem>? = null 30 ) : 31 TextClassItem( 32 codebase = codebase, 33 modifiers = TextModifiers(codebase, DefaultModifierList.PUBLIC), 34 name = name, 35 qualifiedName = name 36 ), 37 TypeParameterItem { 38 boundsnull39 override fun bounds(): List<ClassItem> { 40 if (bounds == null) { 41 val boundsString = bounds(typeParameterString, owner) 42 bounds = if (boundsString.isEmpty()) { 43 emptyList() 44 } else { 45 boundsString.mapNotNull { 46 val clz = codebase.findClass(it) 47 if (clz == null && it.contains(".")) { 48 codebase.getOrCreateClass(it) 49 } else { 50 clz 51 } 52 }.filter { 53 !it.isJavaLangObject() 54 } 55 } 56 } 57 return bounds!! 58 } 59 isReifiednull60 override fun isReified(): Boolean { 61 return typeParameterString.startsWith("reified") 62 } 63 64 companion object { createnull65 fun create( 66 codebase: TextCodebase, 67 owner: TypeParameterListOwner?, 68 typeParameterString: String, 69 bounds: List<ClassItem>? = null 70 ): TextTypeParameterItem { 71 val length = typeParameterString.length 72 var nameEnd = length 73 for (i in 0 until length) { 74 val c = typeParameterString[i] 75 if (!Character.isJavaIdentifierPart(c)) { 76 nameEnd = i 77 break 78 } 79 } 80 val name = typeParameterString.substring(0, nameEnd) 81 return TextTypeParameterItem( 82 codebase = codebase, 83 owner = owner, 84 typeParameterString = typeParameterString, 85 name = name, 86 bounds = bounds 87 ) 88 } 89 boundsnull90 fun bounds(typeString: String?, owner: TypeParameterListOwner? = null): List<String> { 91 val s = typeString ?: return emptyList() 92 val index = s.indexOf("extends ") 93 if (index == -1) { 94 // See if this is a type variable that has bounds in the parent 95 val parameters = (owner as? TextMemberItem)?.containingClass()?.typeParameterList()?.typeParameters() 96 ?: return emptyList() 97 for (p in parameters) { 98 if (p.simpleName() == s) { 99 return p.bounds().filter { !it.isJavaLangObject() }.map { it.qualifiedName() } 100 } 101 } 102 103 return emptyList() 104 } 105 val list = mutableListOf<String>() 106 var balance = 0 107 var start = index + "extends ".length 108 val length = s.length 109 for (i in start until length) { 110 val c = s[i] 111 if (c == '&' && balance == 0) { 112 add(list, typeString, start, i) 113 start = i + 1 114 } else if (c == '<') { 115 balance++ 116 if (balance == 1) { 117 add(list, typeString, start, i) 118 } 119 } else if (c == '>') { 120 balance-- 121 if (balance == 0) { 122 start = i + 1 123 } 124 } 125 } 126 if (start < length) { 127 add(list, typeString, start, length) 128 } 129 return list 130 } 131 addnull132 private fun add(list: MutableList<String>, s: String, from: Int, to: Int) { 133 for (i in from until to) { 134 if (!Character.isWhitespace(s[i])) { 135 var end = to 136 while (end > i && s[end - 1].isWhitespace()) { 137 end-- 138 } 139 var begin = i 140 while (begin < end && s[begin].isWhitespace()) { 141 begin++ 142 } 143 if (begin == end) { 144 return 145 } 146 val element = s.substring(begin, end) 147 list.add(element) 148 return 149 } 150 } 151 } 152 } 153 }