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) const;
54 
55  private:
56   AnnotationProcessor processor_;
57 };
58 
59 template <typename T>
60 class PrimitiveMember : public ClassMember {
61  public:
PrimitiveMember(const android::StringPiece & name,const T & val)62   PrimitiveMember(const android::StringPiece& name, const T& val)
63       : name_(name.to_string()), val_(val) {}
64 
empty()65   bool empty() const override {
66     return false;
67   }
68 
GetName()69   const std::string& GetName() const override {
70     return name_;
71   }
72 
Print(bool final,text::Printer * printer)73   void Print(bool final, text::Printer* printer) const override {
74     using std::to_string;
75 
76     ClassMember::Print(final, printer);
77 
78     printer->Print("public static ");
79     if (final) {
80       printer->Print("final ");
81     }
82     printer->Print("int ").Print(name_).Print("=").Print(to_string(val_)).Print(";");
83   }
84 
85  private:
86   DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
87 
88   std::string name_;
89   T val_;
90 };
91 
92 // Specialization for strings so they get the right type and are quoted with "".
93 template <>
94 class PrimitiveMember<std::string> : public ClassMember {
95  public:
PrimitiveMember(const android::StringPiece & name,const std::string & val)96   PrimitiveMember(const android::StringPiece& name, const std::string& val)
97       : name_(name.to_string()), val_(val) {}
98 
empty()99   bool empty() const override {
100     return false;
101   }
102 
GetName()103   const std::string& GetName() const override {
104     return name_;
105   }
106 
Print(bool final,text::Printer * printer)107   void Print(bool final, text::Printer* printer) const override {
108     ClassMember::Print(final, printer);
109 
110     printer->Print("public static ");
111     if (final) {
112       printer->Print("final ");
113     }
114     printer->Print("String ").Print(name_).Print("=\"").Print(val_).Print("\";");
115   }
116 
117  private:
118   DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
119 
120   std::string name_;
121   std::string val_;
122 };
123 
124 using IntMember = PrimitiveMember<uint32_t>;
125 using ResourceMember = PrimitiveMember<ResourceId>;
126 using StringMember = PrimitiveMember<std::string>;
127 
128 template <typename T>
129 class PrimitiveArrayMember : public ClassMember {
130  public:
PrimitiveArrayMember(const android::StringPiece & name)131   explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {}
132 
AddElement(const T & val)133   void AddElement(const T& val) {
134     elements_.push_back(val);
135   }
136 
empty()137   bool empty() const override {
138     return false;
139   }
140 
GetName()141   const std::string& GetName() const override {
142     return name_;
143   }
144 
Print(bool final,text::Printer * printer)145   void Print(bool final, text::Printer* printer) const override {
146     ClassMember::Print(final, printer);
147 
148     printer->Print("public static final int[] ").Print(name_).Print("={");
149     printer->Indent();
150 
151     const auto begin = elements_.begin();
152     const auto end = elements_.end();
153     for (auto current = begin; current != end; ++current) {
154       if (std::distance(begin, current) % kAttribsPerLine == 0) {
155         printer->Println();
156       }
157 
158       printer->Print(to_string(*current));
159       if (std::distance(current, end) > 1) {
160         printer->Print(", ");
161       }
162     }
163     printer->Println();
164     printer->Undent();
165     printer->Print("};");
166   }
167 
168  private:
169   DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
170 
171   std::string name_;
172   std::vector<T> elements_;
173 };
174 
175 using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
176 
177 // Represents a method in a class.
178 class MethodDefinition : public ClassMember {
179  public:
180   // Expected method signature example: 'public static void onResourcesLoaded(int p)'.
MethodDefinition(const android::StringPiece & signature)181   explicit MethodDefinition(const android::StringPiece& signature)
182       : signature_(signature.to_string()) {}
183 
184   // Appends a single statement to the method. It should include no newlines or else
185   // formatting may be broken.
186   void AppendStatement(const android::StringPiece& statement);
187 
188   // Not quite the same as a name, but good enough.
GetName()189   const std::string& GetName() const override {
190     return signature_;
191   }
192 
193   // Even if the method is empty, we always want to write the method signature.
empty()194   bool empty() const override {
195     return false;
196   }
197 
198   void Print(bool final, text::Printer* printer) const override;
199 
200  private:
201   DISALLOW_COPY_AND_ASSIGN(MethodDefinition);
202 
203   std::string signature_;
204   std::vector<std::string> statements_;
205 };
206 
207 enum class ClassQualifier { kNone, kStatic };
208 
209 class ClassDefinition : public ClassMember {
210  public:
211   static void WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
212                             bool final, io::OutputStream* out);
213 
ClassDefinition(const android::StringPiece & name,ClassQualifier qualifier,bool createIfEmpty)214   ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
215       : name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
216 
217   enum class Result {
218     kAdded,
219     kOverridden,
220   };
221 
222   Result AddMember(std::unique_ptr<ClassMember> member);
223 
224   bool empty() const override;
225 
GetName()226   const std::string& GetName() const override {
227     return name_;
228   }
229 
230   void Print(bool final, text::Printer* printer) const override;
231 
232  private:
233   DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
234 
235   std::string name_;
236   ClassQualifier qualifier_;
237   bool create_if_empty_;
238   std::vector<std::unique_ptr<ClassMember>> ordered_members_;
239   std::unordered_map<android::StringPiece, size_t> indexed_members_;
240 };
241 
242 }  // namespace aapt
243 
244 #endif /* AAPT_JAVA_CLASSDEFINITION_H */
245