blob: aa4bb1e8a5b1203c4a93d348b8d334c735f4fb35 [file] [log] [blame]
Steven Morelandb0057e72018-08-27 01:44:11 -07001/*
2 * Copyright (C) 2018, 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 */
Jooyung Han7a9aceb2019-12-17 14:18:15 +000016#include "aidl_to_cpp_common.h"
Steven Morelandb0057e72018-08-27 01:44:11 -070017
Jooyung Han3df81ae2020-10-17 17:59:59 +090018#include <android-base/format.h>
Devin Moore53fc99c2020-08-12 08:07:52 -070019#include <android-base/stringprintf.h>
Jooyung Han7a9aceb2019-12-17 14:18:15 +000020#include <android-base/strings.h>
Jooyung Han3df81ae2020-10-17 17:59:59 +090021
22#include <set>
Jeongik Cha37e2ad52019-04-18 13:44:26 +090023#include <unordered_map>
Steven Morelandb0057e72018-08-27 01:44:11 -070024
Jooyung Han7a9aceb2019-12-17 14:18:15 +000025#include "ast_cpp.h"
Jeongik Cha37e2ad52019-04-18 13:44:26 +090026#include "logging.h"
Steven Morelandb0057e72018-08-27 01:44:11 -070027#include "os.h"
28
Jooyung Han7a9aceb2019-12-17 14:18:15 +000029using ::android::base::Join;
30
Steven Morelandb0057e72018-08-27 01:44:11 -070031namespace android {
32namespace aidl {
33namespace cpp {
34
Jooyung Han81003c32020-11-04 14:08:26 +090035char kTransactionLogStruct[] = R"(struct TransactionLog {
36 double duration_ms;
37 std::string interface_name;
38 std::string method_name;
39 const void* proxy_address;
40 const void* stub_address;
41 std::vector<std::pair<std::string, std::string>> input_args;
42 std::vector<std::pair<std::string, std::string>> output_args;
43 std::string result;
44 std::string exception_message;
45 int32_t exception_code;
46 int32_t transaction_error;
47 int32_t service_specific_error_code;
48};
49)";
50
Jooyung Hanb8e01b92020-11-01 16:49:13 +090051char kToStringHelper[] = R"(template <typename _T> class _has_toString {
52 template <typename _U> static std::true_type __has_toString(decltype(&_U::toString));
53 template <typename _U> static std::false_type __has_toString(...);
54 public: enum { value = decltype(__has_toString<_T>(nullptr))::value };
55};
56template <typename _T> inline static std::string _call_toString(const _T& t) {
57 if constexpr (_has_toString<_T>::value) return t.toString();
58 return "{no toString() implemented}";
Jooyung Han74b1dd42020-11-01 22:17:16 +090059}
Jooyung Hanb8e01b92020-11-01 16:49:13 +090060)";
Jooyung Han74b1dd42020-11-01 22:17:16 +090061
Steven Morelandb0057e72018-08-27 01:44:11 -070062string ClassName(const AidlDefinedType& defined_type, ClassNames type) {
Jiyong Park5b7e5322019-04-03 20:05:01 +090063 string base_name = defined_type.GetName();
64 if (base_name.length() >= 2 && base_name[0] == 'I' && isupper(base_name[1])) {
65 base_name = base_name.substr(1);
66 }
Steven Morelandb0057e72018-08-27 01:44:11 -070067
68 switch (type) {
69 case ClassNames::CLIENT:
Jiyong Park5b7e5322019-04-03 20:05:01 +090070 return "Bp" + base_name;
Steven Morelandb0057e72018-08-27 01:44:11 -070071 case ClassNames::SERVER:
Jiyong Park5b7e5322019-04-03 20:05:01 +090072 return "Bn" + base_name;
Steven Morelandb0057e72018-08-27 01:44:11 -070073 case ClassNames::INTERFACE:
Jiyong Park5b7e5322019-04-03 20:05:01 +090074 return "I" + base_name;
Steven Morelandb0057e72018-08-27 01:44:11 -070075 case ClassNames::DEFAULT_IMPL:
Jiyong Park5b7e5322019-04-03 20:05:01 +090076 return "I" + base_name + "Default";
Steven Morelandb0057e72018-08-27 01:44:11 -070077 case ClassNames::BASE:
Jiyong Park5b7e5322019-04-03 20:05:01 +090078 return base_name;
79 case ClassNames::RAW:
80 [[fallthrough]];
81 default:
82 return defined_type.GetName();
Steven Morelandb0057e72018-08-27 01:44:11 -070083 }
Steven Morelandb0057e72018-08-27 01:44:11 -070084}
85
86std::string HeaderFile(const AidlDefinedType& defined_type, ClassNames class_type,
87 bool use_os_sep) {
88 std::string file_path = defined_type.GetPackage();
89 for (char& c : file_path) {
90 if (c == '.') {
91 c = (use_os_sep) ? OS_PATH_SEPARATOR : '/';
92 }
93 }
94 if (!file_path.empty()) {
95 file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/';
96 }
97 file_path += ClassName(defined_type, class_type);
98 file_path += ".h";
99
100 return file_path;
101}
102
103void EnterNamespace(CodeWriter& out, const AidlDefinedType& defined_type) {
104 const std::vector<std::string> packages = defined_type.GetSplitPackage();
105 for (const std::string& package : packages) {
106 out << "namespace " << package << " {\n";
107 }
108}
109void LeaveNamespace(CodeWriter& out, const AidlDefinedType& defined_type) {
110 const std::vector<std::string> packages = defined_type.GetSplitPackage();
111 for (auto it = packages.rbegin(); it != packages.rend(); ++it) {
112 out << "} // namespace " << *it << "\n";
113 }
114}
115
Steven Moreland3b1325f2018-09-20 14:45:40 -0700116string BuildVarName(const AidlArgument& a) {
117 string prefix = "out_";
118 if (a.GetDirection() & AidlArgument::IN_DIR) {
119 prefix = "in_";
120 }
121 return prefix + a.GetName();
122}
123
Jooyung Han74b1dd42020-11-01 22:17:16 +0900124string ToString(const AidlTypeSpecifier& type, const string& expr);
125string ToStringNullable(const AidlTypeSpecifier& type, const string& expr);
126string ToStringNullableVector(const AidlTypeSpecifier& element_type, const string& expr);
127string ToStringVector(const AidlTypeSpecifier& element_type, const string& expr);
128string ToStringRaw(const AidlTypeSpecifier& type, const string& expr);
129
130string ToStringNullable(const AidlTypeSpecifier& type, const string& expr) {
131 if (AidlTypenames::IsPrimitiveTypename(type.GetName())) {
132 // we don't allow @nullable for primitives
133 return ToStringRaw(type, expr);
134 }
135 return "((" + expr + ") ? " + ToStringRaw(type, "*" + expr) + ": \"(null)\")";
136}
137
138string ToStringVector(const AidlTypeSpecifier& element_type, const string& expr) {
139 return "[&](){ std::ostringstream o; o << \"[\"; bool first = true; for (const auto& v: " + expr +
140 ") { (void)v; if (first) first = false; else o << \", \"; o << " +
141 ToStringRaw(element_type, "v") + "; }; o << \"]\"; return o.str(); }()";
142}
143
144string ToStringNullableVector(const AidlTypeSpecifier& element_type, const string& expr) {
145 return "[&](){ if (!(" + expr +
146 ")) return std::string(\"(null)\"); std::ostringstream o; o << \"[\"; bool first = true; "
147 "for (const auto& v: *(" +
148 expr + ")) { (void)v; if (first) first = false; else o << \", \"; o << " +
149 ToStringNullable(element_type, "v") + "; }; o << \"]\"; return o.str(); }()";
150}
151
152string ToStringRaw(const AidlTypeSpecifier& type, const string& expr) {
153 if (AidlTypenames::IsBuiltinTypename(type.GetName())) {
154 if (AidlTypenames::IsPrimitiveTypename(type.GetName())) {
155 if (type.GetName() == "boolean") {
156 return "(" + expr + "?\"true\":\"false\")";
157 }
158 if (type.GetName() == "char") {
159 return "std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(" +
160 expr + ")";
161 }
162 return "std::to_string(" + expr + ")";
163 }
164 if (type.GetName() == "String") {
165 return "(std::ostringstream() << " + expr + ").str()";
166 }
167 // ""(empty string) for unsupported types
168 return "\"\"";
169 }
170
171 const AidlDefinedType* defined_type = type.GetDefinedType();
172 AIDL_FATAL_IF(defined_type == nullptr, type);
173
174 if (defined_type->AsInterface()) {
175 // ""(empty string) for unsupported types
176 return "\"\"";
177 }
178 if (defined_type->AsEnumDeclaration()) {
179 const auto ns = Join(defined_type->GetSplitPackage(), "::");
180 return ns + "::toString(" + expr + ")";
181 }
182 return "_call_toString(" + expr + ")";
183}
184
185string ToString(const AidlTypeSpecifier& type, const string& expr) {
186 static const std::set<string> kNotSupported = {"Map", "IBinder", "ParcelFileDescriptor",
187 "ParcelableHolder"};
188 if (kNotSupported.find(type.GetName()) != kNotSupported.end()) {
189 // ""(empty string) for unsupported types
190 return "\"\"";
191 }
192 if (type.IsArray() && type.IsNullable()) {
193 const auto& element_type = type.ArrayBase();
194 return ToStringNullableVector(element_type, expr);
195 }
196 if (type.GetName() == "List" && type.IsNullable()) {
197 const auto& element_type = *type.GetTypeParameters()[0];
198 return ToStringNullableVector(element_type, expr);
199 }
200 if (type.IsArray()) {
201 const auto& element_type = type.ArrayBase();
202 return ToStringVector(element_type, expr);
203 }
204 if (type.GetName() == "List") {
205 const auto& element_type = *type.GetTypeParameters()[0];
206 return ToStringVector(element_type, expr);
207 }
208 if (type.IsNullable()) {
209 return ToStringNullable(type, expr);
210 }
211 return ToStringRaw(type, expr);
212}
213
Jooyung Han81003c32020-11-04 14:08:26 +0900214void WriteLogForArgument(CodeWriter& w, const AidlArgument& a, bool is_server,
215 const string& log_var, bool is_ndk) {
216 const string var_name = is_server || is_ndk ? BuildVarName(a) : a.GetName();
217 const bool is_pointer = a.IsOut() && !is_server;
218 const string value_expr = (is_pointer ? "*" : "") + var_name;
219 w << log_var
220 << ".emplace_back(\"" + var_name + "\", " + ToString(a.GetType(), value_expr) + ");\n";
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900221}
222
223const string GenLogBeforeExecute(const string className, const AidlMethod& method, bool isServer,
224 bool isNdk) {
225 string code;
226 CodeWriterPtr writer = CodeWriter::ForString(&code);
Jooyung Han81003c32020-11-04 14:08:26 +0900227 (*writer) << className << "::TransactionLog _transaction_log;\n";
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900228
229 (*writer) << "if (" << className << "::logFunc != nullptr) {\n";
230 (*writer).Indent();
231
Jooyung Han81003c32020-11-04 14:08:26 +0900232 for (const auto& a : method.GetInArguments()) {
233 WriteLogForArgument(*writer, *a, isServer, "_transaction_log.input_args", isNdk);
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900234 }
235
236 (*writer).Dedent();
237 (*writer) << "}\n";
238
239 (*writer) << "auto _log_start = std::chrono::steady_clock::now();\n";
240 writer->Close();
241 return code;
242}
243
244const string GenLogAfterExecute(const string className, const AidlInterface& interface,
245 const AidlMethod& method, const string& statusVarName,
246 const string& returnVarName, bool isServer, bool isNdk) {
247 string code;
248 CodeWriterPtr writer = CodeWriter::ForString(&code);
249
250 (*writer) << "if (" << className << "::logFunc != nullptr) {\n";
251 (*writer).Indent();
Jooyung Han81003c32020-11-04 14:08:26 +0900252 const auto address = (isNdk && isServer) ? "_aidl_impl.get()" : "static_cast<const void*>(this)";
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900253 (*writer) << "auto _log_end = std::chrono::steady_clock::now();\n";
Jooyung Han81003c32020-11-04 14:08:26 +0900254 (*writer) << "_transaction_log.duration_ms = std::chrono::duration<double, std::milli>(_log_end "
255 "- _log_start).count();\n";
256 (*writer) << "_transaction_log.interface_name = \"" << interface.GetCanonicalName() << "\";\n";
257 (*writer) << "_transaction_log.method_name = \"" << method.GetName() << "\";\n";
258 (*writer) << "_transaction_log.stub_address = " << (isServer ? address : "nullptr") << ";\n";
259 (*writer) << "_transaction_log.proxy_address = " << (isServer ? "nullptr" : address) << ";\n";
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900260
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900261 if (isNdk) {
Jooyung Han81003c32020-11-04 14:08:26 +0900262 (*writer) << "_transaction_log.exception_code = AStatus_getExceptionCode(" << statusVarName
263 << ".get());\n";
264 (*writer) << "_transaction_log.exception_message = AStatus_getMessage(" << statusVarName
265 << ".get());\n";
266 (*writer) << "_transaction_log.transaction_error = AStatus_getStatus(" << statusVarName
267 << ".get());\n";
268 (*writer) << "_transaction_log.service_specific_error_code = AStatus_getServiceSpecificError("
269 << statusVarName << ".get());\n";
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900270 } else {
Jooyung Han81003c32020-11-04 14:08:26 +0900271 (*writer) << "_transaction_log.exception_code = " << statusVarName << ".exceptionCode();\n";
272 (*writer) << "_transaction_log.exception_message = " << statusVarName
273 << ".exceptionMessage();\n";
274 (*writer) << "_transaction_log.transaction_error = " << statusVarName
275 << ".transactionError();\n";
276 (*writer) << "_transaction_log.service_specific_error_code = " << statusVarName
277 << ".serviceSpecificErrorCode();\n";
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900278 }
279
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900280 for (const auto& a : method.GetOutArguments()) {
Jooyung Han81003c32020-11-04 14:08:26 +0900281 WriteLogForArgument(*writer, *a, isServer, "_transaction_log.output_args", isNdk);
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900282 }
283
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900284 if (method.GetType().GetName() != "void") {
Jooyung Han81003c32020-11-04 14:08:26 +0900285 const string expr = (isServer ? "" : "*") + returnVarName;
286 (*writer) << "_transaction_log.result = " << ToString(method.GetType(), expr) << ";\n";
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900287 }
288
Jooyung Han81003c32020-11-04 14:08:26 +0900289 // call the user-provided function with the transaction log object
290 (*writer) << className << "::logFunc(_transaction_log);\n";
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900291
292 (*writer).Dedent();
293 (*writer) << "}\n";
294
295 writer->Close();
296 return code;
297}
298
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000299std::string GenerateEnumValues(const AidlEnumDeclaration& enum_decl,
300 const std::vector<std::string>& enclosing_namespaces_of_enum_decl) {
301 const auto fq_name =
302 Join(Append(enclosing_namespaces_of_enum_decl, enum_decl.GetSplitPackage()), "::") +
303 "::" + enum_decl.GetName();
304 const auto size = enum_decl.GetEnumerators().size();
305 std::ostringstream code;
Jooyung Han0e2a03c2019-12-17 23:25:39 +0900306 code << "#pragma clang diagnostic push\n";
307 code << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000308 code << "template <>\n";
Jooyung Han720253d2021-01-05 19:13:17 +0900309 code << "constexpr inline std::array<" << fq_name << ", " << size << ">";
310 GenerateDeprecated(code, enum_decl);
311 code << " enum_values<" << fq_name << "> = {\n";
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000312 for (const auto& enumerator : enum_decl.GetEnumerators()) {
313 code << " " << fq_name << "::" << enumerator->GetName() << ",\n";
314 }
315 code << "};\n";
Jooyung Han0e2a03c2019-12-17 23:25:39 +0900316 code << "#pragma clang diagnostic pop\n";
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000317 return code.str();
318}
319
Jooyung Han6beac042020-10-17 21:59:43 +0900320std::string TemplateDecl(const AidlParcelable& defined_type) {
Devin Moore53fc99c2020-08-12 08:07:52 -0700321 std::string decl = "";
322 if (defined_type.IsGeneric()) {
323 std::vector<std::string> template_params;
324 for (const auto& parameter : defined_type.GetTypeParameters()) {
325 template_params.push_back(parameter);
326 }
327 decl = base::StringPrintf("template <typename %s>\n",
328 base::Join(template_params, ", typename ").c_str());
329 }
330 return decl;
331}
332
Jooyung Han3df81ae2020-10-17 17:59:59 +0900333void GenerateParcelableComparisonOperators(CodeWriter& out, const AidlParcelable& parcelable) {
334 std::set<string> operators{"<", ">", "==", ">=", "<=", "!="};
335 bool is_empty = false;
336
337 auto comparable = [&](const string& prefix) {
338 vector<string> fields;
339 if (auto p = parcelable.AsStructuredParcelable(); p != nullptr) {
340 is_empty = p->GetFields().empty();
341 for (const auto& f : p->GetFields()) {
342 fields.push_back(prefix + f->GetName());
343 }
344 return "std::tie(" + Join(fields, ", ") + ")";
345 } else if (auto p = parcelable.AsUnionDeclaration(); p != nullptr) {
346 return prefix + "_value";
347 } else {
348 AIDL_FATAL(parcelable) << "Unknown paracelable type";
349 }
350 };
351
352 string lhs = comparable("");
353 string rhs = comparable("rhs.");
354 for (const auto& op : operators) {
355 out << "inline bool operator" << op << "(const " << parcelable.GetName() << "&"
356 << (is_empty ? "" : " rhs") << ") const {\n"
357 << " return " << lhs << " " << op << " " << rhs << ";\n"
358 << "}\n";
359 }
360 out << "\n";
361}
362
Jooyung Han74b1dd42020-11-01 22:17:16 +0900363// Output may look like:
364// inline std::string toString() const {
365// std::ostringstream os;
366// os << "MyData{";
367// os << "field1: " << field1;
368// os << ", field2: " << v.field2;
369// ...
370// os << "}";
371// return os.str();
372// }
373void GenerateToString(CodeWriter& out, const AidlStructuredParcelable& parcelable) {
374 out << kToStringHelper;
375 out << "inline std::string toString() const {\n";
376 out.Indent();
377 out << "std::ostringstream os;\n";
378 out << "os << \"" << parcelable.GetName() << "{\";\n";
379 bool first = true;
380 for (const auto& f : parcelable.GetFields()) {
381 if (first) {
382 out << "os << \"";
383 first = false;
384 } else {
385 out << "os << \", ";
386 }
387 out << f->GetName() << ": \" << " << ToString(f->GetType(), f->GetName()) << ";\n";
388 }
389 out << "os << \"}\";\n";
390 out << "return os.str();\n";
391 out.Dedent();
392 out << "}\n";
393}
394
395// Output may look like:
396// inline std::string toString() const {
397// std::ostringstream os;
398// os << "MyData{";
399// switch (v.getTag()) {
400// case MyData::field: os << "field: " << v.get<MyData::field>(); break;
401// ...
402// }
403// os << "}";
404// return os.str();
405// }
406void GenerateToString(CodeWriter& out, const AidlUnionDecl& parcelable) {
407 out << kToStringHelper;
408 out << "inline std::string toString() const {\n";
409 out.Indent();
410 out << "std::ostringstream os;\n";
411 out << "os << \"" + parcelable.GetName() + "{\";\n";
412 out << "switch (getTag()) {\n";
413 for (const auto& f : parcelable.GetFields()) {
414 const string tag = f->GetName();
415 out << "case " << tag << ": os << \"" << tag << ": \" << "
416 << ToString(f->GetType(), "get<" + tag + ">()") << "; break;\n";
417 }
418 out << "}\n";
419 out << "os << \"}\";\n";
420 out << "return os.str();\n";
421 out.Dedent();
422 out << "}\n";
423}
424
Jooyung Han3df81ae2020-10-17 17:59:59 +0900425const vector<string> UnionWriter::headers{
Jooyung Handf39e192020-11-23 15:59:46 +0900426 "cassert", // __assert for logging
Jooyung Han3df81ae2020-10-17 17:59:59 +0900427 "type_traits", // std::is_same_v
428 "utility", // std::mode/forward for value
429 "variant", // std::variant for value
430};
431
432void UnionWriter::PrivateFields(CodeWriter& out) const {
433 vector<string> field_types;
434 for (const auto& f : decl.GetFields()) {
435 field_types.push_back(name_of(f->GetType(), typenames));
436 }
437 out << "std::variant<" + Join(field_types, ", ") + "> _value;\n";
438}
439
440void UnionWriter::PublicFields(CodeWriter& out) const {
441 AidlTypeSpecifier tag_type(AIDL_LOCATION_HERE, "int", /* is_array= */ false,
442 /* type_params= */ nullptr, /* comments= */ "");
443 tag_type.Resolve(typenames);
444
445 out << "enum Tag : " << name_of(tag_type, typenames) << " {\n";
446 bool is_first = true;
447 for (const auto& f : decl.GetFields()) {
Jooyung Han720253d2021-01-05 19:13:17 +0900448 out << " " << f->GetName();
449 GenerateDeprecated(out, *f);
450 if (is_first) out << " = 0";
451 out << ", // " << f->Signature() << ";\n";
Jooyung Han3df81ae2020-10-17 17:59:59 +0900452 is_first = false;
453 }
454 out << "};\n";
455
456 const auto& name = decl.GetName();
457
458 AIDL_FATAL_IF(decl.GetFields().empty(), decl) << "Union '" << name << "' is empty.";
459 const auto& first_field = decl.GetFields()[0];
460 const auto& default_name = first_field->GetName();
461 const auto& default_value =
462 name_of(first_field->GetType(), typenames) + "(" + first_field->ValueString(decorator) + ")";
463
464 auto tmpl = R"--(
465template<typename _Tp>
466static constexpr bool _not_self = !std::is_same_v<std::remove_cv_t<std::remove_reference_t<_Tp>>, {name}>;
467
468{name}() : _value(std::in_place_index<{default_name}>, {default_value}) {{ }}
469{name}(const {name}&) = default;
470{name}({name}&&) = default;
471{name}& operator=(const {name}&) = default;
472{name}& operator=({name}&&) = default;
473
Jiyong Parkdd57f1a2020-11-16 20:19:55 +0900474template <typename _Tp, typename = std::enable_if_t<_not_self<_Tp>>>
475// NOLINTNEXTLINE(google-explicit-constructor)
Jooyung Han3df81ae2020-10-17 17:59:59 +0900476constexpr {name}(_Tp&& _arg)
477 : _value(std::forward<_Tp>(_arg)) {{}}
478
479template <typename... _Tp>
480constexpr explicit {name}(_Tp&&... _args)
481 : _value(std::forward<_Tp>(_args)...) {{}}
482
483template <Tag _tag, typename... _Tp>
484static {name} make(_Tp&&... _args) {{
485 return {name}(std::in_place_index<_tag>, std::forward<_Tp>(_args)...);
486}}
487
488template <Tag _tag, typename _Tp, typename... _Up>
489static {name} make(std::initializer_list<_Tp> _il, _Up&&... _args) {{
490 return {name}(std::in_place_index<_tag>, std::move(_il), std::forward<_Up>(_args)...);
491}}
492
493Tag getTag() const {{
494 return static_cast<Tag>(_value.index());
495}}
496
497template <Tag _tag>
498const auto& get() const {{
Jooyung Handf39e192020-11-23 15:59:46 +0900499 if (getTag() != _tag) {{ __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__, "bad access: a wrong tag"); }}
Jooyung Han3df81ae2020-10-17 17:59:59 +0900500 return std::get<_tag>(_value);
501}}
502
503template <Tag _tag>
504auto& get() {{
Jooyung Handf39e192020-11-23 15:59:46 +0900505 if (getTag() != _tag) {{ __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__, "bad access: a wrong tag"); }}
Jooyung Han3df81ae2020-10-17 17:59:59 +0900506 return std::get<_tag>(_value);
507}}
508
509template <Tag _tag, typename... _Tp>
510void set(_Tp&&... _args) {{
511 _value.emplace<_tag>(std::forward<_Tp>(_args)...);
512}}
513
514)--";
515 out << fmt::format(tmpl, fmt::arg("name", name), fmt::arg("default_name", default_name),
516 fmt::arg("default_value", default_value));
517}
518
519void UnionWriter::ReadFromParcel(CodeWriter& out, const ParcelWriterContext& ctx) const {
520 AidlTypeSpecifier tag_type(AIDL_LOCATION_HERE, "int", /* is_array= */ false,
521 /* type_params= */ nullptr, /* comments= */ "");
522 tag_type.Resolve(typenames);
523
524 const string tag = "_aidl_tag";
525 const string value = "_aidl_value";
526 const string status = "_aidl_ret_status";
527
528 auto read_var = [&](const string& var, const AidlTypeSpecifier& type) {
529 out << fmt::format("{} {};\n", name_of(type, typenames), var);
530 out << fmt::format("if (({} = ", status);
531 ctx.read_func(out, var, type);
532 out << fmt::format(") != {}) return {};\n", ctx.status_ok, status);
533 };
534
535 out << fmt::format("{} {};\n", ctx.status_type, status);
536 read_var(tag, tag_type);
537 out << fmt::format("switch ({}) {{\n", tag);
538 for (const auto& variable : decl.GetFields()) {
539 out << fmt::format("case {}: {{\n", variable->GetName());
540 out.Indent();
Jiyong Parkdd57f1a2020-11-16 20:19:55 +0900541 const auto& type = variable->GetType();
542 read_var(value, type);
543 out << fmt::format("if constexpr (std::is_trivially_copyable_v<{}>) {{\n",
544 name_of(type, typenames));
545 out.Indent();
546 out << fmt::format("set<{}>({});\n", variable->GetName(), value);
547 out.Dedent();
548 out << "} else {\n";
549 out.Indent();
550 // Even when the `if constexpr` is false, the compiler runs the tidy check for the
551 // next line, which doesn't make sense. Silence the check for the unreachable code.
552 out << "// NOLINTNEXTLINE(performance-move-const-arg)\n";
Jooyung Han3df81ae2020-10-17 17:59:59 +0900553 out << fmt::format("set<{}>(std::move({}));\n", variable->GetName(), value);
Jiyong Parkdd57f1a2020-11-16 20:19:55 +0900554 out.Dedent();
555 out << "}\n";
Jooyung Han3df81ae2020-10-17 17:59:59 +0900556 out << fmt::format("return {}; }}\n", ctx.status_ok);
557 out.Dedent();
558 }
559 out << "}\n";
560 out << fmt::format("return {};\n", ctx.status_bad);
561}
562
563void UnionWriter::WriteToParcel(CodeWriter& out, const ParcelWriterContext& ctx) const {
564 AidlTypeSpecifier tag_type(AIDL_LOCATION_HERE, "int", /* is_array= */ false,
565 /* type_params= */ nullptr, /* comments= */ "");
566 tag_type.Resolve(typenames);
567
568 const string tag = "_aidl_tag";
569 const string value = "_aidl_value";
570 const string status = "_aidl_ret_status";
571
572 out << fmt::format("{} {} = ", ctx.status_type, status);
573 ctx.write_func(out, "getTag()", tag_type);
574 out << ";\n";
575 out << fmt::format("if ({} != {}) return {};\n", status, ctx.status_ok, status);
576 out << "switch (getTag()) {\n";
577 for (const auto& variable : decl.GetFields()) {
578 out << fmt::format("case {}: return ", variable->GetName());
579 ctx.write_func(out, "get<" + variable->GetName() + ">()", variable->GetType());
580 out << ";\n";
581 }
582 out << "}\n";
Jooyung Handf39e192020-11-23 15:59:46 +0900583 out << "__assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__, \"can't reach here\");\n";
Jooyung Han3df81ae2020-10-17 17:59:59 +0900584}
585
Steven Morelandb0057e72018-08-27 01:44:11 -0700586} // namespace cpp
587} // namespace aidl
588} // namespace android