• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_JAVA_CLASSDEFINITION_H
18 #define AAPT_JAVA_CLASSDEFINITION_H
19 
20 #include <string>
21 #include <unordered_map>
22 #include <vector>
23 
24 #include "android-base/macros.h"
25 #include "androidfw/StringPiece.h"
26 
27 #include "Resource.h"
28 #include "java/AnnotationProcessor.h"
29 #include "text/Printer.h"
30 #include "util/Util.h"
31 
32 namespace aapt {
33 
34 // The number of attributes to emit per line in a Styleable array.
35 constexpr static size_t kAttribsPerLine = 4;
36 constexpr static const char* kIndent = "  ";
37 
38 class ClassMember {
39  public:
40   virtual ~ClassMember() = default;
41 
GetCommentBuilder()42   AnnotationProcessor* GetCommentBuilder() {
43     return &processor_;
44   }
45 
46   virtual bool empty() const = 0;
47 
48   virtual const std::string& GetName() const = 0;
49 
50   // Writes the class member to the Printer. Subclasses should derive this method
51   // to write their own data. Call this base method from the subclass to write out
52   // this member's comments/annotations.
53   virtual void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) const;
54 
55  private:
56   AnnotationProcessor processor_;
57 };
58 
59 template <typename T>
60 class PrimitiveMember : public ClassMember {
61  public:
62   PrimitiveMember(android::StringPiece name, const T& val, bool staged_api = false)
name_(name)63       : name_(name), val_(val), staged_api_(staged_api) {
64   }
65 
empty()66   bool empty() const override {
67     return false;
68   }
69 
GetName()70   const std::string& GetName() const override {
71     return name_;
72   }
73 
74   void Print(bool final, text::Printer* printer,
75              bool strip_api_annotations = false) const override {
76     using std::to_string;
77 
78     ClassMember::Print(final, printer, strip_api_annotations);
79 
80     printer->Print("public static ");
81     if (final) {
82       printer->Print("final ");
83     }
84     printer->Print("int ").Print(name_);
85     if (staged_api_) {
86       // Prevent references to staged apis from being inline by setting their value out-of-line.
87       printer->Print("; static { ").Print(name_);
88     }
89     printer->Print("=").Print(to_string(val_)).Print(";");
90     if (staged_api_) {
91       printer->Print(" }");
92     }
93   }
94 
95  private:
96   DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
97 
98   std::string name_;
99   T val_;
100   bool staged_api_;
101 };
102 
103 // Specialization for strings so they get the right type and are quoted with "".
104 template <>
105 class PrimitiveMember<std::string> : public ClassMember {
106  public:
107   PrimitiveMember(android::StringPiece name, const std::string& val, bool staged_api = false)
name_(name)108       : name_(name), val_(val) {
109   }
110 
empty()111   bool empty() const override {
112     return false;
113   }
114 
GetName()115   const std::string& GetName() const override {
116     return name_;
117   }
118 
119   void Print(bool final, text::Printer* printer, bool strip_api_annotations = false)
120       const override {
121     ClassMember::Print(final, printer, strip_api_annotations);
122 
123     printer->Print("public static ");
124     if (final) {
125       printer->Print("final ");
126     }
127     printer->Print("String ").Print(name_).Print("=\"").Print(val_).Print("\";");
128   }
129 
130  private:
131   DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
132 
133   std::string name_;
134   std::string val_;
135 };
136 
137 using IntMember = PrimitiveMember<uint32_t>;
138 using ResourceMember = PrimitiveMember<ResourceId>;
139 using StringMember = PrimitiveMember<std::string>;
140 
141 template <typename T, typename StringConverter>
142 class PrimitiveArrayMember : public ClassMember {
143  public:
PrimitiveArrayMember(android::StringPiece name)144   explicit PrimitiveArrayMember(android::StringPiece name) : name_(name) {
145   }
146 
AddElement(const T & val)147   void AddElement(const T& val) {
148     elements_.emplace_back(val);
149   }
150 
empty()151   bool empty() const override {
152     return false;
153   }
154 
GetName()155   const std::string& GetName() const override {
156     return name_;
157   }
158 
159   void Print(bool final, text::Printer* printer, bool strip_api_annotations = false)
160       const override {
161     ClassMember::Print(final, printer, strip_api_annotations);
162 
163     printer->Print("public static final int[] ").Print(name_).Print("={");
164     printer->Indent();
165 
166     const auto begin = elements_.begin();
167     const auto end = elements_.end();
168     for (auto current = begin; current != end; ++current) {
169       if (std::distance(begin, current) % kAttribsPerLine == 0) {
170         printer->Println();
171       }
172 
173       printer->Print(StringConverter::ToString(*current));
174       if (std::distance(current, end) > 1) {
175         printer->Print(", ");
176       }
177     }
178     printer->Println();
179     printer->Undent();
180     printer->Print("};");
181   }
182 
183  private:
184   DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
185 
186   std::string name_;
187   std::vector<T> elements_;
188 };
189 
190 struct FieldReference {
FieldReferenceFieldReference191   explicit FieldReference(std::string reference) : ref(std::move(reference)) {
192   }
193   std::string ref;
194 };
195 
196 struct ResourceArrayMemberStringConverter {
ToStringResourceArrayMemberStringConverter197   static std::string ToString(const std::variant<ResourceId, FieldReference>& ref) {
198     if (auto id = std::get_if<ResourceId>(&ref)) {
199       return to_string(*id);
200     } else {
201       return std::get<FieldReference>(ref).ref;
202     }
203   }
204 };
205 
206 using ResourceArrayMember = PrimitiveArrayMember<std::variant<ResourceId, FieldReference>,
207                                                  ResourceArrayMemberStringConverter>;
208 
209 // Represents a method in a class.
210 class MethodDefinition : public ClassMember {
211  public:
212   // Expected method signature example: 'public static void onResourcesLoaded(int p)'.
MethodDefinition(android::StringPiece signature)213   explicit MethodDefinition(android::StringPiece signature) : signature_(signature) {
214   }
215 
216   // Appends a single statement to the method. It should include no newlines or else
217   // formatting may be broken.
218   void AppendStatement(android::StringPiece statement);
219 
220   // Not quite the same as a name, but good enough.
GetName()221   const std::string& GetName() const override {
222     return signature_;
223   }
224 
225   // Even if the method is empty, we always want to write the method signature.
empty()226   bool empty() const override {
227     return false;
228   }
229 
230   void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) const override;
231 
232  private:
233   DISALLOW_COPY_AND_ASSIGN(MethodDefinition);
234 
235   std::string signature_;
236   std::vector<std::string> statements_;
237 };
238 
239 enum class ClassQualifier { kNone, kStatic };
240 
241 class ClassDefinition : public ClassMember {
242  public:
243   static void WriteJavaFile(const ClassDefinition* def, android::StringPiece package, bool final,
244                             bool strip_api_annotations, android::OutputStream* out);
245 
ClassDefinition(android::StringPiece name,ClassQualifier qualifier,bool createIfEmpty)246   ClassDefinition(android::StringPiece name, ClassQualifier qualifier, bool createIfEmpty)
247       : name_(name), qualifier_(qualifier), create_if_empty_(createIfEmpty) {
248   }
249 
250   enum class Result {
251     kAdded,
252     kOverridden,
253   };
254 
255   Result AddMember(std::unique_ptr<ClassMember> member);
256 
257   bool empty() const override;
258 
GetName()259   const std::string& GetName() const override {
260     return name_;
261   }
262 
263   void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) const override;
264 
265  private:
266   DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
267 
268   std::string name_;
269   ClassQualifier qualifier_;
270   bool create_if_empty_;
271   std::vector<std::unique_ptr<ClassMember>> ordered_members_;
272   std::unordered_map<android::StringPiece, size_t> indexed_members_;
273 };
274 
275 }  // namespace aapt
276 
277 #endif /* AAPT_JAVA_CLASSDEFINITION_H */
278