1 /* 2 * Copyright (C) 2025 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.turbine 18 19 import com.google.common.collect.Iterables 20 import com.google.turbine.binder.ConstEvaluator 21 import com.google.turbine.binder.Resolve 22 import com.google.turbine.binder.bound.TypeBoundClass 23 import com.google.turbine.binder.env.CompoundEnv 24 import com.google.turbine.binder.env.Env 25 import com.google.turbine.binder.lookup.LookupKey 26 import com.google.turbine.binder.lookup.MemberImportIndex 27 import com.google.turbine.binder.lookup.Scope 28 import com.google.turbine.binder.sym.ClassSymbol 29 import com.google.turbine.model.TurbineFlag 30 import com.google.turbine.tree.Tree 31 32 /** 33 * This copies functionality used within [ConstEvaluator]. 34 * 35 * Ideally, the Turbine team will be able to refactor [ConstEvaluator] to pull that functionality 36 * out for use by us. 37 */ 38 internal class TurbineFieldResolver( 39 private val origin: ClassSymbol, 40 private val owner: ClassSymbol, 41 private val memberImports: MemberImportIndex, 42 private val scope: Scope, 43 private val env: CompoundEnv<ClassSymbol, TypeBoundClass> 44 ) { toStringnull45 override fun toString() = "TurbineFieldResolver($origin)" 46 47 fun resolveField(t: Tree.ConstVarName): TypeBoundClass.FieldInfo? { 48 val simpleName = t.name()[0] 49 var field = lexicalField(env, owner, simpleName) 50 if (field != null) { 51 return field 52 } 53 field = resolveQualifiedField(t) 54 if (field != null) { 55 return field 56 } 57 val classSymbol = memberImports.singleMemberImport(simpleName.value()) 58 if (classSymbol != null) { 59 field = Resolve.resolveField(env, origin, classSymbol, simpleName) 60 if (field != null) { 61 return field 62 } 63 } 64 val it = memberImports.onDemandImports() 65 while (it.hasNext()) { 66 field = Resolve.resolveField(env, origin, it.next(), simpleName) 67 if (field == null) { 68 continue 69 } 70 if ((field.access() and TurbineFlag.ACC_PRIVATE) == TurbineFlag.ACC_PRIVATE) { 71 continue 72 } 73 return field 74 } 75 76 return null 77 } 78 resolveQualifiedFieldnull79 private fun resolveQualifiedField(t: Tree.ConstVarName): TypeBoundClass.FieldInfo? { 80 if (t.name().size <= 1) { 81 return null 82 } 83 val result = scope.lookup(LookupKey(t.name())) ?: return null 84 if (result.remaining().isEmpty()) { 85 return null 86 } 87 var sym = result.sym() as ClassSymbol 88 for (i in 0 until result.remaining().size - 1) { 89 sym = Resolve.resolve(env, sym, sym, result.remaining()[i]) ?: return null 90 } 91 return Resolve.resolveField(env, origin, sym, Iterables.getLast(result.remaining())) 92 } 93 lexicalFieldnull94 private fun lexicalField( 95 env: Env<ClassSymbol, TypeBoundClass>, 96 initialSym: ClassSymbol?, 97 name: Tree.Ident 98 ): TypeBoundClass.FieldInfo? { 99 var sym = initialSym 100 while (sym != null) { 101 val info = env.getNonNull(sym) 102 val field = Resolve.resolveField(env, origin, sym, name) 103 if (field != null) { 104 return field 105 } 106 sym = info.owner() 107 } 108 return null 109 } 110 } 111