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