blob: a8198318b69eb05f7ebc826180859a38ff360114 [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
2 * Copyright (C) 2015 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
Adam Lesinskice5e56e2016-10-21 17:56:45 -070017#include "link/Linkers.h"
18
Adam Lesinski1ab598f2015-08-14 14:26:04 -070019#include "Diagnostics.h"
20#include "ResourceUtils.h"
21#include "SdkConstants.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080022#include "link/ReferenceLinker.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070023#include "process/IResourceTableConsumer.h"
24#include "process/SymbolTable.h"
25#include "util/Util.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080026#include "xml/XmlDom.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070027
28namespace aapt {
29
30namespace {
31
Adam Lesinski467f1712015-11-16 17:35:44 -080032/**
Adam Lesinskicacb28f2016-10-19 12:18:14 -070033 * Visits all references (including parents of styles, references in styles,
34 * arrays, etc) and
35 * links their symbolic name to their Resource ID, performing mangling and
36 * package aliasing
Adam Lesinski467f1712015-11-16 17:35:44 -080037 * as needed.
38 */
39class ReferenceVisitor : public ValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070040 public:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070041 using ValueVisitor::Visit;
Adam Lesinski467f1712015-11-16 17:35:44 -080042
Adam Lesinskicacb28f2016-10-19 12:18:14 -070043 ReferenceVisitor(IAaptContext* context, SymbolTable* symbols,
Adam Lesinskice5e56e2016-10-21 17:56:45 -070044 xml::IPackageDeclStack* decls, CallSite* callsite)
45 : context_(context),
46 symbols_(symbols),
47 decls_(decls),
48 callsite_(callsite),
49 error_(false) {}
Adam Lesinskicacb28f2016-10-19 12:18:14 -070050
Adam Lesinskice5e56e2016-10-21 17:56:45 -070051 void Visit(Reference* ref) override {
52 if (!ReferenceLinker::LinkReference(ref, context_, symbols_, decls_,
53 callsite_)) {
54 error_ = true;
Adam Lesinski467f1712015-11-16 17:35:44 -080055 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070056 }
Adam Lesinski467f1712015-11-16 17:35:44 -080057
Adam Lesinskice5e56e2016-10-21 17:56:45 -070058 bool HasError() const { return error_; }
Adam Lesinski467f1712015-11-16 17:35:44 -080059
Adam Lesinskicacb28f2016-10-19 12:18:14 -070060 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070061 DISALLOW_COPY_AND_ASSIGN(ReferenceVisitor);
62
63 IAaptContext* context_;
64 SymbolTable* symbols_;
65 xml::IPackageDeclStack* decls_;
66 CallSite* callsite_;
67 bool error_;
Adam Lesinski467f1712015-11-16 17:35:44 -080068};
69
70/**
71 * Visits each xml Element and compiles the attributes within.
72 */
73class XmlVisitor : public xml::PackageAwareVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070074 public:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070075 using xml::PackageAwareVisitor::Visit;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070076
Adam Lesinskicacb28f2016-10-19 12:18:14 -070077 XmlVisitor(IAaptContext* context, SymbolTable* symbols, const Source& source,
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078 std::set<int>* sdk_levels_found, CallSite* callsite)
79 : context_(context),
80 symbols_(symbols),
81 source_(source),
82 sdk_levels_found_(sdk_levels_found),
83 callsite_(callsite),
84 reference_visitor_(context, symbols, this, callsite) {}
Adam Lesinski1ab598f2015-08-14 14:26:04 -070085
Adam Lesinskice5e56e2016-10-21 17:56:45 -070086 void Visit(xml::Element* el) override {
87 const Source source = source_.WithLine(el->line_number);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070088 for (xml::Attribute& attr : el->attributes) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070089 Maybe<xml::ExtractedPackage> maybe_package =
90 xml::ExtractPackageFromNamespace(attr.namespace_uri);
91 if (maybe_package) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070092 // There is a valid package name for this attribute. We will look this
93 // up.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070094 StringPiece package = maybe_package.value().package;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070095 if (package.empty()) {
96 // Empty package means the 'current' or 'local' package.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070097 package = context_->GetCompilationPackage();
Adam Lesinski1ab598f2015-08-14 14:26:04 -070098 }
99
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100 Reference attr_ref(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700101 ResourceNameRef(package, ResourceType::kAttr, attr.name));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700102 attr_ref.private_reference = maybe_package.value().private_namespace;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700103
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700104 std::string err_str;
105 attr.compiled_attribute = ReferenceLinker::CompileXmlAttribute(
106 attr_ref, context_->GetNameMangler(), symbols_, callsite_,
107 &err_str);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700108
109 // Convert the string value into a compiled Value if this is a valid
110 // attribute.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700111 if (attr.compiled_attribute) {
112 if (attr.compiled_attribute.value().id) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700113 // Record all SDK levels from which the attributes were defined.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700114 const size_t sdk_level = FindAttributeSdkLevel(
115 attr.compiled_attribute.value().id.value());
116 if (sdk_level > 1) {
117 sdk_levels_found_->insert(sdk_level);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700118 }
119 }
120
121 const Attribute* attribute =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700122 &attr.compiled_attribute.value().attribute;
123 attr.compiled_value =
124 ResourceUtils::TryParseItemForAttribute(attr.value, attribute);
125 if (!attr.compiled_value &&
126 !(attribute->type_mask & android::ResTable_map::TYPE_STRING)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700127 // We won't be able to encode this as a string.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700128 context_->GetDiagnostics()->Error(
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700129 DiagMessage(source) << "'" << attr.value << "' "
130 << "is incompatible with attribute "
131 << package << ":" << attr.name << " "
132 << *attribute);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700133 error_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700134 }
135
136 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700137 context_->GetDiagnostics()->Error(DiagMessage(source)
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700138 << "attribute '" << package << ":"
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700139 << attr.name << "' " << err_str);
140 error_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700141 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700142 } else if (!attr.compiled_value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143 // We still encode references, but only if we haven't manually set this
144 // to
145 // another compiled value.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700146 attr.compiled_value = ResourceUtils::TryParseReference(attr.value);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700147 }
148
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700149 if (attr.compiled_value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700150 // With a compiledValue, we must resolve the reference and assign it an
151 // ID.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700152 attr.compiled_value->SetSource(source);
153 attr.compiled_value->Accept(&reference_visitor_);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700154 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700155 }
156
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700157 // Call the super implementation.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700158 xml::PackageAwareVisitor::Visit(el);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700159 }
Adam Lesinski64587af2016-02-18 18:33:06 -0800160
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700161 bool HasError() { return error_ || reference_visitor_.HasError(); }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700162
163 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700164 DISALLOW_COPY_AND_ASSIGN(XmlVisitor);
165
166 IAaptContext* context_;
167 SymbolTable* symbols_;
168 Source source_;
169 std::set<int>* sdk_levels_found_;
170 CallSite* callsite_;
171 ReferenceVisitor reference_visitor_;
172 bool error_ = false;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700173};
174
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700175} // namespace
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700176
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700177bool XmlReferenceLinker::Consume(IAaptContext* context,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700178 xml::XmlResource* resource) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700179 sdk_levels_found_.clear();
180 CallSite callsite = {resource->file.name};
181 XmlVisitor visitor(context, context->GetExternalSymbols(),
182 resource->file.source, &sdk_levels_found_, &callsite);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 if (resource->root) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700184 resource->root->Accept(&visitor);
185 return !visitor.HasError();
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700186 }
187 return false;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700188}
189
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700190} // namespace aapt