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
23namespace aapt {
24
25/**
26 * Visits a value and invokes the appropriate method based on its type. Does not
27 * traverse into compound types. Use ValueVisitor for that.
28 */
29struct RawValueVisitor {
30  virtual ~RawValueVisitor() = default;
31
32  virtual void VisitAny(Value* value) {}
33  virtual void VisitItem(Item* value) { VisitAny(value); }
34  virtual void Visit(Reference* value) { VisitItem(value); }
35  virtual void Visit(RawString* value) { VisitItem(value); }
36  virtual void Visit(String* value) { VisitItem(value); }
37  virtual void Visit(StyledString* value) { VisitItem(value); }
38  virtual void Visit(FileReference* value) { VisitItem(value); }
39  virtual void Visit(Id* value) { VisitItem(value); }
40  virtual void Visit(BinaryPrimitive* value) { VisitItem(value); }
41
42  virtual void Visit(Attribute* value) { VisitAny(value); }
43  virtual void Visit(Style* value) { VisitAny(value); }
44  virtual void Visit(Array* value) { VisitAny(value); }
45  virtual void Visit(Plural* value) { VisitAny(value); }
46  virtual void Visit(Styleable* value) { VisitAny(value); }
47};
48
49// NOLINT, do not add parentheses around T.
50#define DECL_VISIT_COMPOUND_VALUE(T)                   \
51  virtual void Visit(T* value) override { /* NOLINT */ \
52    VisitSubValues(value);                             \
53  }
54
55/**
56 * Visits values, and if they are compound values, visits the components as
57 * well.
58 */
59struct ValueVisitor : public RawValueVisitor {
60  // The compiler will think we're hiding an overload, when we actually intend
61  // to call into RawValueVisitor. This will expose the visit methods in the
62  // super class so the compiler knows we are trying to call them.
63  using RawValueVisitor::Visit;
64
65  void VisitSubValues(Attribute* attribute) {
66    for (Attribute::Symbol& symbol : attribute->symbols) {
67      Visit(&symbol.symbol);
68    }
69  }
70
71  void VisitSubValues(Style* style) {
72    if (style->parent) {
73      Visit(&style->parent.value());
74    }
75
76    for (Style::Entry& entry : style->entries) {
77      Visit(&entry.key);
78      entry.value->Accept(this);
79    }
80  }
81
82  void VisitSubValues(Array* array) {
83    for (std::unique_ptr<Item>& item : array->items) {
84      item->Accept(this);
85    }
86  }
87
88  void VisitSubValues(Plural* plural) {
89    for (std::unique_ptr<Item>& item : plural->values) {
90      if (item) {
91        item->Accept(this);
92      }
93    }
94  }
95
96  void VisitSubValues(Styleable* styleable) {
97    for (Reference& reference : styleable->entries) {
98      Visit(&reference);
99    }
100  }
101
102  DECL_VISIT_COMPOUND_VALUE(Attribute);
103  DECL_VISIT_COMPOUND_VALUE(Style);
104  DECL_VISIT_COMPOUND_VALUE(Array);
105  DECL_VISIT_COMPOUND_VALUE(Plural);
106  DECL_VISIT_COMPOUND_VALUE(Styleable);
107};
108
109/**
110 * Do not use directly. Helper struct for dyn_cast.
111 */
112template <typename T>
113struct DynCastVisitor : public RawValueVisitor {
114  T* value = nullptr;
115
116  void Visit(T* v) override { value = v; }
117};
118
119/**
120 * Specialization that checks if the value is an Item.
121 */
122template <>
123struct DynCastVisitor<Item> : public RawValueVisitor {
124  Item* value = nullptr;
125
126  void VisitItem(Item* item) override { value = item; }
127};
128
129template <typename T>
130const T* ValueCast(const Value* value) {
131  return ValueCast<T>(const_cast<Value*>(value));
132}
133
134/**
135 * Returns a valid pointer to T if the Value is of subtype T.
136 * Otherwise, returns nullptr.
137 */
138template <typename T>
139T* ValueCast(Value* value) {
140  if (!value) {
141    return nullptr;
142  }
143  DynCastVisitor<T> visitor;
144  value->Accept(&visitor);
145  return visitor.value;
146}
147
148inline void VisitAllValuesInPackage(ResourceTablePackage* pkg,
149                                    RawValueVisitor* visitor) {
150  for (auto& type : pkg->types) {
151    for (auto& entry : type->entries) {
152      for (auto& config_value : entry->values) {
153        config_value->value->Accept(visitor);
154      }
155    }
156  }
157}
158
159inline void VisitAllValuesInTable(ResourceTable* table,
160                                  RawValueVisitor* visitor) {
161  for (auto& pkg : table->packages) {
162    VisitAllValuesInPackage(pkg.get(), visitor);
163  }
164}
165
166}  // namespace aapt
167
168#endif  // AAPT_VALUE_VISITOR_H
169