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.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.TypeItem 22 import com.intellij.psi.PsiClass 23 import com.intellij.psi.PsiEnumConstant 24 import com.intellij.psi.PsiField 25 import com.intellij.psi.impl.JavaConstantExpressionEvaluator 26 import org.jetbrains.uast.UClass 27 28 class PsiFieldItem( 29 override val codebase: PsiBasedCodebase, 30 private val psiField: PsiField, 31 private val containingClass: PsiClassItem, 32 private val name: String, 33 modifiers: PsiModifierItem, 34 documentation: String, 35 private val fieldType: PsiTypeItem, 36 private val isEnumConstant: Boolean, 37 private val initialValue: Any? 38 ) : 39 PsiItem( 40 codebase = codebase, 41 modifiers = modifiers, 42 documentation = documentation, 43 element = psiField 44 ), 45 FieldItem { 46 47 override var property: PsiPropertyItem? = null 48 typenull49 override fun type(): TypeItem = fieldType 50 override fun initialValue(requireConstant: Boolean): Any? { 51 if (initialValue != null) { 52 return initialValue 53 } 54 val constant = psiField.computeConstantValue() 55 if (constant != null) { 56 return constant 57 } 58 59 return if (!requireConstant) { 60 val initializer = psiField.initializer ?: return null 61 JavaConstantExpressionEvaluator.computeConstantExpression(initializer, false) 62 } else { 63 null 64 } 65 } 66 isEnumConstantnull67 override fun isEnumConstant(): Boolean = isEnumConstant 68 override fun name(): String = name 69 override fun containingClass(): ClassItem = containingClass 70 71 override fun isCloned(): Boolean { 72 val psiClass = run { 73 val p = containingClass().psi() as? PsiClass ?: return false 74 if (p is UClass) { 75 p.sourcePsi as? PsiClass ?: return false 76 } else { 77 p 78 } 79 } 80 return psiField.containingClass != psiClass 81 } 82 duplicatenull83 override fun duplicate(targetContainingClass: ClassItem): PsiFieldItem { 84 val duplicated = create(codebase, targetContainingClass as PsiClassItem, psiField) 85 duplicated.inheritedFrom = containingClass 86 duplicated.inheritedField = inheritedField 87 88 // Preserve flags that may have been inherited (propagated) from surrounding packages 89 if (targetContainingClass.hidden) { 90 duplicated.hidden = true 91 } 92 if (targetContainingClass.removed) { 93 duplicated.removed = true 94 } 95 if (targetContainingClass.docOnly) { 96 duplicated.docOnly = true 97 } 98 99 return duplicated 100 } 101 102 override var inheritedFrom: ClassItem? = null 103 override var inheritedField: Boolean = false 104 equalsnull105 override fun equals(other: Any?): Boolean { 106 if (this === other) { 107 return true 108 } 109 return other is FieldItem && name == other.name() && containingClass == other.containingClass() 110 } 111 hashCodenull112 override fun hashCode(): Int { 113 return name.hashCode() 114 } 115 toStringnull116 override fun toString(): String = "field ${containingClass.fullName()}.${name()}" 117 118 companion object { 119 fun create(codebase: PsiBasedCodebase, containingClass: PsiClassItem, psiField: PsiField): PsiFieldItem { 120 val name = psiField.name 121 val commentText = javadoc(psiField) 122 val modifiers = modifiers(codebase, psiField, commentText) 123 124 val fieldType = codebase.getType(psiField.type) 125 val isEnumConstant = psiField is PsiEnumConstant 126 val initialValue = null // compute lazily 127 128 val field = PsiFieldItem( 129 codebase = codebase, 130 psiField = psiField, 131 containingClass = containingClass, 132 name = name, 133 documentation = commentText, 134 modifiers = modifiers, 135 fieldType = fieldType, 136 isEnumConstant = isEnumConstant, 137 initialValue = initialValue 138 ) 139 field.modifiers.setOwner(field) 140 return field 141 } 142 } 143 } 144