1 /*
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 
17 #ifndef AAPT_VALUE_VISITOR_H
18 #define AAPT_VALUE_VISITOR_H
19 
20 #include "ResourceTable.h"
21 #include "ResourceValues.h"
22 
23 namespace aapt {
24 
25 // Visits a value and invokes the appropriate method based on its type.
26 // Does not traverse into compound types. Use ValueVisitor for that.
27 class ValueVisitor {
28  public:
29   virtual ~ValueVisitor() = default;
30 
VisitAny(Value * value)31   virtual void VisitAny(Value* value) {}
VisitItem(Item * value)32   virtual void VisitItem(Item* value) { VisitAny(value); }
Visit(Reference * value)33   virtual void Visit(Reference* value) { VisitItem(value); }
Visit(RawString * value)34   virtual void Visit(RawString* value) { VisitItem(value); }
Visit(String * value)35   virtual void Visit(String* value) { VisitItem(value); }
Visit(StyledString * value)36   virtual void Visit(StyledString* value) { VisitItem(value); }
Visit(FileReference * value)37   virtual void Visit(FileReference* value) { VisitItem(value); }
Visit(Id * value)38   virtual void Visit(Id* value) { VisitItem(value); }
Visit(BinaryPrimitive * value)39   virtual void Visit(BinaryPrimitive* value) { VisitItem(value); }
40 
Visit(Attribute * value)41   virtual void Visit(Attribute* value) { VisitAny(value); }
Visit(Style * value)42   virtual void Visit(Style* value) { VisitAny(value); }
Visit(Array * value)43   virtual void Visit(Array* value) { VisitAny(value); }
Visit(Plural * value)44   virtual void Visit(Plural* value) { VisitAny(value); }
Visit(Styleable * value)45   virtual void Visit(Styleable* value) { VisitAny(value); }
46 };
47 
48 // Const version of ValueVisitor.
49 class ConstValueVisitor {
50  public:
51   virtual ~ConstValueVisitor() = default;
52 
VisitAny(const Value * value)53   virtual void VisitAny(const Value* value) {
54   }
VisitItem(const Item * value)55   virtual void VisitItem(const Item* value) {
56     VisitAny(value);
57   }
Visit(const Reference * value)58   virtual void Visit(const Reference* value) {
59     VisitItem(value);
60   }
Visit(const RawString * value)61   virtual void Visit(const RawString* value) {
62     VisitItem(value);
63   }
Visit(const String * value)64   virtual void Visit(const String* value) {
65     VisitItem(value);
66   }
Visit(const StyledString * value)67   virtual void Visit(const StyledString* value) {
68     VisitItem(value);
69   }
Visit(const FileReference * value)70   virtual void Visit(const FileReference* value) {
71     VisitItem(value);
72   }
Visit(const Id * value)73   virtual void Visit(const Id* value) {
74     VisitItem(value);
75   }
Visit(const BinaryPrimitive * value)76   virtual void Visit(const BinaryPrimitive* value) {
77     VisitItem(value);
78   }
79 
Visit(const Attribute * value)80   virtual void Visit(const Attribute* value) {
81     VisitAny(value);
82   }
Visit(const Style * value)83   virtual void Visit(const Style* value) {
84     VisitAny(value);
85   }
Visit(const Array * value)86   virtual void Visit(const Array* value) {
87     VisitAny(value);
88   }
Visit(const Plural * value)89   virtual void Visit(const Plural* value) {
90     VisitAny(value);
91   }
Visit(const Styleable * value)92   virtual void Visit(const Styleable* value) {
93     VisitAny(value);
94   }
95 };
96 
97 // NOLINT, do not add parentheses around T.
98 #define DECL_VISIT_COMPOUND_VALUE(T)                   \
99   virtual void Visit(T* value) override { /* NOLINT */ \
100     VisitSubValues(value);                             \
101   }
102 
103 // Visits values, and if they are compound values, descends into their components as well.
104 struct DescendingValueVisitor : public ValueVisitor {
105   // The compiler will think we're hiding an overload, when we actually intend
106   // to call into RawValueVisitor. This will expose the visit methods in the
107   // super class so the compiler knows we are trying to call them.
108   using ValueVisitor::Visit;
109 
VisitSubValuesDescendingValueVisitor110   void VisitSubValues(Attribute* attribute) {
111     for (Attribute::Symbol& symbol : attribute->symbols) {
112       Visit(&symbol.symbol);
113     }
114   }
115 
VisitSubValuesDescendingValueVisitor116   void VisitSubValues(Style* style) {
117     if (style->parent) {
118       Visit(&style->parent.value());
119     }
120 
121     for (Style::Entry& entry : style->entries) {
122       Visit(&entry.key);
123       entry.value->Accept(this);
124     }
125   }
126 
VisitSubValuesDescendingValueVisitor127   void VisitSubValues(Array* array) {
128     for (std::unique_ptr<Item>& item : array->elements) {
129       item->Accept(this);
130     }
131   }
132 
VisitSubValuesDescendingValueVisitor133   void VisitSubValues(Plural* plural) {
134     for (std::unique_ptr<Item>& item : plural->values) {
135       if (item) {
136         item->Accept(this);
137       }
138     }
139   }
140 
VisitSubValuesDescendingValueVisitor141   void VisitSubValues(Styleable* styleable) {
142     for (Reference& reference : styleable->entries) {
143       Visit(&reference);
144     }
145   }
146 
147   DECL_VISIT_COMPOUND_VALUE(Attribute);
148   DECL_VISIT_COMPOUND_VALUE(Style);
149   DECL_VISIT_COMPOUND_VALUE(Array);
150   DECL_VISIT_COMPOUND_VALUE(Plural);
151   DECL_VISIT_COMPOUND_VALUE(Styleable);
152 };
153 
154 // Do not use directly. Helper struct for dyn_cast.
155 template <typename T>
156 struct DynCastVisitor : public ConstValueVisitor {
157   const T* value = nullptr;
158 
VisitDynCastVisitor159   void Visit(const T* v) override {
160     value = v;
161   }
162 };
163 
164 // Specialization that checks if the value is an Item.
165 template <>
166 struct DynCastVisitor<Item> : public ConstValueVisitor {
167   const Item* value = nullptr;
168 
169   void VisitItem(const Item* item) override {
170     value = item;
171   }
172 };
173 
174 // Returns a valid pointer to T if the value is an instance of T. Returns nullptr if value is
175 // nullptr of if value is not an instance of T.
176 template <typename T>
177 const T* ValueCast(const Value* value) {
178   if (!value) {
179     return nullptr;
180   }
181   DynCastVisitor<T> visitor;
182   value->Accept(&visitor);
183   return visitor.value;
184 }
185 
186 // Non-const version of ValueCast.
187 template <typename T>
188 T* ValueCast(Value* value) {
189   return const_cast<T*>(ValueCast<T>(static_cast<const Value*>(value)));
190 }
191 
192 inline void VisitAllValuesInPackage(ResourceTablePackage* pkg, ValueVisitor* visitor) {
193   for (auto& type : pkg->types) {
194     for (auto& entry : type->entries) {
195       for (auto& config_value : entry->values) {
196         config_value->value->Accept(visitor);
197       }
198     }
199   }
200 }
201 
202 inline void VisitAllValuesInTable(ResourceTable* table, ValueVisitor* visitor) {
203   for (auto& pkg : table->packages) {
204     VisitAllValuesInPackage(pkg.get(), visitor);
205   }
206 }
207 
208 }  // namespace aapt
209 
210 #endif  // AAPT_VALUE_VISITOR_H
211