1 /*
2  * Copyright (C) 2021, 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 #include "aidl_dumpapi.h"
18 
19 #include <android-base/strings.h>
20 
21 #include "aidl.h"
22 #include "logging.h"
23 #include "os.h"
24 
25 using android::base::EndsWith;
26 using android::base::Join;
27 using android::base::Split;
28 using std::string;
29 using std::unique_ptr;
30 
31 namespace android {
32 namespace aidl {
33 
NeedsFinalValue(const AidlTypeSpecifier & type,const AidlConstantValue & c)34 static bool NeedsFinalValue(const AidlTypeSpecifier& type, const AidlConstantValue& c) {
35   // For enum types, use enumerator
36   if (auto defined_type = type.GetDefinedType();
37       defined_type && defined_type->AsEnumDeclaration()) {
38     return false;
39   }
40   // We need final value for constant expression which is not a single constant expression.
41   struct Visitor : AidlVisitor {
42     bool trivial = true;
43     void Visit(const AidlConstantReference&) override { trivial = false; }
44     void Visit(const AidlUnaryConstExpression&) override { trivial = false; }
45     void Visit(const AidlBinaryConstExpression&) override { trivial = false; }
46   } v;
47   c.DispatchVisit(v);
48   return !v.trivial;
49 }
50 
DumpType(const AidlDefinedType & dt,const string & type)51 void DumpVisitor::DumpType(const AidlDefinedType& dt, const string& type) {
52   if (!dt.IsUserDefined()) {
53     return;
54   }
55   DumpComments(dt);
56   DumpAnnotations(dt);
57   out << type << " " << dt.GetName();
58   if (auto generic_type = dt.AsParameterizable(); generic_type && generic_type->IsGeneric()) {
59     out << "<" << Join(generic_type->GetTypeParameters(), ", ") << ">";
60   }
61 
62   if (dt.AsUnstructuredParcelable()) {
63     out << ";\n";
64     return;
65   }
66 
67   out << " {\n";
68   out.Indent();
69   DumpMembers(dt);
70   out.Dedent();
71   out << "}\n";
72 }
73 
DumpMembers(const AidlDefinedType & dt)74 void DumpVisitor::DumpMembers(const AidlDefinedType& dt) {
75   for (const auto& method : dt.GetMethods()) {
76     method->DispatchVisit(*this);
77   }
78   for (const auto& field : dt.GetFields()) {
79     field->DispatchVisit(*this);
80   }
81   for (const auto& constdecl : dt.GetConstantDeclarations()) {
82     constdecl->DispatchVisit(*this);
83   }
84   for (const auto& nested : dt.GetNestedTypes()) {
85     nested->DispatchVisit(*this);
86   }
87 }
88 
89 // Dumps comment only if its has meaningful tags.
DumpComments(const AidlCommentable & c)90 void DumpVisitor::DumpComments(const AidlCommentable& c) {
91   const auto hidden = c.IsHidden();
92   const auto deprecated = FindDeprecated(c.GetComments());
93   if (hidden && !deprecated) {
94     // to pass --checkapi between the current and the tot in the mainline-prod branch
95     // emit @hide in a legacy dump style
96     out << "/* @hide */\n";
97   } else if (hidden || deprecated) {
98     out << "/**\n";
99     if (hidden) {
100       out << " * @hide\n";
101     }
102     if (deprecated) {
103       out << " * @deprecated " << deprecated->note << "\n";
104     }
105     out << " */\n";
106   }
107 }
108 
DumpAnnotations(const AidlAnnotatable & a)109 void DumpVisitor::DumpAnnotations(const AidlAnnotatable& a) {
110   auto annotations = a.ToString();
111   if (!annotations.empty()) {
112     out << annotations << "\n";
113   }
114 }
115 
DumpConstantValue(const AidlTypeSpecifier & type,const AidlConstantValue & c)116 void DumpVisitor::DumpConstantValue(const AidlTypeSpecifier& type, const AidlConstantValue& c) {
117   if (inline_constants) {
118     out << c.ValueString(type, AidlConstantValueDecorator);
119     return;
120   }
121   if (c.GetType() == AidlConstantValue::Type::ARRAY) {
122     type.ViewAsArrayBase([&](const auto& base_type) {
123       out << "{";
124       for (size_t i = 0; i < c.Size(); i++) {
125         if (i > 0) {
126           out << ", ";
127         }
128         DumpConstantValue(base_type, c.ValueAt(i));
129       }
130       out << "}";
131     });
132   } else {
133     c.DispatchVisit(*this);
134     // print final value as comment
135     if (NeedsFinalValue(type, c)) {
136       out << " /* " << c.ValueString(type, AidlConstantValueDecorator) << " */";
137     }
138   }
139 }
140 
Visit(const AidlInterface & t)141 void DumpVisitor::Visit(const AidlInterface& t) {
142   DumpType(t, "interface");
143 }
144 
Visit(const AidlParcelable & t)145 void DumpVisitor::Visit(const AidlParcelable& t) {
146   DumpType(t, "parcelable");
147 }
148 
Visit(const AidlStructuredParcelable & t)149 void DumpVisitor::Visit(const AidlStructuredParcelable& t) {
150   DumpType(t, "parcelable");
151 }
152 
Visit(const AidlUnionDecl & t)153 void DumpVisitor::Visit(const AidlUnionDecl& t) {
154   DumpType(t, "union");
155 }
156 
Visit(const AidlEnumDeclaration & t)157 void DumpVisitor::Visit(const AidlEnumDeclaration& t) {
158   if (!t.IsUserDefined()) {
159     return;
160   }
161   DumpComments(t);
162   DumpAnnotations(t);
163   out << "enum " << t.GetName() << " {\n";
164   out.Indent();
165   for (const auto& e : t.GetEnumerators()) {
166     DumpComments(*e);
167     out << e->GetName();
168     if (e->IsValueUserSpecified() || inline_constants) {
169       out << " = ";
170       DumpConstantValue(t.GetBackingType(), *e->GetValue());
171     }
172     out << ",\n";
173   }
174   out.Dedent();
175   out << "}\n";
176 }
177 
Visit(const AidlMethod & m)178 void DumpVisitor::Visit(const AidlMethod& m) {
179   if (!m.IsUserDefined()) {
180     return;
181   }
182   DumpComments(m);
183   out << m.ToString() << ";\n";
184 }
185 
Visit(const AidlVariableDeclaration & v)186 void DumpVisitor::Visit(const AidlVariableDeclaration& v) {
187   if (!v.IsUserDefined()) {
188     return;
189   }
190   DumpComments(v);
191   Visit(v.GetType());
192   if (v.IsDefaultUserSpecified()) {
193     out << " " << v.GetName() << " = ";
194     DumpConstantValue(v.GetType(), *v.GetDefaultValue());
195     out << ";\n";
196   } else {
197     out << " " << v.GetName() << ";\n";
198   }
199 }
200 
Visit(const AidlConstantDeclaration & c)201 void DumpVisitor::Visit(const AidlConstantDeclaration& c) {
202   if (!c.IsUserDefined()) {
203     return;
204   }
205   DumpComments(c);
206   out << "const ";
207   Visit(c.GetType());
208   out << " " << c.GetName() << " = ";
209   DumpConstantValue(c.GetType(), c.GetValue());
210   out << ";\n";
211 }
212 
Visit(const AidlTypeSpecifier & t)213 void DumpVisitor::Visit(const AidlTypeSpecifier& t) {
214   out << t.ToString();
215 }
216 
217 // These Visit() methods are not invoked when inline_constants = true
Visit(const AidlConstantValue & c)218 void DumpVisitor::Visit(const AidlConstantValue& c) {
219   AIDL_FATAL_IF(inline_constants, AIDL_LOCATION_HERE);
220   out << c.Literal();
221 }
222 
Visit(const AidlConstantReference & r)223 void DumpVisitor::Visit(const AidlConstantReference& r) {
224   AIDL_FATAL_IF(inline_constants, AIDL_LOCATION_HERE);
225   if (auto& ref = r.GetRefType(); ref) {
226     ref->DispatchVisit(*this);
227     out << ".";
228   }
229   out << r.GetFieldName();
230 }
231 
Visit(const AidlBinaryConstExpression & b)232 void DumpVisitor::Visit(const AidlBinaryConstExpression& b) {
233   AIDL_FATAL_IF(inline_constants, AIDL_LOCATION_HERE);
234   // TODO(b/262594867) put parentheses only when necessary
235   out << "(";
236   b.Left()->DispatchVisit(*this);
237   out << " " << b.Op() << " ";
238   b.Right()->DispatchVisit(*this);
239   out << ")";
240 }
241 
Visit(const AidlUnaryConstExpression & u)242 void DumpVisitor::Visit(const AidlUnaryConstExpression& u) {
243   AIDL_FATAL_IF(inline_constants, AIDL_LOCATION_HERE);
244   // TODO(b/262594867) put parentheses only when necessary
245   out << "(";
246   out << u.Op();
247   u.Val()->DispatchVisit(*this);
248   out << ")";
249 }
250 
GetApiDumpPathFor(const AidlDefinedType & defined_type,const Options & options)251 static string GetApiDumpPathFor(const AidlDefinedType& defined_type, const Options& options) {
252   string package_as_path = Join(Split(defined_type.GetPackage(), "."), OS_PATH_SEPARATOR);
253   AIDL_FATAL_IF(options.OutputDir().empty() || options.OutputDir().back() != OS_PATH_SEPARATOR,
254                 defined_type);
255   return options.OutputDir() + package_as_path + OS_PATH_SEPARATOR + defined_type.GetName() +
256          ".aidl";
257 }
258 
DumpComments(CodeWriter & out,const Comments & comments)259 static void DumpComments(CodeWriter& out, const Comments& comments) {
260   bool needs_newline = false;
261   for (const auto& c : comments) {
262     out << c.body;
263     needs_newline = !EndsWith(c.body, "\n");
264   }
265   if (needs_newline) {
266     out << "\n";
267   }
268 }
269 
dump_api(const Options & options,const IoDelegate & io_delegate)270 bool dump_api(const Options& options, const IoDelegate& io_delegate) {
271   for (const auto& file : options.InputFiles()) {
272     AidlTypenames typenames;
273     if (internals::load_and_validate_aidl(file, options, io_delegate, &typenames, nullptr) ==
274         AidlError::OK) {
275       const auto& doc = typenames.MainDocument();
276 
277       for (const auto& type : doc.DefinedTypes()) {
278         unique_ptr<CodeWriter> writer =
279             io_delegate.GetCodeWriter(GetApiDumpPathFor(*type, options));
280         if (!options.DumpNoLicense()) {
281           // dump doc comments (license) as well for each type
282           DumpComments(*writer, doc.GetComments());
283         }
284         (*writer) << kPreamble;
285         if (!type->GetPackage().empty()) {
286           (*writer) << "package " << type->GetPackage() << ";\n";
287         }
288         DumpVisitor visitor(*writer, /*inline_constants=*/false);
289         type->DispatchVisit(visitor);
290       }
291     } else {
292       return false;
293     }
294   }
295   return true;
296 }
297 
298 }  // namespace aidl
299 }  // namespace android
300