• 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(const android::StringPiece& name, const T& val, bool staged_api = false)
63       : name_(name.to_string()), 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(const android::StringPiece& name, const std::string& val, bool staged_api = false)
108       : name_(name.to_string()), 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(const android::StringPiece & name)144   explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {}
145 
AddElement(const T & val)146   void AddElement(const T& val) {
147     elements_.emplace_back(val);
148   }
149 
empty()150   bool empty() const override {
151     return false;
152   }
153 
GetName()154   const std::string& GetName() const override {
155     return name_;
156   }
157 
158   void Print(bool final, text::Printer* printer, bool strip_api_annotations = false)
159       const override {
160     ClassMember::Print(final, printer, strip_api_annotations);
161 
162     printer->Print("public static final int[] ").Print(name_).Print("={");
163     printer->Indent();
164 
165     const auto begin = elements_.begin();
166     const auto end = elements_.end();
167     for (auto current = begin; current != end; ++current) {
168       if (std::distance(begin, current) % kAttribsPerLine == 0) {
169         printer->Println();
170       }
171 
172       printer->Print(StringConverter::ToString(*current));
173       if (std::distance(current, end) > 1) {
174         printer->Print(", ");
175       }
176     }
177     printer->Println();
178     printer->Undent();
179     printer->Print("};");
180   }
181 
182  private:
183   DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
184 
185   std::string name_;
186   std::vector<T> elements_;
187 };
188 
189 struct FieldReference {
FieldReferenceFieldReference190   explicit FieldReference(std::string reference) : ref(std::move(reference)) {
191   }
192   std::string ref;
193 };
194 
195 struct ResourceArrayMemberStringConverter {
ToStringResourceArrayMemberStringConverter196   static std::string ToString(const std::variant<ResourceId, FieldReference>& ref) {
197     if (auto id = std::get_if<ResourceId>(&ref)) {
198       return to_string(*id);
199     } else {
200       return std::get<FieldReference>(ref).ref;
201     }
202   }
203 };
204 
205 using ResourceArrayMember = PrimitiveArrayMember<std::variant<ResourceId, FieldReference>,
206                                                  ResourceArrayMemberStringConverter>;
207 
208 // Represents a method in a class.
209 class MethodDefinition : public ClassMember {
210  public:
211   // Expected method signature example: 'public static void onResourcesLoaded(int p)'.
MethodDefinition(const android::StringPiece & signature)212   explicit MethodDefinition(const android::StringPiece& signature)
213       : signature_(signature.to_string()) {}
214 
215   // Appends a single statement to the method. It should include no newlines or else
216   // formatting may be broken.
217   void AppendStatement(const android::StringPiece& statement);
218 
219   // Not quite the same as a name, but good enough.
GetName()220   const std::string& GetName() const override {
221     return signature_;
222   }
223 
224   // Even if the method is empty, we always want to write the method signature.
empty()225   bool empty() const override {
226     return false;
227   }
228 
229   void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) const override;
230 
231  private:
232   DISALLOW_COPY_AND_ASSIGN(MethodDefinition);
233 
234   std::string signature_;
235   std::vector<std::string> statements_;
236 };
237 
238 enum class ClassQualifier { kNone, kStatic };
239 
240 class ClassDefinition : public ClassMember {
241  public:
242   static void WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
243                             bool final, bool strip_api_annotations, io::OutputStream* out);
244 
ClassDefinition(const android::StringPiece & name,ClassQualifier qualifier,bool createIfEmpty)245   ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
246       : name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
247 
248   enum class Result {
249     kAdded,
250     kOverridden,
251   };
252 
253   Result AddMember(std::unique_ptr<ClassMember> member);
254 
255   bool empty() const override;
256 
GetName()257   const std::string& GetName() const override {
258     return name_;
259   }
260 
261   void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) const override;
262 
263  private:
264   DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
265 
266   std::string name_;
267   ClassQualifier qualifier_;
268   bool create_if_empty_;
269   std::vector<std::unique_ptr<ClassMember>> ordered_members_;
270   std::unordered_map<android::StringPiece, size_t> indexed_members_;
271 };
272 
273 }  // namespace aapt
274 
275 #endif /* AAPT_JAVA_CLASSDEFINITION_H */
276