• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }