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