blob: 58dafdb406582bd03af77933ce80999687c19bc1 [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 Han74b1dd42020-11-01 22:17:16 +090035namespace {
36constexpr char kToStringHelper[] =
37 R"(template <typename _T, ::std::enable_if_t<::std::is_same_v<::std::string, decltype(std::declval<_T>().toString())>, int> = 0>
38static inline ::std::string _call_toString(const _T& _t) { return _t.toString(); }
39static inline ::std::string _call_toString(...) { return "{no toString() implemented}"; }
40)";
41}
42
Steven Morelandb0057e72018-08-27 01:44:11 -070043string ClassName(const AidlDefinedType& defined_type, ClassNames type) {
Jiyong Park5b7e5322019-04-03 20:05:01 +090044 string base_name = defined_type.GetName();
45 if (base_name.length() >= 2 && base_name[0] == 'I' && isupper(base_name[1])) {
46 base_name = base_name.substr(1);
47 }
Steven Morelandb0057e72018-08-27 01:44:11 -070048
49 switch (type) {
50 case ClassNames::CLIENT:
Jiyong Park5b7e5322019-04-03 20:05:01 +090051 return "Bp" + base_name;
Steven Morelandb0057e72018-08-27 01:44:11 -070052 case ClassNames::SERVER:
Jiyong Park5b7e5322019-04-03 20:05:01 +090053 return "Bn" + base_name;
Steven Morelandb0057e72018-08-27 01:44:11 -070054 case ClassNames::INTERFACE:
Jiyong Park5b7e5322019-04-03 20:05:01 +090055 return "I" + base_name;
Steven Morelandb0057e72018-08-27 01:44:11 -070056 case ClassNames::DEFAULT_IMPL:
Jiyong Park5b7e5322019-04-03 20:05:01 +090057 return "I" + base_name + "Default";
Steven Morelandb0057e72018-08-27 01:44:11 -070058 case ClassNames::BASE:
Jiyong Park5b7e5322019-04-03 20:05:01 +090059 return base_name;
60 case ClassNames::RAW:
61 [[fallthrough]];
62 default:
63 return defined_type.GetName();
Steven Morelandb0057e72018-08-27 01:44:11 -070064 }
Steven Morelandb0057e72018-08-27 01:44:11 -070065}
66
67std::string HeaderFile(const AidlDefinedType& defined_type, ClassNames class_type,
68 bool use_os_sep) {
69 std::string file_path = defined_type.GetPackage();
70 for (char& c : file_path) {
71 if (c == '.') {
72 c = (use_os_sep) ? OS_PATH_SEPARATOR : '/';
73 }
74 }
75 if (!file_path.empty()) {
76 file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/';
77 }
78 file_path += ClassName(defined_type, class_type);
79 file_path += ".h";
80
81 return file_path;
82}
83
84void EnterNamespace(CodeWriter& out, const AidlDefinedType& defined_type) {
85 const std::vector<std::string> packages = defined_type.GetSplitPackage();
86 for (const std::string& package : packages) {
87 out << "namespace " << package << " {\n";
88 }
89}
90void LeaveNamespace(CodeWriter& out, const AidlDefinedType& defined_type) {
91 const std::vector<std::string> packages = defined_type.GetSplitPackage();
92 for (auto it = packages.rbegin(); it != packages.rend(); ++it) {
93 out << "} // namespace " << *it << "\n";
94 }
95}
96
Steven Moreland3b1325f2018-09-20 14:45:40 -070097string BuildVarName(const AidlArgument& a) {
98 string prefix = "out_";
99 if (a.GetDirection() & AidlArgument::IN_DIR) {
100 prefix = "in_";
101 }
102 return prefix + a.GetName();
103}
104
Jooyung Han74b1dd42020-11-01 22:17:16 +0900105string ToString(const AidlTypeSpecifier& type, const string& expr);
106string ToStringNullable(const AidlTypeSpecifier& type, const string& expr);
107string ToStringNullableVector(const AidlTypeSpecifier& element_type, const string& expr);
108string ToStringVector(const AidlTypeSpecifier& element_type, const string& expr);
109string ToStringRaw(const AidlTypeSpecifier& type, const string& expr);
110
111string ToStringNullable(const AidlTypeSpecifier& type, const string& expr) {
112 if (AidlTypenames::IsPrimitiveTypename(type.GetName())) {
113 // we don't allow @nullable for primitives
114 return ToStringRaw(type, expr);
115 }
116 return "((" + expr + ") ? " + ToStringRaw(type, "*" + expr) + ": \"(null)\")";
117}
118
119string ToStringVector(const AidlTypeSpecifier& element_type, const string& expr) {
120 return "[&](){ std::ostringstream o; o << \"[\"; bool first = true; for (const auto& v: " + expr +
121 ") { (void)v; if (first) first = false; else o << \", \"; o << " +
122 ToStringRaw(element_type, "v") + "; }; o << \"]\"; return o.str(); }()";
123}
124
125string ToStringNullableVector(const AidlTypeSpecifier& element_type, const string& expr) {
126 return "[&](){ if (!(" + expr +
127 ")) return std::string(\"(null)\"); std::ostringstream o; o << \"[\"; bool first = true; "
128 "for (const auto& v: *(" +
129 expr + ")) { (void)v; if (first) first = false; else o << \", \"; o << " +
130 ToStringNullable(element_type, "v") + "; }; o << \"]\"; return o.str(); }()";
131}
132
133string ToStringRaw(const AidlTypeSpecifier& type, const string& expr) {
134 if (AidlTypenames::IsBuiltinTypename(type.GetName())) {
135 if (AidlTypenames::IsPrimitiveTypename(type.GetName())) {
136 if (type.GetName() == "boolean") {
137 return "(" + expr + "?\"true\":\"false\")";
138 }
139 if (type.GetName() == "char") {
140 return "std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(" +
141 expr + ")";
142 }
143 return "std::to_string(" + expr + ")";
144 }
145 if (type.GetName() == "String") {
146 return "(std::ostringstream() << " + expr + ").str()";
147 }
148 // ""(empty string) for unsupported types
149 return "\"\"";
150 }
151
152 const AidlDefinedType* defined_type = type.GetDefinedType();
153 AIDL_FATAL_IF(defined_type == nullptr, type);
154
155 if (defined_type->AsInterface()) {
156 // ""(empty string) for unsupported types
157 return "\"\"";
158 }
159 if (defined_type->AsEnumDeclaration()) {
160 const auto ns = Join(defined_type->GetSplitPackage(), "::");
161 return ns + "::toString(" + expr + ")";
162 }
163 return "_call_toString(" + expr + ")";
164}
165
166string ToString(const AidlTypeSpecifier& type, const string& expr) {
167 static const std::set<string> kNotSupported = {"Map", "IBinder", "ParcelFileDescriptor",
168 "ParcelableHolder"};
169 if (kNotSupported.find(type.GetName()) != kNotSupported.end()) {
170 // ""(empty string) for unsupported types
171 return "\"\"";
172 }
173 if (type.IsArray() && type.IsNullable()) {
174 const auto& element_type = type.ArrayBase();
175 return ToStringNullableVector(element_type, expr);
176 }
177 if (type.GetName() == "List" && type.IsNullable()) {
178 const auto& element_type = *type.GetTypeParameters()[0];
179 return ToStringNullableVector(element_type, expr);
180 }
181 if (type.IsArray()) {
182 const auto& element_type = type.ArrayBase();
183 return ToStringVector(element_type, expr);
184 }
185 if (type.GetName() == "List") {
186 const auto& element_type = *type.GetTypeParameters()[0];
187 return ToStringVector(element_type, expr);
188 }
189 if (type.IsNullable()) {
190 return ToStringNullable(type, expr);
191 }
192 return ToStringRaw(type, expr);
193}
194
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900195struct TypeInfo {
196 // name of the type in C++ output
197 std::string cpp_name;
198
199 // function that writes an expression to convert a variable to a Json::Value
200 // object
201 std::function<void(CodeWriter& w, const string& var_name, bool isNdk)> toJsonValueExpr;
202};
203
204const static std::unordered_map<std::string, TypeInfo> kTypeInfoMap = {
205 {"void", {"void", nullptr}},
206 {"boolean",
207 {
208 "bool",
209 [](CodeWriter& c, const string& var_name, bool) {
210 c << "Json::Value(" << var_name << "? \"true\" : \"false\")";
211 },
212 }},
213 {"byte",
214 {
215 "int8_t",
216 [](CodeWriter& c, const string& var_name, bool) {
217 c << "Json::Value(" << var_name << ")";
218 },
219 }},
220 {"char",
221 {
222 "char16_t",
223 [](CodeWriter& c, const string& var_name, bool isNdk) {
224 if (isNdk) {
225 c << "Json::Value(" << var_name << ")";
226 } else {
227 c << "Json::Value(std::string(android::String8(&" << var_name << ", 1)))";
228 }
229 },
230 }},
231 {"int",
232 {
233 "int32_t",
234 [](CodeWriter& c, const string& var_name, bool) {
235 c << "Json::Value(" << var_name << ")";
236 },
237 }},
238 {"long",
239 {
240 "int64_t",
241 [](CodeWriter& c, const string& var_name, bool) {
242 c << "Json::Value(static_cast<Json::Int64>(" << var_name << "))";
243 },
244 }},
245 {"float",
246 {
247 "float",
248 [](CodeWriter& c, const string& var_name, bool) {
249 c << "Json::Value(" << var_name << ")";
250 },
251 }},
252 {"double",
253 {
254 "double",
255 [](CodeWriter& c, const string& var_name, bool) {
256 c << "Json::Value(" << var_name << ")";
257 },
258 }},
259 {"String",
260 {
261 "std::string",
262 [](CodeWriter& c, const string& var_name, bool) {
263 c << "Json::Value(" << var_name << ")";
264 },
265 }}
266 // missing List, Map, ParcelFileDescriptor, IBinder
267};
268
269TypeInfo GetTypeInfo(const AidlTypeSpecifier& aidl) {
Steven Moreland21780812020-09-11 01:29:45 +0000270 AIDL_FATAL_IF(!aidl.IsResolved(), aidl) << aidl.ToString();
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900271 const string& aidl_name = aidl.GetName();
272
273 TypeInfo info;
274 if (AidlTypenames::IsBuiltinTypename(aidl_name)) {
275 auto it = kTypeInfoMap.find(aidl_name);
276 if (it != kTypeInfoMap.end()) {
277 info = it->second;
278 }
279 }
280 // Missing interface and parcelable type
281 return info;
282}
283
284inline bool CanWriteLog(const TypeInfo& t) {
285 return t.cpp_name != "";
286}
287
288bool CanWriteLog(const AidlTypeSpecifier& aidl) {
289 return CanWriteLog(GetTypeInfo(aidl));
290}
291
292void WriteLogFor(CodeWriter& writer, const AidlTypeSpecifier& type, const std::string& name,
293 bool isPointer, const std::string& log, bool isNdk) {
294 const TypeInfo info = GetTypeInfo(type);
295 if (!CanWriteLog(info)) {
296 return;
297 }
298
299 const string var_object_expr = ((isPointer ? "*" : "")) + name;
300 if (type.IsArray()) {
301 writer << log << " = Json::Value(Json::arrayValue);\n";
302 writer << "for (const auto& v: " << var_object_expr << ") " << log << ".append(";
303 info.toJsonValueExpr(writer, "v", isNdk);
304 writer << ");";
305 } else {
306 writer << log << " = ";
307 info.toJsonValueExpr(writer, var_object_expr, isNdk);
308 writer << ";";
309 }
310 writer << "\n";
311}
312
313void WriteLogForArguments(CodeWriterPtr& writer, const AidlArgument& a, bool isServer,
314 string logVarName, bool isNdk) {
315 if (!CanWriteLog(a.GetType())) {
316 return;
317 }
318 string logElementVarName = "_log_arg_element";
319 (*writer) << "{\n";
320 (*writer).Indent();
321 (*writer) << "Json::Value " << logElementVarName << "(Json::objectValue);\n";
322 string varName = isServer || isNdk ? BuildVarName(a) : a.GetName();
323 (*writer) << logElementVarName << "[\"name\"] = \"" << varName << "\";\n";
324
325 bool isPointer = a.IsOut() && !isServer;
326 WriteLogFor(*(writer.get()), a.GetType(), varName, isPointer, logElementVarName + "[\"value\"]",
327 isNdk);
328 (*writer) << logVarName << ".append(" << logElementVarName << ");\n";
329 (*writer) << "}\n";
330 (*writer).Dedent();
331}
332
333const string GenLogBeforeExecute(const string className, const AidlMethod& method, bool isServer,
334 bool isNdk) {
335 string code;
336 CodeWriterPtr writer = CodeWriter::ForString(&code);
337 (*writer) << "Json::Value _log_input_args(Json::arrayValue);\n";
338
339 (*writer) << "if (" << className << "::logFunc != nullptr) {\n";
340 (*writer).Indent();
341
342 for (const auto& a : method.GetArguments()) {
343 if (a->IsIn()) {
344 WriteLogForArguments(writer, *a, isServer, "_log_input_args", isNdk);
345 }
346 }
347
348 (*writer).Dedent();
349 (*writer) << "}\n";
350
351 (*writer) << "auto _log_start = std::chrono::steady_clock::now();\n";
352 writer->Close();
353 return code;
354}
355
356const string GenLogAfterExecute(const string className, const AidlInterface& interface,
357 const AidlMethod& method, const string& statusVarName,
358 const string& returnVarName, bool isServer, bool isNdk) {
359 string code;
360 CodeWriterPtr writer = CodeWriter::ForString(&code);
361
362 (*writer) << "if (" << className << "::logFunc != nullptr) {\n";
363 (*writer).Indent();
364
365 // Write the log as a Json object. For example,
366 //
367 // Json log object for following interface description
368 //
369 // package foo.bar;
370 // interface IFoo {
371 // String TestMethod(int arg1, inout String[] arg2, out double arg3);
372 // }
373 //
374 // would be:
375 //
376 // {
377 // duration_ms: 100.42,
378 // interface_name: "foo.bar.IFoo",
379 // method_name: "TestMethod",
380 // (proxy|stub)_address: "0x12345678",
381 // input_args: [
382 // {name: "arg1", value: 30,},
383 // {name: "arg2", value: ["apple", "grape"],},
384 // ],
385 // output_args: [
386 // {name: "arg2", value: ["mango", "banana"],},
387 // {name: "arg3", value: "10.5",},
388 // ],
389 // _aidl_return: "ok",
390 // binder_status: {
391 // exception_code: -8,
392 // exception_message: "Something wrong",
393 // transaction_error: 0,
394 // service_specific_error_code: -42,
395 // },
396 // }
397 (*writer) << "auto _log_end = std::chrono::steady_clock::now();\n";
398 (*writer) << "Json::Value _log_transaction(Json::objectValue);\n";
399 (*writer) << "_log_transaction[\"duration_ms\"] = "
400 << "std::chrono::duration<double, std::milli>(_log_end - "
401 "_log_start).count();\n";
402 (*writer) << "_log_transaction[\"interface_name\"] = "
403 << "Json::Value(\"" << interface.GetCanonicalName() << "\");\n";
404 (*writer) << "_log_transaction[\"method_name\"] = "
405 << "Json::Value(\"" << method.GetName() << "\");\n";
406
407 (*writer) << "_log_transaction[\"" << (isServer ? "stub_address" : "proxy_address") << "\"] = ";
408 (*writer) << "Json::Value("
409 << "(std::ostringstream() << "
410 << (isNdk && isServer ? "_aidl_impl" : "static_cast<const void*>(this)") << ").str()"
411 << ");\n";
412 (*writer) << "_log_transaction[\"input_args\"] = _log_input_args;\n";
413 (*writer) << "Json::Value _log_output_args(Json::arrayValue);\n";
414
415 (*writer) << "Json::Value _log_status(Json::objectValue);\n";
416 if (isNdk) {
417 (*writer) << "_log_status[\"exception_code\"] = Json::Value(AStatus_getExceptionCode("
418 << statusVarName << ".get()));\n";
419 (*writer) << "_log_status[\"exception_message\"] = Json::Value(AStatus_getMessage("
420 << statusVarName << ".get()));\n";
421 (*writer) << "_log_status[\"transaction_error\"] = Json::Value(AStatus_getStatus("
422 << statusVarName << ".get()));\n";
Jeongik Chaeaf978e2019-05-04 00:32:35 +0900423 (*writer) << "_log_status[\"service_specific_error_code\"] = "
424 "Json::Value(AStatus_getServiceSpecificError("
Jeongik Cha37e2ad52019-04-18 13:44:26 +0900425 << statusVarName << ".get()));\n";
426 } else {
427 (*writer) << "_log_status[\"exception_code\"] = Json::Value(" << statusVarName
428 << ".exceptionCode());\n";
429 (*writer) << "_log_status[\"exception_message\"] = Json::Value(" << statusVarName
430 << ".exceptionMessage());\n";
431 (*writer) << "_log_status[\"transaction_error\"] = Json::Value(" << statusVarName
432 << ".transactionError());\n";
433 (*writer) << "_log_status[\"service_specific_error_code\"] = Json::Value(" << statusVarName
434 << ".serviceSpecificErrorCode());\n";
435 }
436
437 (*writer) << "_log_transaction[\"binder_status\"] = _log_status;\n";
438
439 for (const auto& a : method.GetOutArguments()) {
440 WriteLogForArguments(writer, *a, isServer, "_log_output_args", isNdk);
441 }
442
443 (*writer) << "_log_transaction[\"output_args\"] = _log_output_args;\n";
444
445 if (method.GetType().GetName() != "void") {
446 WriteLogFor(*(writer.get()), method.GetType(), returnVarName, !isServer,
447 "_log_transaction[\"" + returnVarName + "\"]", isNdk);
448 }
449
450 // call the user-provided function with the Json object for the entire
451 // transaction
452 (*writer) << className << "::logFunc(_log_transaction);\n";
453
454 (*writer).Dedent();
455 (*writer) << "}\n";
456
457 writer->Close();
458 return code;
459}
460
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000461std::string GenerateEnumValues(const AidlEnumDeclaration& enum_decl,
462 const std::vector<std::string>& enclosing_namespaces_of_enum_decl) {
463 const auto fq_name =
464 Join(Append(enclosing_namespaces_of_enum_decl, enum_decl.GetSplitPackage()), "::") +
465 "::" + enum_decl.GetName();
466 const auto size = enum_decl.GetEnumerators().size();
467 std::ostringstream code;
Jooyung Han0e2a03c2019-12-17 23:25:39 +0900468 code << "#pragma clang diagnostic push\n";
469 code << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000470 code << "template <>\n";
471 code << "constexpr inline std::array<" << fq_name << ", " << size << "> enum_values<" << fq_name
472 << "> = {\n";
473 for (const auto& enumerator : enum_decl.GetEnumerators()) {
474 code << " " << fq_name << "::" << enumerator->GetName() << ",\n";
475 }
476 code << "};\n";
Jooyung Han0e2a03c2019-12-17 23:25:39 +0900477 code << "#pragma clang diagnostic pop\n";
Jooyung Han7a9aceb2019-12-17 14:18:15 +0000478 return code.str();
479}
480
Jooyung Han6beac042020-10-17 21:59:43 +0900481std::string TemplateDecl(const AidlParcelable& defined_type) {
Devin Moore53fc99c2020-08-12 08:07:52 -0700482 std::string decl = "";
483 if (defined_type.IsGeneric()) {
484 std::vector<std::string> template_params;
485 for (const auto& parameter : defined_type.GetTypeParameters()) {
486 template_params.push_back(parameter);
487 }
488 decl = base::StringPrintf("template <typename %s>\n",
489 base::Join(template_params, ", typename ").c_str());
490 }
491 return decl;
492}
493
Jooyung Han3df81ae2020-10-17 17:59:59 +0900494void GenerateParcelableComparisonOperators(CodeWriter& out, const AidlParcelable& parcelable) {
495 std::set<string> operators{"<", ">", "==", ">=", "<=", "!="};
496 bool is_empty = false;
497
498 auto comparable = [&](const string& prefix) {
499 vector<string> fields;
500 if (auto p = parcelable.AsStructuredParcelable(); p != nullptr) {
501 is_empty = p->GetFields().empty();
502 for (const auto& f : p->GetFields()) {
503 fields.push_back(prefix + f->GetName());
504 }
505 return "std::tie(" + Join(fields, ", ") + ")";
506 } else if (auto p = parcelable.AsUnionDeclaration(); p != nullptr) {
507 return prefix + "_value";
508 } else {
509 AIDL_FATAL(parcelable) << "Unknown paracelable type";
510 }
511 };
512
513 string lhs = comparable("");
514 string rhs = comparable("rhs.");
515 for (const auto& op : operators) {
516 out << "inline bool operator" << op << "(const " << parcelable.GetName() << "&"
517 << (is_empty ? "" : " rhs") << ") const {\n"
518 << " return " << lhs << " " << op << " " << rhs << ";\n"
519 << "}\n";
520 }
521 out << "\n";
522}
523
Jooyung Han74b1dd42020-11-01 22:17:16 +0900524// Output may look like:
525// inline std::string toString() const {
526// std::ostringstream os;
527// os << "MyData{";
528// os << "field1: " << field1;
529// os << ", field2: " << v.field2;
530// ...
531// os << "}";
532// return os.str();
533// }
534void GenerateToString(CodeWriter& out, const AidlStructuredParcelable& parcelable) {
535 out << kToStringHelper;
536 out << "inline std::string toString() const {\n";
537 out.Indent();
538 out << "std::ostringstream os;\n";
539 out << "os << \"" << parcelable.GetName() << "{\";\n";
540 bool first = true;
541 for (const auto& f : parcelable.GetFields()) {
542 if (first) {
543 out << "os << \"";
544 first = false;
545 } else {
546 out << "os << \", ";
547 }
548 out << f->GetName() << ": \" << " << ToString(f->GetType(), f->GetName()) << ";\n";
549 }
550 out << "os << \"}\";\n";
551 out << "return os.str();\n";
552 out.Dedent();
553 out << "}\n";
554}
555
556// Output may look like:
557// inline std::string toString() const {
558// std::ostringstream os;
559// os << "MyData{";
560// switch (v.getTag()) {
561// case MyData::field: os << "field: " << v.get<MyData::field>(); break;
562// ...
563// }
564// os << "}";
565// return os.str();
566// }
567void GenerateToString(CodeWriter& out, const AidlUnionDecl& parcelable) {
568 out << kToStringHelper;
569 out << "inline std::string toString() const {\n";
570 out.Indent();
571 out << "std::ostringstream os;\n";
572 out << "os << \"" + parcelable.GetName() + "{\";\n";
573 out << "switch (getTag()) {\n";
574 for (const auto& f : parcelable.GetFields()) {
575 const string tag = f->GetName();
576 out << "case " << tag << ": os << \"" << tag << ": \" << "
577 << ToString(f->GetType(), "get<" + tag + ">()") << "; break;\n";
578 }
579 out << "}\n";
580 out << "os << \"}\";\n";
581 out << "return os.str();\n";
582 out.Dedent();
583 out << "}\n";
584}
585
Jooyung Han3df81ae2020-10-17 17:59:59 +0900586const vector<string> UnionWriter::headers{
587 "type_traits", // std::is_same_v
588 "utility", // std::mode/forward for value
589 "variant", // std::variant for value
590};
591
592void UnionWriter::PrivateFields(CodeWriter& out) const {
593 vector<string> field_types;
594 for (const auto& f : decl.GetFields()) {
595 field_types.push_back(name_of(f->GetType(), typenames));
596 }
597 out << "std::variant<" + Join(field_types, ", ") + "> _value;\n";
598}
599
600void UnionWriter::PublicFields(CodeWriter& out) const {
601 AidlTypeSpecifier tag_type(AIDL_LOCATION_HERE, "int", /* is_array= */ false,
602 /* type_params= */ nullptr, /* comments= */ "");
603 tag_type.Resolve(typenames);
604
605 out << "enum Tag : " << name_of(tag_type, typenames) << " {\n";
606 bool is_first = true;
607 for (const auto& f : decl.GetFields()) {
608 out << " " << f->GetName() << (is_first ? " = 0" : "") << ", // " << f->Signature() << ";\n";
609 is_first = false;
610 }
611 out << "};\n";
612
613 const auto& name = decl.GetName();
614
615 AIDL_FATAL_IF(decl.GetFields().empty(), decl) << "Union '" << name << "' is empty.";
616 const auto& first_field = decl.GetFields()[0];
617 const auto& default_name = first_field->GetName();
618 const auto& default_value =
619 name_of(first_field->GetType(), typenames) + "(" + first_field->ValueString(decorator) + ")";
620
621 auto tmpl = R"--(
622template<typename _Tp>
623static constexpr bool _not_self = !std::is_same_v<std::remove_cv_t<std::remove_reference_t<_Tp>>, {name}>;
624
625{name}() : _value(std::in_place_index<{default_name}>, {default_value}) {{ }}
626{name}(const {name}&) = default;
627{name}({name}&&) = default;
628{name}& operator=(const {name}&) = default;
629{name}& operator=({name}&&) = default;
630
631template <typename _Tp, std::enable_if_t<_not_self<_Tp>, int> = 0>
632constexpr {name}(_Tp&& _arg)
633 : _value(std::forward<_Tp>(_arg)) {{}}
634
635template <typename... _Tp>
636constexpr explicit {name}(_Tp&&... _args)
637 : _value(std::forward<_Tp>(_args)...) {{}}
638
639template <Tag _tag, typename... _Tp>
640static {name} make(_Tp&&... _args) {{
641 return {name}(std::in_place_index<_tag>, std::forward<_Tp>(_args)...);
642}}
643
644template <Tag _tag, typename _Tp, typename... _Up>
645static {name} make(std::initializer_list<_Tp> _il, _Up&&... _args) {{
646 return {name}(std::in_place_index<_tag>, std::move(_il), std::forward<_Up>(_args)...);
647}}
648
649Tag getTag() const {{
650 return static_cast<Tag>(_value.index());
651}}
652
653template <Tag _tag>
654const auto& get() const {{
655 if (getTag() != _tag) {{ abort(); }}
656 return std::get<_tag>(_value);
657}}
658
659template <Tag _tag>
660auto& get() {{
661 if (getTag() != _tag) {{ abort(); }}
662 return std::get<_tag>(_value);
663}}
664
665template <Tag _tag, typename... _Tp>
666void set(_Tp&&... _args) {{
667 _value.emplace<_tag>(std::forward<_Tp>(_args)...);
668}}
669
670)--";
671 out << fmt::format(tmpl, fmt::arg("name", name), fmt::arg("default_name", default_name),
672 fmt::arg("default_value", default_value));
673}
674
675void UnionWriter::ReadFromParcel(CodeWriter& out, const ParcelWriterContext& ctx) const {
676 AidlTypeSpecifier tag_type(AIDL_LOCATION_HERE, "int", /* is_array= */ false,
677 /* type_params= */ nullptr, /* comments= */ "");
678 tag_type.Resolve(typenames);
679
680 const string tag = "_aidl_tag";
681 const string value = "_aidl_value";
682 const string status = "_aidl_ret_status";
683
684 auto read_var = [&](const string& var, const AidlTypeSpecifier& type) {
685 out << fmt::format("{} {};\n", name_of(type, typenames), var);
686 out << fmt::format("if (({} = ", status);
687 ctx.read_func(out, var, type);
688 out << fmt::format(") != {}) return {};\n", ctx.status_ok, status);
689 };
690
691 out << fmt::format("{} {};\n", ctx.status_type, status);
692 read_var(tag, tag_type);
693 out << fmt::format("switch ({}) {{\n", tag);
694 for (const auto& variable : decl.GetFields()) {
695 out << fmt::format("case {}: {{\n", variable->GetName());
696 out.Indent();
697 read_var(value, variable->GetType());
698 out << fmt::format("set<{}>(std::move({}));\n", variable->GetName(), value);
699 out << fmt::format("return {}; }}\n", ctx.status_ok);
700 out.Dedent();
701 }
702 out << "}\n";
703 out << fmt::format("return {};\n", ctx.status_bad);
704}
705
706void UnionWriter::WriteToParcel(CodeWriter& out, const ParcelWriterContext& ctx) const {
707 AidlTypeSpecifier tag_type(AIDL_LOCATION_HERE, "int", /* is_array= */ false,
708 /* type_params= */ nullptr, /* comments= */ "");
709 tag_type.Resolve(typenames);
710
711 const string tag = "_aidl_tag";
712 const string value = "_aidl_value";
713 const string status = "_aidl_ret_status";
714
715 out << fmt::format("{} {} = ", ctx.status_type, status);
716 ctx.write_func(out, "getTag()", tag_type);
717 out << ";\n";
718 out << fmt::format("if ({} != {}) return {};\n", status, ctx.status_ok, status);
719 out << "switch (getTag()) {\n";
720 for (const auto& variable : decl.GetFields()) {
721 out << fmt::format("case {}: return ", variable->GetName());
722 ctx.write_func(out, "get<" + variable->GetName() + ">()", variable->GetType());
723 out << ";\n";
724 }
725 out << "}\n";
726 out << "abort();\n";
727}
728
Steven Morelandb0057e72018-08-27 01:44:11 -0700729} // namespace cpp
730} // namespace aidl
731} // namespace android