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.model.ClassItem
21 import com.android.tools.metalava.model.Item
22 import com.android.tools.metalava.model.MethodItem
23 import com.android.tools.metalava.model.ParameterItem
24 import com.android.tools.metalava.model.TypeItem
25 import com.android.tools.metalava.model.TypeParameterItem
26 import com.android.tools.metalava.model.TypeParameterList
27 import com.android.tools.metalava.model.TypeParameterListOwner
28 import java.util.function.Predicate
29 
30 open class TextMethodItem(
31     codebase: TextCodebase,
32     name: String,
33     containingClass: TextClassItem,
34     modifiers: TextModifiers,
35     private val returnType: TextTypeItem?,
36     position: SourcePositionInfo
37 ) : TextMemberItem(
38     codebase, name, containingClass, position,
39     modifiers = modifiers
40 ), MethodItem, TypeParameterListOwner {
41     init {
42         @Suppress("LeakingThis")
43         modifiers.setOwner(this)
44     }
45 
equalsnull46     override fun equals(other: Any?): Boolean {
47         if (this === other) return true
48         if (other !is MethodItem) return false
49 
50         if (name() != other.name()) {
51             return false
52         }
53 
54         if (containingClass() != other.containingClass()) {
55             return false
56         }
57 
58         val parameters1 = parameters()
59         val parameters2 = other.parameters()
60 
61         if (parameters1.size != parameters2.size) {
62             return false
63         }
64 
65         for (i in parameters1.indices) {
66             val parameter1 = parameters1[i]
67             val parameter2 = parameters2[i]
68             if (parameter1.type() != parameter2.type()) {
69                 return false
70             }
71         }
72         return true
73     }
74 
hashCodenull75     override fun hashCode(): Int {
76         return name().hashCode()
77     }
78 
isConstructornull79     override fun isConstructor(): Boolean = false
80 
81     override fun returnType(): TypeItem? = returnType
82 
83     override fun superMethods(): List<MethodItem> {
84         if (isConstructor()) {
85             return emptyList()
86         }
87 
88         val list = mutableListOf<MethodItem>()
89 
90         var curr = containingClass().superClass()
91         while (curr != null) {
92             val superMethod = curr.findMethod(this)
93             if (superMethod != null) {
94                 list.add(superMethod)
95                 break
96             }
97             curr = curr.superClass()
98         }
99 
100         // Interfaces
101         for (itf in containingClass().allInterfaces()) {
102             val interfaceMethod = itf.findMethod(this)
103             if (interfaceMethod != null) {
104                 list.add(interfaceMethod)
105             }
106         }
107 
108         return list
109     }
110 
findPredicateSuperMethodnull111     override fun findPredicateSuperMethod(predicate: Predicate<Item>): MethodItem? = null
112 
113     private var typeParameterList: TypeParameterList = TypeParameterList.NONE
114 
115     fun setTypeParameterList(typeParameterList: TypeParameterList) {
116         this.typeParameterList = typeParameterList
117     }
118 
typeParameterListnull119     override fun typeParameterList(): TypeParameterList = typeParameterList
120 
121     override fun typeParameterListOwnerParent(): TypeParameterListOwner? {
122         return containingClass() as TextClassItem?
123     }
124 
resolveParameternull125     override fun resolveParameter(variable: String): TypeParameterItem? {
126         for (t in typeParameterList.typeParameters()) {
127             if (t.simpleName() == variable) {
128                 return t
129             }
130         }
131 
132         return (containingClass() as TextClassItem).resolveParameter(variable)
133     }
134 
duplicatenull135     override fun duplicate(targetContainingClass: ClassItem): MethodItem {
136         val duplicated = TextMethodItem(
137             codebase, name(), targetContainingClass as TextClassItem,
138             modifiers.duplicate(), returnType, position
139         )
140         duplicated.inheritedFrom = containingClass()
141 
142         // Preserve flags that may have been inherited (propagated) from surrounding packages
143         if (targetContainingClass.hidden) {
144             duplicated.hidden = true
145         }
146         if (targetContainingClass.removed) {
147             duplicated.removed = true
148         }
149         if (targetContainingClass.docOnly) {
150             duplicated.docOnly = true
151         }
152         if (targetContainingClass.deprecated && compatibility.propagateDeprecatedMembers) {
153             duplicated.deprecated = true
154         }
155 
156         duplicated.varargs = varargs
157         duplicated.deprecated = deprecated
158         duplicated.annotationDefault = annotationDefault
159         duplicated.throwsTypes.addAll(throwsTypes)
160         duplicated.throwsClasses = throwsClasses
161         duplicated.typeParameterList = typeParameterList
162         // Consider cloning these: they have back references to the parent method (though it's
163         // unlikely anyone will care about the difference in parent methods)
164         duplicated.parameters.addAll(parameters)
165 
166         return duplicated
167     }
168 
169     override val synthetic: Boolean get() = isEnumSyntheticMethod()
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