1 /*
2  * Copyright (C) 2017 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.compatibility
20 import com.android.tools.metalava.doclava1.SourcePositionInfo
21 import com.android.tools.metalava.doclava1.TextCodebase
22 import com.android.tools.metalava.model.ClassItem
23 import com.android.tools.metalava.model.Item
24 import com.android.tools.metalava.model.MethodItem
25 import com.android.tools.metalava.model.ParameterItem
26 import com.android.tools.metalava.model.TypeItem
27 import com.android.tools.metalava.model.TypeParameterItem
28 import com.android.tools.metalava.model.TypeParameterList
29 import com.android.tools.metalava.model.TypeParameterListOwner
30 import java.util.function.Predicate
31 
32 open class TextMethodItem(
33     codebase: TextCodebase,
34     name: String,
35     containingClass: TextClassItem,
36     modifiers: TextModifiers,
37     private val returnType: TextTypeItem?,
38     position: SourcePositionInfo
39 ) : TextMemberItem(
40     codebase, name, containingClass, position,
41     modifiers = modifiers
42 ), MethodItem, TypeParameterListOwner {
43     init {
44         @Suppress("LeakingThis")
45         modifiers.setOwner(this)
46     }
47 
equalsnull48     override fun equals(other: Any?): Boolean {
49         if (this === other) return true
50         if (other !is MethodItem) return false
51 
52         if (name() != other.name()) {
53             return false
54         }
55 
56         if (containingClass() != other.containingClass()) {
57             return false
58         }
59 
60         val parameters1 = parameters()
61         val parameters2 = other.parameters()
62 
63         if (parameters1.size != parameters2.size) {
64             return false
65         }
66 
67         for (i in 0 until parameters1.size) {
68             val parameter1 = parameters1[i]
69             val parameter2 = parameters2[i]
70             if (parameter1.type() != parameter2.type()) {
71                 return false
72             }
73         }
74         return true
75     }
76 
hashCodenull77     override fun hashCode(): Int {
78         return name().hashCode()
79     }
80 
isConstructornull81     override fun isConstructor(): Boolean = false
82 
83     override fun returnType(): TypeItem? = returnType
84 
85     override fun superMethods(): List<MethodItem> {
86         if (isConstructor()) {
87             return emptyList()
88         }
89 
90         val list = mutableListOf<MethodItem>()
91 
92         var curr = containingClass().superClass()
93         while (curr != null) {
94             val superMethod = curr.findMethod(this)
95             if (superMethod != null) {
96                 list.add(superMethod)
97                 break
98             }
99             curr = curr.superClass()
100         }
101 
102         // Interfaces
103         for (itf in containingClass().allInterfaces()) {
104             val interfaceMethod = itf.findMethod(this)
105             if (interfaceMethod != null) {
106                 list.add(interfaceMethod)
107             }
108         }
109 
110         return list
111     }
112 
findPredicateSuperMethodnull113     override fun findPredicateSuperMethod(predicate: Predicate<Item>): MethodItem? = null
114 
115     private var typeParameterList: TypeParameterList = TypeParameterList.NONE
116 
117     fun setTypeParameterList(typeParameterList: TypeParameterList) {
118         this.typeParameterList = typeParameterList
119     }
120 
typeParameterListnull121     override fun typeParameterList(): TypeParameterList = typeParameterList
122 
123     override fun typeParameterListOwnerParent(): TypeParameterListOwner? {
124         return containingClass() as TextClassItem?
125     }
126 
resolveParameternull127     override fun resolveParameter(variable: String): TypeParameterItem? {
128         for (t in typeParameterList.typeParameters()) {
129             if (t.simpleName() == variable) {
130                 return t
131             }
132         }
133 
134         return (containingClass() as TextClassItem).resolveParameter(variable)
135     }
136 
duplicatenull137     override fun duplicate(targetContainingClass: ClassItem): MethodItem {
138         val duplicated = TextMethodItem(
139             codebase, name(), targetContainingClass as TextClassItem,
140             modifiers.duplicate(), returnType, position
141         )
142         duplicated.inheritedFrom = containingClass()
143 
144         // Preserve flags that may have been inherited (propagated) from surrounding packages
145         if (targetContainingClass.hidden) {
146             duplicated.hidden = true
147         }
148         if (targetContainingClass.removed) {
149             duplicated.removed = true
150         }
151         if (targetContainingClass.docOnly) {
152             duplicated.docOnly = true
153         }
154         if (targetContainingClass.deprecated && compatibility.propagateDeprecatedMembers) {
155             duplicated.deprecated = true
156         }
157 
158         duplicated.varargs = varargs
159         duplicated.deprecated = deprecated
160         duplicated.annotationDefault = annotationDefault
161         duplicated.throwsTypes.addAll(throwsTypes)
162         duplicated.throwsClasses = throwsClasses
163         duplicated.typeParameterList = typeParameterList
164         // Consider cloning these: they have back references to the parent method (though it's
165         // unlikely anyone will care about the difference in parent methods)
166         duplicated.parameters.addAll(parameters)
167 
168         return duplicated
169     }
170 
171     private val throwsTypes = mutableListOf<String>()
172     private val parameters = mutableListOf<TextParameterItem>()
173     private var throwsClasses: List<ClassItem>? = null
174 
throwsTypeNamesnull175     fun throwsTypeNames(): List<String> {
176         return throwsTypes
177     }
178 
throwsTypesnull179     override fun throwsTypes(): List<ClassItem> = if (throwsClasses == null) emptyList() else throwsClasses!!
180 
181     fun setThrowsList(throwsClasses: List<TextClassItem>) {
182         this.throwsClasses = throwsClasses
183     }
184 
parametersnull185     override fun parameters(): List<ParameterItem> = parameters
186 
187     fun addException(throwsType: String) {
188         throwsTypes += throwsType
189     }
190 
addParameternull191     fun addParameter(parameter: TextParameterItem) {
192         parameters += parameter
193     }
194 
195     private var varargs: Boolean = false
196 
setVarargsnull197     fun setVarargs(varargs: Boolean) {
198         this.varargs = varargs
199     }
200 
isVarArgnull201     fun isVarArg(): Boolean = varargs
202 
203     override fun isExtensionMethod(): Boolean = codebase.unsupported()
204 
205     override var inheritedMethod: Boolean = false
206     override var inheritedFrom: ClassItem? = null
207 
208     override fun toString(): String =
209         "${if (isConstructor()) "constructor" else "method"} ${containingClass().qualifiedName()}.${name()}(${parameters().joinToString {
210             it.type().toSimpleType()
211         }})"
212 
213     private var annotationDefault = ""
214 
215     fun setAnnotationDefault(default: String) {
216         annotationDefault = default
217     }
218 
defaultValuenull219     override fun defaultValue(): String {
220         return annotationDefault
221     }
222 }
223