xref: /aosp_15_r20/frameworks/base/tools/aapt2/link/ReferenceLinker.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "link/ReferenceLinker.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include "ResourceParser.h"
20*d57664e9SAndroid Build Coastguard Worker #include "ResourceTable.h"
21*d57664e9SAndroid Build Coastguard Worker #include "ResourceUtils.h"
22*d57664e9SAndroid Build Coastguard Worker #include "ResourceValues.h"
23*d57664e9SAndroid Build Coastguard Worker #include "ValueVisitor.h"
24*d57664e9SAndroid Build Coastguard Worker #include "android-base/logging.h"
25*d57664e9SAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
26*d57664e9SAndroid Build Coastguard Worker #include "androidfw/IDiagnostics.h"
27*d57664e9SAndroid Build Coastguard Worker #include "androidfw/ResourceTypes.h"
28*d57664e9SAndroid Build Coastguard Worker #include "link/Linkers.h"
29*d57664e9SAndroid Build Coastguard Worker #include "process/IResourceTableConsumer.h"
30*d57664e9SAndroid Build Coastguard Worker #include "process/SymbolTable.h"
31*d57664e9SAndroid Build Coastguard Worker #include "trace/TraceBuffer.h"
32*d57664e9SAndroid Build Coastguard Worker #include "util/Util.h"
33*d57664e9SAndroid Build Coastguard Worker #include "xml/XmlUtil.h"
34*d57664e9SAndroid Build Coastguard Worker 
35*d57664e9SAndroid Build Coastguard Worker using ::aapt::ResourceUtils::StringBuilder;
36*d57664e9SAndroid Build Coastguard Worker using ::android::StringPiece;
37*d57664e9SAndroid Build Coastguard Worker using ::android::base::StringPrintf;
38*d57664e9SAndroid Build Coastguard Worker 
39*d57664e9SAndroid Build Coastguard Worker namespace aapt {
40*d57664e9SAndroid Build Coastguard Worker namespace {
41*d57664e9SAndroid Build Coastguard Worker struct LoggingResourceName {
LoggingResourceNameaapt::__anon57bc1d580111::LoggingResourceName42*d57664e9SAndroid Build Coastguard Worker   LoggingResourceName(const Reference& ref, const CallSite& callsite,
43*d57664e9SAndroid Build Coastguard Worker                       const xml::IPackageDeclStack* decls)
44*d57664e9SAndroid Build Coastguard Worker       : ref_(ref), callsite_(callsite), decls_(decls) {
45*d57664e9SAndroid Build Coastguard Worker   }
46*d57664e9SAndroid Build Coastguard Worker 
47*d57664e9SAndroid Build Coastguard Worker   const Reference& ref_;
48*d57664e9SAndroid Build Coastguard Worker   const CallSite& callsite_;
49*d57664e9SAndroid Build Coastguard Worker   const xml::IPackageDeclStack* decls_;
50*d57664e9SAndroid Build Coastguard Worker };
51*d57664e9SAndroid Build Coastguard Worker 
operator <<(::std::ostream & out,const LoggingResourceName & name)52*d57664e9SAndroid Build Coastguard Worker inline ::std::ostream& operator<<(::std::ostream& out, const LoggingResourceName& name) {
53*d57664e9SAndroid Build Coastguard Worker   if (!name.ref_.name) {
54*d57664e9SAndroid Build Coastguard Worker     out << name.ref_.id.value();
55*d57664e9SAndroid Build Coastguard Worker     return out;
56*d57664e9SAndroid Build Coastguard Worker   }
57*d57664e9SAndroid Build Coastguard Worker 
58*d57664e9SAndroid Build Coastguard Worker   out << name.ref_.name.value();
59*d57664e9SAndroid Build Coastguard Worker 
60*d57664e9SAndroid Build Coastguard Worker   Reference fully_qualified = name.ref_;
61*d57664e9SAndroid Build Coastguard Worker   xml::ResolvePackage(name.decls_, &fully_qualified);
62*d57664e9SAndroid Build Coastguard Worker 
63*d57664e9SAndroid Build Coastguard Worker   ResourceName& full_name = fully_qualified.name.value();
64*d57664e9SAndroid Build Coastguard Worker   if (full_name.package.empty()) {
65*d57664e9SAndroid Build Coastguard Worker     full_name.package = name.callsite_.package;
66*d57664e9SAndroid Build Coastguard Worker   }
67*d57664e9SAndroid Build Coastguard Worker 
68*d57664e9SAndroid Build Coastguard Worker   if (full_name != name.ref_.name.value()) {
69*d57664e9SAndroid Build Coastguard Worker     out << " (aka " << full_name << ")";
70*d57664e9SAndroid Build Coastguard Worker   }
71*d57664e9SAndroid Build Coastguard Worker   return out;
72*d57664e9SAndroid Build Coastguard Worker }
73*d57664e9SAndroid Build Coastguard Worker 
74*d57664e9SAndroid Build Coastguard Worker }  // namespace
75*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Reference * value)76*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Reference> ReferenceLinkerTransformer::TransformDerived(const Reference* value) {
77*d57664e9SAndroid Build Coastguard Worker   auto linked_item =
78*d57664e9SAndroid Build Coastguard Worker       ReferenceLinker::LinkReference(callsite_, *value, context_, symbols_, table_, package_decls_);
79*d57664e9SAndroid Build Coastguard Worker   if (linked_item) {
80*d57664e9SAndroid Build Coastguard Worker     auto linked_item_ptr = linked_item.release();
81*d57664e9SAndroid Build Coastguard Worker     if (auto ref = ValueCast<Reference>(linked_item_ptr)) {
82*d57664e9SAndroid Build Coastguard Worker       return std::unique_ptr<Reference>(ref);
83*d57664e9SAndroid Build Coastguard Worker     }
84*d57664e9SAndroid Build Coastguard Worker     context_->GetDiagnostics()->Error(android::DiagMessage(value->GetSource())
85*d57664e9SAndroid Build Coastguard Worker                                       << "value of '"
86*d57664e9SAndroid Build Coastguard Worker                                       << LoggingResourceName(*value, callsite_, package_decls_)
87*d57664e9SAndroid Build Coastguard Worker                                       << "' must be a resource reference");
88*d57664e9SAndroid Build Coastguard Worker     delete linked_item_ptr;
89*d57664e9SAndroid Build Coastguard Worker   }
90*d57664e9SAndroid Build Coastguard Worker 
91*d57664e9SAndroid Build Coastguard Worker   error_ = true;
92*d57664e9SAndroid Build Coastguard Worker   return CloningValueTransformer::TransformDerived(value);
93*d57664e9SAndroid Build Coastguard Worker }
94*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Style * style)95*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Style> ReferenceLinkerTransformer::TransformDerived(const Style* style) {
96*d57664e9SAndroid Build Coastguard Worker   // We visit the Style specially because during this phase, values of attributes are either
97*d57664e9SAndroid Build Coastguard Worker   // RawString or Reference values. Now that we are expected to resolve all symbols, we can lookup
98*d57664e9SAndroid Build Coastguard Worker   // the attributes to find out which types are allowed for the attributes' values.
99*d57664e9SAndroid Build Coastguard Worker   auto new_style = CloningValueTransformer::TransformDerived(style);
100*d57664e9SAndroid Build Coastguard Worker   if (new_style->parent) {
101*d57664e9SAndroid Build Coastguard Worker     new_style->parent = *TransformDerived(&style->parent.value());
102*d57664e9SAndroid Build Coastguard Worker   }
103*d57664e9SAndroid Build Coastguard Worker 
104*d57664e9SAndroid Build Coastguard Worker   for (Style::Entry& entry : new_style->entries) {
105*d57664e9SAndroid Build Coastguard Worker     std::string err_str;
106*d57664e9SAndroid Build Coastguard Worker 
107*d57664e9SAndroid Build Coastguard Worker     // Transform the attribute reference so that it is using the fully qualified package
108*d57664e9SAndroid Build Coastguard Worker     // name. This will also mark the reference as being able to see private resources if
109*d57664e9SAndroid Build Coastguard Worker     // there was a '*' in the reference or if the package came from the private namespace.
110*d57664e9SAndroid Build Coastguard Worker     Reference transformed_reference = entry.key;
111*d57664e9SAndroid Build Coastguard Worker     ResolvePackage(package_decls_, &transformed_reference);
112*d57664e9SAndroid Build Coastguard Worker 
113*d57664e9SAndroid Build Coastguard Worker     // Find the attribute in the symbol table and check if it is visible from this callsite.
114*d57664e9SAndroid Build Coastguard Worker     const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility(
115*d57664e9SAndroid Build Coastguard Worker         transformed_reference, callsite_, context_, symbols_, &err_str);
116*d57664e9SAndroid Build Coastguard Worker     if (symbol) {
117*d57664e9SAndroid Build Coastguard Worker       // Assign our style key the correct ID. The ID may not exist.
118*d57664e9SAndroid Build Coastguard Worker       entry.key.id = symbol->id;
119*d57664e9SAndroid Build Coastguard Worker 
120*d57664e9SAndroid Build Coastguard Worker       // Link/resolve the final value if it's a reference.
121*d57664e9SAndroid Build Coastguard Worker       entry.value = entry.value->Transform(*this);
122*d57664e9SAndroid Build Coastguard Worker 
123*d57664e9SAndroid Build Coastguard Worker       // Try to convert the value to a more specific, typed value based on the attribute it is
124*d57664e9SAndroid Build Coastguard Worker       // set to.
125*d57664e9SAndroid Build Coastguard Worker       entry.value = ParseValueWithAttribute(std::move(entry.value), symbol->attribute.get());
126*d57664e9SAndroid Build Coastguard Worker 
127*d57664e9SAndroid Build Coastguard Worker       // Now verify that the type of this item is compatible with the
128*d57664e9SAndroid Build Coastguard Worker       // attribute it is defined for. We pass `nullptr` as the DiagMessage so that this
129*d57664e9SAndroid Build Coastguard Worker       // check is fast and we avoid creating a DiagMessage when the match is successful.
130*d57664e9SAndroid Build Coastguard Worker       if (!symbol->attribute->Matches(*entry.value, nullptr)) {
131*d57664e9SAndroid Build Coastguard Worker         // The actual type of this item is incompatible with the attribute.
132*d57664e9SAndroid Build Coastguard Worker         android::DiagMessage msg(entry.key.GetSource());
133*d57664e9SAndroid Build Coastguard Worker 
134*d57664e9SAndroid Build Coastguard Worker         // Call the matches method again, this time with a DiagMessage so we fill in the actual
135*d57664e9SAndroid Build Coastguard Worker         // error message.
136*d57664e9SAndroid Build Coastguard Worker         symbol->attribute->Matches(*entry.value, &msg);
137*d57664e9SAndroid Build Coastguard Worker         context_->GetDiagnostics()->Error(msg);
138*d57664e9SAndroid Build Coastguard Worker         error_ = true;
139*d57664e9SAndroid Build Coastguard Worker       }
140*d57664e9SAndroid Build Coastguard Worker     } else {
141*d57664e9SAndroid Build Coastguard Worker       context_->GetDiagnostics()->Error(android::DiagMessage(entry.key.GetSource())
142*d57664e9SAndroid Build Coastguard Worker                                         << "style attribute '"
143*d57664e9SAndroid Build Coastguard Worker                                         << LoggingResourceName(entry.key, callsite_, package_decls_)
144*d57664e9SAndroid Build Coastguard Worker                                         << "' " << err_str);
145*d57664e9SAndroid Build Coastguard Worker 
146*d57664e9SAndroid Build Coastguard Worker       error_ = true;
147*d57664e9SAndroid Build Coastguard Worker     }
148*d57664e9SAndroid Build Coastguard Worker   }
149*d57664e9SAndroid Build Coastguard Worker   return new_style;
150*d57664e9SAndroid Build Coastguard Worker }
151*d57664e9SAndroid Build Coastguard Worker 
TransformItem(const Reference * value)152*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Item> ReferenceLinkerTransformer::TransformItem(const Reference* value) {
153*d57664e9SAndroid Build Coastguard Worker   auto linked_value =
154*d57664e9SAndroid Build Coastguard Worker       ReferenceLinker::LinkReference(callsite_, *value, context_, symbols_, table_, package_decls_);
155*d57664e9SAndroid Build Coastguard Worker   if (linked_value) {
156*d57664e9SAndroid Build Coastguard Worker     return linked_value;
157*d57664e9SAndroid Build Coastguard Worker   }
158*d57664e9SAndroid Build Coastguard Worker   error_ = true;
159*d57664e9SAndroid Build Coastguard Worker   return CloningValueTransformer::TransformDerived(value);
160*d57664e9SAndroid Build Coastguard Worker }
161*d57664e9SAndroid Build Coastguard Worker 
162*d57664e9SAndroid Build Coastguard Worker // Transform a RawString value into a more specific, appropriate value, based on the
163*d57664e9SAndroid Build Coastguard Worker // Attribute. If a non RawString value is passed in, this is an identity transform.
ParseValueWithAttribute(std::unique_ptr<Item> value,const Attribute * attr)164*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Item> ReferenceLinkerTransformer::ParseValueWithAttribute(
165*d57664e9SAndroid Build Coastguard Worker     std::unique_ptr<Item> value, const Attribute* attr) {
166*d57664e9SAndroid Build Coastguard Worker   if (RawString* raw_string = ValueCast<RawString>(value.get())) {
167*d57664e9SAndroid Build Coastguard Worker     std::unique_ptr<Item> transformed = ResourceUtils::TryParseItemForAttribute(
168*d57664e9SAndroid Build Coastguard Worker         context_->GetDiagnostics(), *raw_string->value, attr);
169*d57664e9SAndroid Build Coastguard Worker 
170*d57664e9SAndroid Build Coastguard Worker     // If we could not parse as any specific type, try a basic STRING.
171*d57664e9SAndroid Build Coastguard Worker     if (!transformed && (attr->type_mask & android::ResTable_map::TYPE_STRING)) {
172*d57664e9SAndroid Build Coastguard Worker       StringBuilder string_builder;
173*d57664e9SAndroid Build Coastguard Worker       string_builder.AppendText(*raw_string->value);
174*d57664e9SAndroid Build Coastguard Worker       if (string_builder) {
175*d57664e9SAndroid Build Coastguard Worker         transformed = util::make_unique<String>(pool_->MakeRef(string_builder.to_string()));
176*d57664e9SAndroid Build Coastguard Worker       }
177*d57664e9SAndroid Build Coastguard Worker     }
178*d57664e9SAndroid Build Coastguard Worker 
179*d57664e9SAndroid Build Coastguard Worker     if (transformed) {
180*d57664e9SAndroid Build Coastguard Worker       return transformed;
181*d57664e9SAndroid Build Coastguard Worker     }
182*d57664e9SAndroid Build Coastguard Worker   }
183*d57664e9SAndroid Build Coastguard Worker   return value;
184*d57664e9SAndroid Build Coastguard Worker }
185*d57664e9SAndroid Build Coastguard Worker 
186*d57664e9SAndroid Build Coastguard Worker namespace {
187*d57664e9SAndroid Build Coastguard Worker 
188*d57664e9SAndroid Build Coastguard Worker class EmptyDeclStack : public xml::IPackageDeclStack {
189*d57664e9SAndroid Build Coastguard Worker  public:
190*d57664e9SAndroid Build Coastguard Worker   EmptyDeclStack() = default;
191*d57664e9SAndroid Build Coastguard Worker 
TransformPackageAlias(StringPiece alias) const192*d57664e9SAndroid Build Coastguard Worker   std::optional<xml::ExtractedPackage> TransformPackageAlias(StringPiece alias) const override {
193*d57664e9SAndroid Build Coastguard Worker     if (alias.empty()) {
194*d57664e9SAndroid Build Coastguard Worker       return xml::ExtractedPackage{{}, true /*private*/};
195*d57664e9SAndroid Build Coastguard Worker     }
196*d57664e9SAndroid Build Coastguard Worker     return {};
197*d57664e9SAndroid Build Coastguard Worker   }
198*d57664e9SAndroid Build Coastguard Worker 
199*d57664e9SAndroid Build Coastguard Worker  private:
200*d57664e9SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(EmptyDeclStack);
201*d57664e9SAndroid Build Coastguard Worker };
202*d57664e9SAndroid Build Coastguard Worker 
203*d57664e9SAndroid Build Coastguard Worker struct MacroDeclStack : public xml::IPackageDeclStack {
MacroDeclStackaapt::__anon57bc1d580211::MacroDeclStack204*d57664e9SAndroid Build Coastguard Worker   explicit MacroDeclStack(std::vector<Macro::Namespace> namespaces)
205*d57664e9SAndroid Build Coastguard Worker       : alias_namespaces_(std::move(namespaces)) {
206*d57664e9SAndroid Build Coastguard Worker   }
207*d57664e9SAndroid Build Coastguard Worker 
TransformPackageAliasaapt::__anon57bc1d580211::MacroDeclStack208*d57664e9SAndroid Build Coastguard Worker   std::optional<xml::ExtractedPackage> TransformPackageAlias(StringPiece alias) const override {
209*d57664e9SAndroid Build Coastguard Worker     if (alias.empty()) {
210*d57664e9SAndroid Build Coastguard Worker       return xml::ExtractedPackage{{}, true /*private*/};
211*d57664e9SAndroid Build Coastguard Worker     }
212*d57664e9SAndroid Build Coastguard Worker     for (auto it = alias_namespaces_.rbegin(); it != alias_namespaces_.rend(); ++it) {
213*d57664e9SAndroid Build Coastguard Worker       if (alias == StringPiece(it->alias)) {
214*d57664e9SAndroid Build Coastguard Worker         return xml::ExtractedPackage{it->package_name, it->is_private};
215*d57664e9SAndroid Build Coastguard Worker       }
216*d57664e9SAndroid Build Coastguard Worker     }
217*d57664e9SAndroid Build Coastguard Worker     return {};
218*d57664e9SAndroid Build Coastguard Worker   }
219*d57664e9SAndroid Build Coastguard Worker 
220*d57664e9SAndroid Build Coastguard Worker  private:
221*d57664e9SAndroid Build Coastguard Worker   std::vector<Macro::Namespace> alias_namespaces_;
222*d57664e9SAndroid Build Coastguard Worker };
223*d57664e9SAndroid Build Coastguard Worker 
224*d57664e9SAndroid Build Coastguard Worker // The symbol is visible if it is public, or if the reference to it is requesting private access
225*d57664e9SAndroid Build Coastguard Worker // or if the callsite comes from the same package.
IsSymbolVisible(const SymbolTable::Symbol & symbol,const Reference & ref,const CallSite & callsite)226*d57664e9SAndroid Build Coastguard Worker bool IsSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
227*d57664e9SAndroid Build Coastguard Worker                      const CallSite& callsite) {
228*d57664e9SAndroid Build Coastguard Worker   if (symbol.is_public || ref.private_reference) {
229*d57664e9SAndroid Build Coastguard Worker     return true;
230*d57664e9SAndroid Build Coastguard Worker   }
231*d57664e9SAndroid Build Coastguard Worker 
232*d57664e9SAndroid Build Coastguard Worker   if (ref.name) {
233*d57664e9SAndroid Build Coastguard Worker     const ResourceName& name = ref.name.value();
234*d57664e9SAndroid Build Coastguard Worker     if (name.package.empty()) {
235*d57664e9SAndroid Build Coastguard Worker       // If the symbol was found, and the package is empty, that means it was found in the local
236*d57664e9SAndroid Build Coastguard Worker       // scope, which is always visible (private local).
237*d57664e9SAndroid Build Coastguard Worker       return true;
238*d57664e9SAndroid Build Coastguard Worker     }
239*d57664e9SAndroid Build Coastguard Worker 
240*d57664e9SAndroid Build Coastguard Worker     // The symbol is visible if the reference is local to the same package it is defined in.
241*d57664e9SAndroid Build Coastguard Worker     return callsite.package == name.package;
242*d57664e9SAndroid Build Coastguard Worker   }
243*d57664e9SAndroid Build Coastguard Worker 
244*d57664e9SAndroid Build Coastguard Worker   if (ref.id && symbol.id) {
245*d57664e9SAndroid Build Coastguard Worker     return ref.id.value().package_id() == symbol.id.value().package_id();
246*d57664e9SAndroid Build Coastguard Worker   }
247*d57664e9SAndroid Build Coastguard Worker   return false;
248*d57664e9SAndroid Build Coastguard Worker }
249*d57664e9SAndroid Build Coastguard Worker 
250*d57664e9SAndroid Build Coastguard Worker }  // namespace
251*d57664e9SAndroid Build Coastguard Worker 
ResolveSymbol(const Reference & reference,const CallSite & callsite,IAaptContext * context,SymbolTable * symbols)252*d57664e9SAndroid Build Coastguard Worker const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference,
253*d57664e9SAndroid Build Coastguard Worker                                                           const CallSite& callsite,
254*d57664e9SAndroid Build Coastguard Worker                                                           IAaptContext* context,
255*d57664e9SAndroid Build Coastguard Worker                                                           SymbolTable* symbols) {
256*d57664e9SAndroid Build Coastguard Worker   if (reference.name) {
257*d57664e9SAndroid Build Coastguard Worker     const ResourceName& name = reference.name.value();
258*d57664e9SAndroid Build Coastguard Worker     if (name.package.empty()) {
259*d57664e9SAndroid Build Coastguard Worker       // Use the callsite's package name if no package name was defined.
260*d57664e9SAndroid Build Coastguard Worker       const SymbolTable::Symbol* symbol = symbols->FindByName(
261*d57664e9SAndroid Build Coastguard Worker           ResourceName(callsite.package, name.type, name.entry));
262*d57664e9SAndroid Build Coastguard Worker       if (symbol) {
263*d57664e9SAndroid Build Coastguard Worker         return symbol;
264*d57664e9SAndroid Build Coastguard Worker       }
265*d57664e9SAndroid Build Coastguard Worker 
266*d57664e9SAndroid Build Coastguard Worker       // If the callsite package is the same as the current compilation package,
267*d57664e9SAndroid Build Coastguard Worker       // check the feature split dependencies as well. Feature split resources
268*d57664e9SAndroid Build Coastguard Worker       // can be referenced without a namespace, just like the base package.
269*d57664e9SAndroid Build Coastguard Worker       if (callsite.package == context->GetCompilationPackage()) {
270*d57664e9SAndroid Build Coastguard Worker         const auto& split_name_dependencies = context->GetSplitNameDependencies();
271*d57664e9SAndroid Build Coastguard Worker         for (const std::string& split_name : split_name_dependencies) {
272*d57664e9SAndroid Build Coastguard Worker           std::string split_package =
273*d57664e9SAndroid Build Coastguard Worker               StringPrintf("%s.%s", callsite.package.c_str(), split_name.c_str());
274*d57664e9SAndroid Build Coastguard Worker           symbol = symbols->FindByName(ResourceName(split_package, name.type, name.entry));
275*d57664e9SAndroid Build Coastguard Worker           if (symbol) {
276*d57664e9SAndroid Build Coastguard Worker             return symbol;
277*d57664e9SAndroid Build Coastguard Worker           }
278*d57664e9SAndroid Build Coastguard Worker         }
279*d57664e9SAndroid Build Coastguard Worker       }
280*d57664e9SAndroid Build Coastguard Worker       return nullptr;
281*d57664e9SAndroid Build Coastguard Worker     }
282*d57664e9SAndroid Build Coastguard Worker     return symbols->FindByName(name);
283*d57664e9SAndroid Build Coastguard Worker   } else if (reference.id) {
284*d57664e9SAndroid Build Coastguard Worker     return symbols->FindById(reference.id.value());
285*d57664e9SAndroid Build Coastguard Worker   } else {
286*d57664e9SAndroid Build Coastguard Worker     return nullptr;
287*d57664e9SAndroid Build Coastguard Worker   }
288*d57664e9SAndroid Build Coastguard Worker }
289*d57664e9SAndroid Build Coastguard Worker 
ResolveSymbolCheckVisibility(const Reference & reference,const CallSite & callsite,IAaptContext * context,SymbolTable * symbols,std::string * out_error)290*d57664e9SAndroid Build Coastguard Worker const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(const Reference& reference,
291*d57664e9SAndroid Build Coastguard Worker                                                                          const CallSite& callsite,
292*d57664e9SAndroid Build Coastguard Worker                                                                          IAaptContext* context,
293*d57664e9SAndroid Build Coastguard Worker                                                                          SymbolTable* symbols,
294*d57664e9SAndroid Build Coastguard Worker                                                                          std::string* out_error) {
295*d57664e9SAndroid Build Coastguard Worker   const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, context, symbols);
296*d57664e9SAndroid Build Coastguard Worker   if (!symbol) {
297*d57664e9SAndroid Build Coastguard Worker     if (out_error) *out_error = "not found";
298*d57664e9SAndroid Build Coastguard Worker     return nullptr;
299*d57664e9SAndroid Build Coastguard Worker   }
300*d57664e9SAndroid Build Coastguard Worker 
301*d57664e9SAndroid Build Coastguard Worker   if (!IsSymbolVisible(*symbol, reference, callsite)) {
302*d57664e9SAndroid Build Coastguard Worker     if (out_error) *out_error = "is private";
303*d57664e9SAndroid Build Coastguard Worker     return nullptr;
304*d57664e9SAndroid Build Coastguard Worker   }
305*d57664e9SAndroid Build Coastguard Worker   return symbol;
306*d57664e9SAndroid Build Coastguard Worker }
307*d57664e9SAndroid Build Coastguard Worker 
ResolveAttributeCheckVisibility(const Reference & reference,const CallSite & callsite,IAaptContext * context,SymbolTable * symbols,std::string * out_error)308*d57664e9SAndroid Build Coastguard Worker const SymbolTable::Symbol* ReferenceLinker::ResolveAttributeCheckVisibility(
309*d57664e9SAndroid Build Coastguard Worker     const Reference& reference, const CallSite& callsite, IAaptContext* context,
310*d57664e9SAndroid Build Coastguard Worker     SymbolTable* symbols, std::string* out_error) {
311*d57664e9SAndroid Build Coastguard Worker   const SymbolTable::Symbol* symbol =
312*d57664e9SAndroid Build Coastguard Worker       ResolveSymbolCheckVisibility(reference, callsite, context, symbols, out_error);
313*d57664e9SAndroid Build Coastguard Worker   if (!symbol) {
314*d57664e9SAndroid Build Coastguard Worker     return nullptr;
315*d57664e9SAndroid Build Coastguard Worker   }
316*d57664e9SAndroid Build Coastguard Worker 
317*d57664e9SAndroid Build Coastguard Worker   if (!symbol->attribute) {
318*d57664e9SAndroid Build Coastguard Worker     if (out_error) *out_error = "is not an attribute";
319*d57664e9SAndroid Build Coastguard Worker     return nullptr;
320*d57664e9SAndroid Build Coastguard Worker   }
321*d57664e9SAndroid Build Coastguard Worker   return symbol;
322*d57664e9SAndroid Build Coastguard Worker }
323*d57664e9SAndroid Build Coastguard Worker 
CompileXmlAttribute(const Reference & reference,const CallSite & callsite,IAaptContext * context,SymbolTable * symbols,std::string * out_error)324*d57664e9SAndroid Build Coastguard Worker std::optional<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference,
325*d57664e9SAndroid Build Coastguard Worker                                                                        const CallSite& callsite,
326*d57664e9SAndroid Build Coastguard Worker                                                                        IAaptContext* context,
327*d57664e9SAndroid Build Coastguard Worker                                                                        SymbolTable* symbols,
328*d57664e9SAndroid Build Coastguard Worker                                                                        std::string* out_error) {
329*d57664e9SAndroid Build Coastguard Worker   const SymbolTable::Symbol* symbol =
330*d57664e9SAndroid Build Coastguard Worker       ResolveAttributeCheckVisibility(reference, callsite, context, symbols, out_error);
331*d57664e9SAndroid Build Coastguard Worker   if (!symbol) {
332*d57664e9SAndroid Build Coastguard Worker     return {};
333*d57664e9SAndroid Build Coastguard Worker   }
334*d57664e9SAndroid Build Coastguard Worker 
335*d57664e9SAndroid Build Coastguard Worker   if (!symbol->attribute) {
336*d57664e9SAndroid Build Coastguard Worker     if (out_error) *out_error = "is not an attribute";
337*d57664e9SAndroid Build Coastguard Worker     return {};
338*d57664e9SAndroid Build Coastguard Worker   }
339*d57664e9SAndroid Build Coastguard Worker   return xml::AaptAttribute(*symbol->attribute, symbol->id);
340*d57664e9SAndroid Build Coastguard Worker }
341*d57664e9SAndroid Build Coastguard Worker 
WriteAttributeName(const Reference & ref,const CallSite & callsite,const xml::IPackageDeclStack * decls,android::DiagMessage * out_msg)342*d57664e9SAndroid Build Coastguard Worker void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite,
343*d57664e9SAndroid Build Coastguard Worker                                          const xml::IPackageDeclStack* decls,
344*d57664e9SAndroid Build Coastguard Worker                                          android::DiagMessage* out_msg) {
345*d57664e9SAndroid Build Coastguard Worker   CHECK(out_msg != nullptr);
346*d57664e9SAndroid Build Coastguard Worker   if (!ref.name) {
347*d57664e9SAndroid Build Coastguard Worker     *out_msg << ref.id.value();
348*d57664e9SAndroid Build Coastguard Worker     return;
349*d57664e9SAndroid Build Coastguard Worker   }
350*d57664e9SAndroid Build Coastguard Worker 
351*d57664e9SAndroid Build Coastguard Worker   const ResourceName& ref_name = ref.name.value();
352*d57664e9SAndroid Build Coastguard Worker   CHECK_EQ(ref_name.type.type, ResourceType::kAttr);
353*d57664e9SAndroid Build Coastguard Worker 
354*d57664e9SAndroid Build Coastguard Worker   if (!ref_name.package.empty()) {
355*d57664e9SAndroid Build Coastguard Worker     *out_msg << ref_name.package << ":";
356*d57664e9SAndroid Build Coastguard Worker   }
357*d57664e9SAndroid Build Coastguard Worker   *out_msg << ref_name.entry;
358*d57664e9SAndroid Build Coastguard Worker 
359*d57664e9SAndroid Build Coastguard Worker   Reference fully_qualified = ref;
360*d57664e9SAndroid Build Coastguard Worker   xml::ResolvePackage(decls, &fully_qualified);
361*d57664e9SAndroid Build Coastguard Worker 
362*d57664e9SAndroid Build Coastguard Worker   ResourceName& full_name = fully_qualified.name.value();
363*d57664e9SAndroid Build Coastguard Worker   if (full_name.package.empty()) {
364*d57664e9SAndroid Build Coastguard Worker     full_name.package = callsite.package;
365*d57664e9SAndroid Build Coastguard Worker   }
366*d57664e9SAndroid Build Coastguard Worker 
367*d57664e9SAndroid Build Coastguard Worker   if (full_name != ref.name.value()) {
368*d57664e9SAndroid Build Coastguard Worker     *out_msg << " (aka " << full_name.package << ":" << full_name.entry << ")";
369*d57664e9SAndroid Build Coastguard Worker   }
370*d57664e9SAndroid Build Coastguard Worker }
371*d57664e9SAndroid Build Coastguard Worker 
LinkReference(const CallSite & callsite,const Reference & reference,IAaptContext * context,SymbolTable * symbols,ResourceTable * table,const xml::IPackageDeclStack * decls)372*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Item> ReferenceLinker::LinkReference(const CallSite& callsite,
373*d57664e9SAndroid Build Coastguard Worker                                                      const Reference& reference,
374*d57664e9SAndroid Build Coastguard Worker                                                      IAaptContext* context, SymbolTable* symbols,
375*d57664e9SAndroid Build Coastguard Worker                                                      ResourceTable* table,
376*d57664e9SAndroid Build Coastguard Worker                                                      const xml::IPackageDeclStack* decls) {
377*d57664e9SAndroid Build Coastguard Worker   if (!reference.name && !reference.id) {
378*d57664e9SAndroid Build Coastguard Worker     // This is @null.
379*d57664e9SAndroid Build Coastguard Worker     return std::make_unique<Reference>(reference);
380*d57664e9SAndroid Build Coastguard Worker   }
381*d57664e9SAndroid Build Coastguard Worker 
382*d57664e9SAndroid Build Coastguard Worker   Reference transformed_reference = reference;
383*d57664e9SAndroid Build Coastguard Worker   xml::ResolvePackage(decls, &transformed_reference);
384*d57664e9SAndroid Build Coastguard Worker 
385*d57664e9SAndroid Build Coastguard Worker   if (transformed_reference.name.value().type.type == ResourceType::kMacro) {
386*d57664e9SAndroid Build Coastguard Worker     if (transformed_reference.name.value().package.empty()) {
387*d57664e9SAndroid Build Coastguard Worker       transformed_reference.name.value().package = callsite.package;
388*d57664e9SAndroid Build Coastguard Worker     }
389*d57664e9SAndroid Build Coastguard Worker 
390*d57664e9SAndroid Build Coastguard Worker     auto result = table->FindResource(transformed_reference.name.value());
391*d57664e9SAndroid Build Coastguard Worker     if (!result || result.value().entry->values.empty()) {
392*d57664e9SAndroid Build Coastguard Worker       context->GetDiagnostics()->Error(
393*d57664e9SAndroid Build Coastguard Worker           android::DiagMessage(reference.GetSource())
394*d57664e9SAndroid Build Coastguard Worker           << "failed to find definition for "
395*d57664e9SAndroid Build Coastguard Worker           << LoggingResourceName(transformed_reference, callsite, decls));
396*d57664e9SAndroid Build Coastguard Worker       return {};
397*d57664e9SAndroid Build Coastguard Worker     }
398*d57664e9SAndroid Build Coastguard Worker 
399*d57664e9SAndroid Build Coastguard Worker     auto& macro_values = result.value().entry->values;
400*d57664e9SAndroid Build Coastguard Worker     CHECK(macro_values.size() == 1) << "Macros can only be defined in the default configuration.";
401*d57664e9SAndroid Build Coastguard Worker 
402*d57664e9SAndroid Build Coastguard Worker     auto macro = ValueCast<Macro>(macro_values[0]->value.get());
403*d57664e9SAndroid Build Coastguard Worker     CHECK(macro != nullptr) << "Value of macro resource is not a Macro (actual "
404*d57664e9SAndroid Build Coastguard Worker                             << *macro_values[0]->value << ")";
405*d57664e9SAndroid Build Coastguard Worker 
406*d57664e9SAndroid Build Coastguard Worker     // Re-create the state used to parse the macro tag to compile the macro contents as if it was
407*d57664e9SAndroid Build Coastguard Worker     // defined inline
408*d57664e9SAndroid Build Coastguard Worker     uint32_t type_flags = 0;
409*d57664e9SAndroid Build Coastguard Worker     if (reference.type_flags.has_value()) {
410*d57664e9SAndroid Build Coastguard Worker       type_flags = reference.type_flags.value();
411*d57664e9SAndroid Build Coastguard Worker     }
412*d57664e9SAndroid Build Coastguard Worker 
413*d57664e9SAndroid Build Coastguard Worker     MacroDeclStack namespace_stack(macro->alias_namespaces);
414*d57664e9SAndroid Build Coastguard Worker     FlattenedXmlSubTree sub_tree{.raw_value = macro->raw_value,
415*d57664e9SAndroid Build Coastguard Worker                                  .style_string = macro->style_string,
416*d57664e9SAndroid Build Coastguard Worker                                  .untranslatable_sections = macro->untranslatable_sections,
417*d57664e9SAndroid Build Coastguard Worker                                  .namespace_resolver = &namespace_stack,
418*d57664e9SAndroid Build Coastguard Worker                                  .source = macro->GetSource()};
419*d57664e9SAndroid Build Coastguard Worker 
420*d57664e9SAndroid Build Coastguard Worker     auto new_value = ResourceParser::ParseXml(sub_tree, type_flags, reference.allow_raw, *table,
421*d57664e9SAndroid Build Coastguard Worker                                               macro_values[0]->config, *context->GetDiagnostics());
422*d57664e9SAndroid Build Coastguard Worker     if (new_value == nullptr) {
423*d57664e9SAndroid Build Coastguard Worker       context->GetDiagnostics()->Error(
424*d57664e9SAndroid Build Coastguard Worker           android::DiagMessage(reference.GetSource())
425*d57664e9SAndroid Build Coastguard Worker           << "failed to substitute macro "
426*d57664e9SAndroid Build Coastguard Worker           << LoggingResourceName(transformed_reference, callsite, decls)
427*d57664e9SAndroid Build Coastguard Worker           << ": failed to parse contents as one of type(s) " << Attribute::MaskString(type_flags));
428*d57664e9SAndroid Build Coastguard Worker       return {};
429*d57664e9SAndroid Build Coastguard Worker     }
430*d57664e9SAndroid Build Coastguard Worker 
431*d57664e9SAndroid Build Coastguard Worker     if (auto ref = ValueCast<Reference>(new_value.get())) {
432*d57664e9SAndroid Build Coastguard Worker       return LinkReference(callsite, *ref, context, symbols, table, decls);
433*d57664e9SAndroid Build Coastguard Worker     }
434*d57664e9SAndroid Build Coastguard Worker     return new_value;
435*d57664e9SAndroid Build Coastguard Worker   }
436*d57664e9SAndroid Build Coastguard Worker 
437*d57664e9SAndroid Build Coastguard Worker   std::string err_str;
438*d57664e9SAndroid Build Coastguard Worker   const SymbolTable::Symbol* s =
439*d57664e9SAndroid Build Coastguard Worker       ResolveSymbolCheckVisibility(transformed_reference, callsite, context, symbols, &err_str);
440*d57664e9SAndroid Build Coastguard Worker   if (s) {
441*d57664e9SAndroid Build Coastguard Worker     // The ID may not exist. This is fine because of the possibility of building
442*d57664e9SAndroid Build Coastguard Worker     // against libraries without assigned IDs.
443*d57664e9SAndroid Build Coastguard Worker     // Ex: Linking against own resources when building a static library.
444*d57664e9SAndroid Build Coastguard Worker     auto new_ref = std::make_unique<Reference>(reference);
445*d57664e9SAndroid Build Coastguard Worker     new_ref->id = s->id;
446*d57664e9SAndroid Build Coastguard Worker     new_ref->is_dynamic = s->is_dynamic;
447*d57664e9SAndroid Build Coastguard Worker     return std::move(new_ref);
448*d57664e9SAndroid Build Coastguard Worker   }
449*d57664e9SAndroid Build Coastguard Worker 
450*d57664e9SAndroid Build Coastguard Worker   context->GetDiagnostics()->Error(android::DiagMessage(reference.GetSource())
451*d57664e9SAndroid Build Coastguard Worker                                    << "resource "
452*d57664e9SAndroid Build Coastguard Worker                                    << LoggingResourceName(transformed_reference, callsite, decls)
453*d57664e9SAndroid Build Coastguard Worker                                    << " " << err_str);
454*d57664e9SAndroid Build Coastguard Worker   return {};
455*d57664e9SAndroid Build Coastguard Worker }
456*d57664e9SAndroid Build Coastguard Worker 
Consume(IAaptContext * context,ResourceTable * table)457*d57664e9SAndroid Build Coastguard Worker bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) {
458*d57664e9SAndroid Build Coastguard Worker   TRACE_NAME("ReferenceLinker::Consume");
459*d57664e9SAndroid Build Coastguard Worker   EmptyDeclStack decl_stack;
460*d57664e9SAndroid Build Coastguard Worker   bool error = false;
461*d57664e9SAndroid Build Coastguard Worker   for (auto& package : table->packages) {
462*d57664e9SAndroid Build Coastguard Worker     // Since we're linking, each package must have a name.
463*d57664e9SAndroid Build Coastguard Worker     CHECK(!package->name.empty()) << "all packages being linked must have a name";
464*d57664e9SAndroid Build Coastguard Worker 
465*d57664e9SAndroid Build Coastguard Worker     for (auto& type : package->types) {
466*d57664e9SAndroid Build Coastguard Worker       for (auto& entry : type->entries) {
467*d57664e9SAndroid Build Coastguard Worker         // First, unmangle the name if necessary.
468*d57664e9SAndroid Build Coastguard Worker         ResourceName name(package->name, type->named_type, entry->name);
469*d57664e9SAndroid Build Coastguard Worker         NameMangler::Unmangle(&name.entry, &name.package);
470*d57664e9SAndroid Build Coastguard Worker 
471*d57664e9SAndroid Build Coastguard Worker         // Symbol state information may be lost if there is no value for the resource.
472*d57664e9SAndroid Build Coastguard Worker         if (entry->visibility.level != Visibility::Level::kUndefined && entry->values.empty()) {
473*d57664e9SAndroid Build Coastguard Worker           context->GetDiagnostics()->Error(android::DiagMessage(entry->visibility.source)
474*d57664e9SAndroid Build Coastguard Worker                                            << "no definition for declared symbol '" << name << "'");
475*d57664e9SAndroid Build Coastguard Worker           error = true;
476*d57664e9SAndroid Build Coastguard Worker         }
477*d57664e9SAndroid Build Coastguard Worker 
478*d57664e9SAndroid Build Coastguard Worker         // Ensure that definitions for values declared as overlayable exist
479*d57664e9SAndroid Build Coastguard Worker         if (entry->overlayable_item && entry->values.empty()) {
480*d57664e9SAndroid Build Coastguard Worker           context->GetDiagnostics()->Error(
481*d57664e9SAndroid Build Coastguard Worker               android::DiagMessage(entry->overlayable_item.value().source)
482*d57664e9SAndroid Build Coastguard Worker               << "no definition for overlayable symbol '" << name << "'");
483*d57664e9SAndroid Build Coastguard Worker           error = true;
484*d57664e9SAndroid Build Coastguard Worker         }
485*d57664e9SAndroid Build Coastguard Worker 
486*d57664e9SAndroid Build Coastguard Worker         // The context of this resource is the package in which it is defined.
487*d57664e9SAndroid Build Coastguard Worker         const CallSite callsite{name.package};
488*d57664e9SAndroid Build Coastguard Worker         ReferenceLinkerTransformer reference_transformer(callsite, context,
489*d57664e9SAndroid Build Coastguard Worker                                                          context->GetExternalSymbols(),
490*d57664e9SAndroid Build Coastguard Worker                                                          &table->string_pool, table, &decl_stack);
491*d57664e9SAndroid Build Coastguard Worker 
492*d57664e9SAndroid Build Coastguard Worker         for (auto& config_value : entry->values) {
493*d57664e9SAndroid Build Coastguard Worker           config_value->value = config_value->value->Transform(reference_transformer);
494*d57664e9SAndroid Build Coastguard Worker         }
495*d57664e9SAndroid Build Coastguard Worker 
496*d57664e9SAndroid Build Coastguard Worker         if (reference_transformer.HasError()) {
497*d57664e9SAndroid Build Coastguard Worker           error = true;
498*d57664e9SAndroid Build Coastguard Worker         }
499*d57664e9SAndroid Build Coastguard Worker       }
500*d57664e9SAndroid Build Coastguard Worker     }
501*d57664e9SAndroid Build Coastguard Worker   }
502*d57664e9SAndroid Build Coastguard Worker   return !error;
503*d57664e9SAndroid Build Coastguard Worker }
504*d57664e9SAndroid Build Coastguard Worker 
505*d57664e9SAndroid Build Coastguard Worker }  // namespace aapt
506