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.psi
18 
19 import com.android.tools.metalava.model.BoundsTypeItem
20 import com.android.tools.metalava.model.DefaultModifierList
21 import com.android.tools.metalava.model.TypeParameterItem
22 import com.android.tools.metalava.model.VariableTypeItem
23 import com.intellij.psi.PsiTypeParameter
24 import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterBuilder
25 import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
26 import org.jetbrains.kotlin.lexer.KtTokens
27 import org.jetbrains.kotlin.psi.KtTypeParameter
28 
29 internal class PsiTypeParameterItem(
30     codebase: PsiBasedCodebase,
31     private val psiClass: PsiTypeParameter,
32     private val name: String,
33     modifiers: DefaultModifierList
34 ) :
35     PsiItem(
36         codebase = codebase,
37         element = psiClass,
38         modifiers = modifiers,
39         documentation = "",
40     ),
41     TypeParameterItem {
42 
namenull43     override fun name() = name
44 
45     /** Must only be used by [type] to cache its result. */
46     private lateinit var variableTypeItem: VariableTypeItem
47 
48     override fun type(): VariableTypeItem {
49         if (!::variableTypeItem.isInitialized) {
50             variableTypeItem = codebase.globalTypeItemFactory.getVariableTypeForTypeParameter(this)
51         }
52         return variableTypeItem
53     }
54 
psinull55     override fun psi() = psiClass
56 
57     override fun typeBounds(): List<BoundsTypeItem> = bounds
58 
59     override fun isReified(): Boolean {
60         return isReified(psiClass as? PsiTypeParameter)
61     }
62 
63     internal lateinit var bounds: List<BoundsTypeItem>
64 
equalsnull65     override fun equals(other: Any?): Boolean {
66         if (this === other) return true
67         if (other !is TypeParameterItem) return false
68 
69         return name == other.name()
70     }
71 
hashCodenull72     override fun hashCode(): Int {
73         return name.hashCode()
74     }
75 
76     companion object {
createnull77         fun create(codebase: PsiBasedCodebase, psiClass: PsiTypeParameter): PsiTypeParameterItem {
78             val simpleName = psiClass.name!!
79             val modifiers = modifiers(codebase, psiClass)
80 
81             return PsiTypeParameterItem(
82                 codebase = codebase,
83                 psiClass = psiClass,
84                 name = simpleName,
85                 modifiers = modifiers
86             )
87         }
88 
isReifiednull89         fun isReified(element: PsiTypeParameter?): Boolean {
90             element ?: return false
91             // TODO(jsjeon): Handle PsiElementWithOrigin<*> when available
92             if (
93                 element is KtLightDeclaration<*, *> &&
94                     element.kotlinOrigin is KtTypeParameter &&
95                     element.kotlinOrigin?.text?.startsWith(KtTokens.REIFIED_KEYWORD.value) == true
96             ) {
97                 return true
98             } else if (
99                 element is KotlinLightTypeParameterBuilder &&
100                     element.origin.text.startsWith(KtTokens.REIFIED_KEYWORD.value)
101             ) {
102                 return true
103             }
104             return false
105         }
106     }
107 }
108