• 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.psi
18 
19 import com.android.tools.metalava.model.ClassItem
20 import com.android.tools.metalava.model.FieldItem
21 import com.android.tools.metalava.model.PropertyItem
22 import com.android.tools.metalava.model.TypeItem
23 import com.intellij.psi.PsiClass
24 import com.intellij.psi.PsiMethod
25 import org.jetbrains.kotlin.psi.KtPropertyAccessor
26 import org.jetbrains.uast.UClass
27 
28 class PsiPropertyItem private constructor(
29     override val codebase: PsiBasedCodebase,
30     private val psiMethod: PsiMethod,
31     private val containingClass: PsiClassItem,
32     private val name: String,
33     modifiers: PsiModifierItem,
34     documentation: String,
35     private val fieldType: PsiTypeItem,
36     override val getter: PsiMethodItem,
37     override val setter: PsiMethodItem?,
38     override val constructorParameter: PsiParameterItem?,
39     override val backingField: PsiFieldItem?
40 ) :
41     PsiItem(
42         codebase = codebase,
43         modifiers = modifiers,
44         documentation = documentation,
45         element = psiMethod
46     ),
47     PropertyItem {
48 
typenull49     override fun type(): TypeItem = fieldType
50     override fun name(): String = name
51     override fun containingClass(): ClassItem = containingClass
52 
53     override fun isCloned(): Boolean {
54         val psiClass = run {
55             val p = containingClass().psi() as? PsiClass ?: return false
56             if (p is UClass) {
57                 p.sourcePsi as? PsiClass ?: return false
58             } else {
59                 p
60             }
61         }
62         return psiMethod.containingClass != psiClass
63     }
64 
equalsnull65     override fun equals(other: Any?): Boolean {
66         if (this === other) {
67             return true
68         }
69         return other is FieldItem && name == other.name() && containingClass == other.containingClass()
70     }
71 
hashCodenull72     override fun hashCode(): Int {
73         return name.hashCode()
74     }
75 
toStringnull76     override fun toString(): String = "field ${containingClass.fullName()}.${name()}"
77 
78     companion object {
79         /**
80          * Creates a new property item, given a [name], [type] and relationships to other items.
81          *
82          * Kotlin properties consist of up to four other declarations: Their accessor functions,
83          * primary constructor parameter, and a backing field. These relationships are useful for
84          * resolving documentation and exposing the model correctly in Kotlin stubs.
85          *
86          * Metalava currently requires all properties to have a [getter]. It does not currently
87          * support private, `const val`, or [JvmField] properties. Mutable `var` properties usually
88          * have a [setter], but properties with a private default setter may use direct field
89          * access instead.
90          *
91          * Properties declared in the primary constructor of a class have an associated
92          * [constructorParameter]. This relationship is important for resolving docs which may
93          * exist on the constructor parameter.
94          *
95          * Most properties on classes without a custom getter have a [backingField] to hold their
96          * value. This is private except for [JvmField] properties.
97          */
98         fun create(
99             codebase: PsiBasedCodebase,
100             containingClass: PsiClassItem,
101             name: String,
102             type: PsiTypeItem,
103             getter: PsiMethodItem,
104             setter: PsiMethodItem? = null,
105             constructorParameter: PsiParameterItem? = null,
106             backingField: PsiFieldItem? = null
107         ): PsiPropertyItem {
108             val psiMethod = getter.psiMethod
109             val documentation = when (val sourcePsi = getter.sourcePsi) {
110                 is KtPropertyAccessor -> javadoc(sourcePsi.property)
111                 else -> javadoc(sourcePsi ?: psiMethod)
112             }
113             val modifiers = modifiers(codebase, psiMethod, documentation)
114             val property = PsiPropertyItem(
115                 codebase = codebase,
116                 psiMethod = psiMethod,
117                 containingClass = containingClass,
118                 name = name,
119                 documentation = documentation,
120                 modifiers = modifiers,
121                 fieldType = type,
122                 getter = getter,
123                 setter = setter,
124                 constructorParameter = constructorParameter,
125                 backingField = backingField
126             )
127             getter.property = property
128             setter?.property = property
129             constructorParameter?.property = property
130             backingField?.property = property
131             property.modifiers.setOwner(property)
132             return property
133         }
134     }
135 }
136