• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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