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