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 ), FieldItem { 45 typenull46 override fun type(): TypeItem = fieldType 47 override fun initialValue(requireConstant: Boolean): Any? { 48 if (initialValue != null) { 49 return initialValue 50 } 51 val constant = psiField.computeConstantValue() 52 if (constant != null) { 53 return constant 54 } 55 56 return if (!requireConstant) { 57 val initializer = psiField.initializer ?: return null 58 JavaConstantExpressionEvaluator.computeConstantExpression(initializer, false) 59 } else { 60 null 61 } 62 } 63 isEnumConstantnull64 override fun isEnumConstant(): Boolean = isEnumConstant 65 override fun name(): String = name 66 override fun containingClass(): ClassItem = containingClass 67 68 override fun isCloned(): Boolean { 69 val psiClass = run { 70 val p = containingClass().psi() as? PsiClass ?: return false 71 if (p is UClass) { 72 p.sourcePsi as? PsiClass ?: return false 73 } else { 74 p 75 } 76 } 77 return psiField.containingClass != psiClass 78 } 79 duplicatenull80 override fun duplicate(targetContainingClass: ClassItem): PsiFieldItem { 81 val duplicated = create(codebase, targetContainingClass as PsiClassItem, psiField) 82 duplicated.inheritedFrom = containingClass 83 duplicated.inheritedField = inheritedField 84 85 // Preserve flags that may have been inherited (propagated) from surrounding packages 86 if (targetContainingClass.hidden) { 87 duplicated.hidden = true 88 } 89 if (targetContainingClass.removed) { 90 duplicated.removed = true 91 } 92 if (targetContainingClass.docOnly) { 93 duplicated.docOnly = true 94 } 95 96 return duplicated 97 } 98 99 override var inheritedFrom: ClassItem? = null 100 override var inheritedField: Boolean = false 101 equalsnull102 override fun equals(other: Any?): Boolean { 103 if (this === other) { 104 return true 105 } 106 return other is FieldItem && name == other.name() && containingClass == other.containingClass() 107 } 108 hashCodenull109 override fun hashCode(): Int { 110 return name.hashCode() 111 } 112 toStringnull113 override fun toString(): String = "field ${containingClass.fullName()}.${name()}" 114 115 companion object { 116 fun create(codebase: PsiBasedCodebase, containingClass: PsiClassItem, psiField: PsiField): PsiFieldItem { 117 val name = psiField.name 118 val commentText = javadoc(psiField) 119 val modifiers = modifiers(codebase, psiField, commentText) 120 121 val fieldType = codebase.getType(psiField.type) 122 val isEnumConstant = psiField is PsiEnumConstant 123 val initialValue = null // compute lazily 124 125 val field = PsiFieldItem( 126 codebase = codebase, 127 psiField = psiField, 128 containingClass = containingClass, 129 name = name, 130 documentation = commentText, 131 modifiers = modifiers, 132 fieldType = fieldType, 133 isEnumConstant = isEnumConstant, 134 initialValue = initialValue 135 ) 136 field.modifiers.setOwner(field) 137 return field 138 } 139 } 140 }