1 /*
2 * Copyright (C) 2020 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 <android-base/logging.h>
18 #include <android-base/strings.h>
19 #include <hidl-util/FQName.h>
20 #include <hidl-util/Formatter.h>
21 #include <hidl-util/StringHelper.h>
22 #include <limits>
23 #include <set>
24 #include <string>
25 #include <vector>
26
27 #include "AidlHelper.h"
28 #include "ArrayType.h"
29 #include "CompoundType.h"
30 #include "ConstantExpression.h"
31 #include "Coordinator.h"
32 #include "EnumType.h"
33 #include "Interface.h"
34 #include "NamedType.h"
35 #include "ScalarType.h"
36 #include "Scope.h"
37 #include "VectorType.h"
38
39 namespace android {
40
translateHeaderFile(const FQName & fqName,AidlBackend backend)41 std::string AidlHelper::translateHeaderFile(const FQName& fqName, AidlBackend backend) {
42 switch (backend) {
43 case AidlBackend::NDK:
44 return AidlHelper::getAidlPackagePath(fqName) + "/translate-ndk.h";
45 case AidlBackend::CPP:
46 return AidlHelper::getAidlPackagePath(fqName) + "/translate-cpp.h";
47 default:
48 LOG(FATAL) << "Unexpected AidlBackend value";
49 return "";
50 }
51 }
52
translateSourceFile(const FQName & fqName,AidlBackend backend)53 std::string AidlHelper::translateSourceFile(const FQName& fqName, AidlBackend backend) {
54 switch (backend) {
55 case AidlBackend::NDK:
56 return AidlHelper::getAidlPackagePath(fqName) + "/translate-ndk.cpp";
57 case AidlBackend::CPP:
58 return AidlHelper::getAidlPackagePath(fqName) + "/translate-cpp.cpp";
59 case AidlBackend::JAVA:
60 return AidlHelper::getAidlPackagePath(fqName) + "/Translate.java";
61 default:
62 LOG(FATAL) << "Unexpected AidlBackend value";
63 return "";
64 }
65 }
66
aidlTypePackage(const NamedType & type,AidlBackend backend)67 static const std::string aidlTypePackage(const NamedType& type, AidlBackend backend) {
68 const std::string prefix = (backend == AidlBackend::NDK) ? "aidl::" : std::string();
69 const std::string separator = (backend == AidlBackend::JAVA) ? "." : "::";
70 return prefix +
71 base::Join(base::Split(AidlHelper::getAidlPackage(type.fqName()), "."), separator) +
72 separator + AidlHelper::getAidlType(type, type.fqName());
73 }
74
emitEnumStaticAssert(Formatter & out,const NamedType & namedType,AidlBackend backend)75 static void emitEnumStaticAssert(Formatter& out, const NamedType& namedType, AidlBackend backend) {
76 CHECK(namedType.isEnum());
77 const auto& enumType = static_cast<const EnumType&>(namedType);
78
79 std::vector<const EnumValue*> values;
80 for (const EnumType* type : enumType.typeChain()) {
81 if (!AidlHelper::shouldBeExpanded(enumType.fqName(), type->fqName())) {
82 break;
83 }
84 values.insert(values.end(), type->values().rbegin(), type->values().rend());
85 }
86
87 for (auto it = values.rbegin(); it != values.rend(); ++it) {
88 out << "static_assert(" << aidlTypePackage(namedType, backend) << "::" << (*it)->name()
89 << " == static_cast<" << aidlTypePackage(namedType, backend) << ">("
90 << namedType.fullName() << "::" << (*it)->name() << "));\n";
91 };
92
93 out << "\n";
94 }
95
emitStaticAsserts(Formatter & out,const std::set<const NamedType * > & namedTypes,AidlBackend backend)96 static void emitStaticAsserts(Formatter& out, const std::set<const NamedType*>& namedTypes,
97 AidlBackend backend) {
98 CHECK(backend != AidlBackend::JAVA);
99 for (const auto& namedType : namedTypes) {
100 if (namedType->isEnum()) {
101 emitEnumStaticAssert(out, *namedType, backend);
102 }
103 }
104 }
105
namedTypeTranslation(Formatter & out,const std::set<const NamedType * > & namedTypes,const FieldWithVersion & field,const CompoundType * parent,AidlBackend backend)106 static void namedTypeTranslation(Formatter& out, const std::set<const NamedType*>& namedTypes,
107 const FieldWithVersion& field, const CompoundType* parent,
108 AidlBackend backend) {
109 const NamedType* type = static_cast<const NamedType*>(field.field->get());
110 if (namedTypes.find(type) == namedTypes.end()) {
111 std::optional<const ReplacedTypeInfo> replacedType =
112 AidlHelper::getAidlReplacedType(type->fqName());
113 if (replacedType) {
114 std::optional<std::function<void(Formatter&)>> translateField =
115 replacedType.value().translateField;
116 if (translateField) {
117 translateField.value()(out);
118 }
119 } else {
120 AidlHelper::notes() << "An unknown named type was found in translation: "
121 << type->fqName().string() + "\n";
122 out << "// FIXME Unknown type: " << type->fqName().string() << "\n";
123 out << "// That type's package needs to be converted separately and the corresponding "
124 "translate function should be added here.\n";
125 }
126 } else {
127 if (parent->style() == CompoundType::STYLE_STRUCT) {
128 if (backend == AidlBackend::JAVA) {
129 out << "out." << field.field->name() << " = h2aTranslate(in." << field.fullName
130 << ");\n";
131 } else {
132 out << "if (!translate(in." << field.fullName << ", &out->" << field.field->name()
133 << ")) return false;\n";
134 }
135 } else {
136 if (backend == AidlBackend::JAVA) {
137 out << "out.set" << StringHelper::Capitalize(field.field->name())
138 << "(h2aTranslate(in." << field.fullName << "()));\n";
139 } else {
140 out << "{\n";
141 out << aidlTypePackage(*type, backend) << " " << field.field->name() << ";\n";
142 out << "if (!translate(in." << field.fullName + "(), &" << field.field->name()
143 << ")) return false;\n";
144 out << "out->set<" << aidlTypePackage(*parent, backend) << "::" << field.fullName
145 << ">(" << field.field->name() << ");\n";
146 out << "}\n";
147 }
148 }
149 }
150 }
151
h2aScalarChecks(Formatter & out,const Type & type,const std::string & inputAccess,AidlBackend backend)152 static void h2aScalarChecks(Formatter& out, const Type& type, const std::string& inputAccess,
153 AidlBackend backend) {
154 static const std::map<ScalarType::Kind, std::pair<std::string, size_t>> kSignedMaxSize{
155 {ScalarType::KIND_UINT8,
156 {"std::numeric_limits<int8_t>::max()", std::numeric_limits<int8_t>::max()}},
157 {ScalarType::KIND_UINT16, {"", 0}},
158 {ScalarType::KIND_INT16, {"", 0}},
159 {ScalarType::KIND_UINT32,
160 {"std::numeric_limits<int32_t>::max()", std::numeric_limits<int32_t>::max()}},
161 {ScalarType::KIND_UINT64,
162 {"std::numeric_limits<int64_t>::max()", std::numeric_limits<int64_t>::max()}}};
163 const ScalarType* scalarType = type.resolveToScalarType();
164 if (scalarType != nullptr && !type.isEnum()) {
165 const auto& it = kSignedMaxSize.find(scalarType->getKind());
166 // *int16_t is a special case for both HIDL and AIDL. For uint16_t, checks are only
167 // needed in the Java backend.
168 if (backend != AidlBackend::JAVA && scalarType->getKind() == ScalarType::KIND_UINT16) {
169 return;
170 }
171 if (it != kSignedMaxSize.end()) {
172 out << "// FIXME This requires conversion between signed and unsigned. Change this if "
173 "it doesn't suit your needs.\n";
174 if (scalarType->getKind() == ScalarType::KIND_UINT16 ||
175 scalarType->getKind() == ScalarType::KIND_INT16) {
176 // HIDL uses a signed 16-bit char in Java for uint16_t and int16_t
177 // AIDL uses an unsigned 16-bit char/char16_t, so this is signed to unsigned.
178 out << "if (" << inputAccess << " < 0) {\n";
179 } else {
180 std::string affix = (scalarType->getKind() == ScalarType::KIND_UINT64) ? "L" : "";
181 std::string limit = (backend == AidlBackend::JAVA)
182 ? std::to_string(it->second.second) + affix
183 : it->second.first;
184 out << "if (" << inputAccess << " > " << limit << " || " << inputAccess
185 << " < 0) {\n";
186 }
187 if (backend == AidlBackend::JAVA) {
188 out.indent([&] {
189 out << "throw new RuntimeException(\"Unsafe conversion between signed and "
190 "unsigned scalars for field: "
191 << inputAccess << "\");\n";
192 });
193 } else {
194 out.indent([&] { out << "return false;\n"; });
195 }
196 out << "}\n";
197 }
198 }
199 }
200
wrapToString16(const std::string & payload,AidlBackend backend)201 static std::string wrapToString16(const std::string& payload, AidlBackend backend) {
202 if (backend == AidlBackend::CPP) {
203 return "String16(" + payload + ".c_str())";
204 } else {
205 return payload;
206 }
207 }
208
wrapStaticCast(const std::string & payload,const Type & type,const FQName & fqName,AidlBackend backend)209 static std::string wrapStaticCast(const std::string& payload, const Type& type,
210 const FQName& fqName, AidlBackend backend) {
211 static const std::map<std::string, std::string> kAidlBackendScalarTypes{
212 {"boolean", "bool"}, {"byte", "int8_t"}, {"char", "char16_t"}, {"int", "int32_t"},
213 {"long", "int64_t"}, {"float", "float"}, {"double", "double"}};
214 if (type.isEnum()) {
215 return "static_cast<" +
216 aidlTypePackage(static_cast<const android::NamedType&>(type), backend) + ">(" +
217 payload + ")";
218 }
219 const auto& it = kAidlBackendScalarTypes.find(AidlHelper::getAidlType(type, fqName));
220 if (it != kAidlBackendScalarTypes.end()) {
221 return "static_cast<" + it->second + ">(" + payload + ")";
222 } else {
223 return payload;
224 }
225 }
226
wrapCppSource(const std::string & payload,const Type & type,const FQName & fqName,AidlBackend backend)227 static std::string wrapCppSource(const std::string& payload, const Type& type, const FQName& fqName,
228 AidlBackend backend) {
229 if (type.isString()) {
230 return wrapToString16(payload, backend);
231 } else if (type.isBitField()) {
232 return wrapStaticCast(payload, *static_cast<const BitFieldType&>(type).getElementEnumType(),
233 fqName, backend);
234 } else {
235 return wrapStaticCast(payload, type, fqName, backend);
236 }
237 }
238
containerTranslation(Formatter & out,const FieldWithVersion & field,const CompoundType * parent,AidlBackend backend)239 static void containerTranslation(Formatter& out, const FieldWithVersion& field,
240 const CompoundType* parent, AidlBackend backend) {
241 const Type* elementType;
242 std::string javaSizeAccess;
243 std::string javaElementAccess;
244 std::string cppSize;
245 if (field.field->type().isArray()) {
246 elementType = static_cast<const ArrayType*>(field.field->get())->getElementType();
247 javaSizeAccess = ".length";
248 javaElementAccess = "[i]";
249 cppSize = "sizeof(in." + field.fullName + ")/sizeof(in." + field.fullName + "[0])";
250 } else if (field.field->type().isVector()) {
251 elementType = static_cast<const VectorType*>(field.field->get())->getElementType();
252 javaSizeAccess = ".size()";
253 javaElementAccess = ".get(i)";
254 cppSize = "in." + field.fullName + ".size()";
255 } else {
256 LOG(FATAL) << "Unexpected container type for field: " << field.field->name();
257 return;
258 }
259 if (elementType->isArray() || elementType->isVector()) {
260 out << "#error Nested arrays and vectors are currently not supported. Needs implementation "
261 "for field: "
262 << field.field->name() << "\n";
263 return;
264 }
265 if (elementType->isNamedType() && !elementType->isEnum()) {
266 out << "#error Arrays of NamedTypes are not currently not supported. Needs implementation "
267 "for field: "
268 << field.field->name() << "\n";
269 return;
270 }
271 if (backend == AidlBackend::JAVA) {
272 const std::string inputAccess = "in." + field.fullName;
273 out << "if (" << inputAccess << " != null) {\n";
274 out.indent([&] {
275 out << "out." << field.field->name() << " = new " << elementType->getJavaType(true)
276 << "[" << inputAccess << javaSizeAccess << "];\n";
277 out << "for (int i = 0; i < " << inputAccess << javaSizeAccess << "; i++) {\n";
278 out.indent([&] {
279 h2aScalarChecks(out, *elementType, inputAccess + javaElementAccess, backend);
280 out << "out." << field.field->name() << "[i] = " << inputAccess << javaElementAccess
281 << ";\n";
282 });
283 out << "}\n";
284 });
285 out << "}\n";
286 } else {
287 const std::string inputAccessElement = "in." + field.fullName + "[i]";
288 out << "{\n";
289 out.indent([&] {
290 out << "size_t size = " << cppSize << ";\n";
291 out << "for (size_t i = 0; i < size; i++) {\n";
292 out.indent([&] {
293 h2aScalarChecks(out, *elementType, inputAccessElement, backend);
294 out << "out->" << field.field->name() << ".push_back("
295 << wrapCppSource(inputAccessElement, *elementType, parent->fqName(), backend)
296 << ");\n";
297 });
298 out << "}\n";
299 });
300 out << "}\n";
301 }
302 }
303
simpleTranslation(Formatter & out,const FieldWithVersion & field,const CompoundType * parent,AidlBackend backend)304 static void simpleTranslation(Formatter& out, const FieldWithVersion& field,
305 const CompoundType* parent, AidlBackend backend) {
306 std::string inputAccess = "in." + field.fullName;
307 if (backend == AidlBackend::JAVA) {
308 // HIDL uses short(signed) in the Java backend for uint16_t and int16_t
309 // AIDL uses char which is unsigned. This assignment needs a cast.
310 std::string cast;
311 if (AidlHelper::getAidlType(field.field->type(), parent->fqName()) == "char") {
312 cast = "(char) ";
313 }
314 if (parent->style() == CompoundType::STYLE_STRUCT) {
315 h2aScalarChecks(out, field.field->type(), inputAccess, backend);
316 out << "out." << field.field->name() << " = " << cast << inputAccess << ";\n";
317 } else {
318 inputAccess += "()";
319 h2aScalarChecks(out, field.field->type(), inputAccess, backend);
320 out << "out.set" << StringHelper::Capitalize(field.fullName) << "(" << cast
321 << inputAccess << ");\n";
322 }
323 } else {
324 if (parent->style() == CompoundType::STYLE_STRUCT) {
325 h2aScalarChecks(out, field.field->type(), inputAccess, backend);
326 out << "out->" << field.field->name() << " = "
327 << wrapCppSource("in." + field.fullName, field.field->type(), parent->fqName(),
328 backend)
329 << ";\n";
330 } else {
331 inputAccess += "()";
332 h2aScalarChecks(out, field.field->type(), inputAccess, backend);
333 out << "*out = "
334 << wrapCppSource(inputAccess, field.field->type(), parent->fqName(), backend)
335 << ";\n";
336 }
337 }
338 }
339
h2aFieldTranslation(Formatter & out,const std::set<const NamedType * > & namedTypes,const CompoundType * parent,const FieldWithVersion & field,AidlBackend backend)340 static void h2aFieldTranslation(Formatter& out, const std::set<const NamedType*>& namedTypes,
341 const CompoundType* parent, const FieldWithVersion& field,
342 AidlBackend backend) {
343 if (field.field->type().isNamedType() && !field.field->type().isEnum()) {
344 namedTypeTranslation(out, namedTypes, field, parent, backend);
345 } else if (field.field->type().isArray() || field.field->type().isVector()) {
346 containerTranslation(out, field, parent, backend);
347 } else if (field.field->type().isEnum() || field.field->type().isScalar() ||
348 field.field->type().isString() || field.field->type().isBitField()) {
349 simpleTranslation(out, field, parent, backend);
350 } else {
351 AidlHelper::notes() << "An unhandled type was found in translation: "
352 << field.field->type().typeName() << "\n";
353 out << "#error FIXME Unhandled type: " << field.field->type().typeName() << "\n";
354 }
355 }
356
declareAidlFunctionSignature(const NamedType * type,AidlBackend backend)357 static const std::string declareAidlFunctionSignature(const NamedType* type, AidlBackend backend) {
358 if (backend == AidlBackend::JAVA) {
359 return "static public " + aidlTypePackage(*type, backend) + " h2aTranslate(" +
360 type->fullJavaName() + " in)";
361 } else {
362 return "__attribute__((warn_unused_result)) bool translate(const " + type->fullName() +
363 "& in, " + aidlTypePackage(*type, backend) + "* out)";
364 }
365 }
366
getHidlPackagePath(const NamedType * type)367 static const std::string getHidlPackagePath(const NamedType* type) {
368 return base::Join(base::Split(type->fqName().package(), "."), "/");
369 }
370
getParentInterface(const NamedType * type)371 static std::optional<const Interface*> getParentInterface(const NamedType* type) {
372 const Scope* parent = type->parent();
373 while (parent != nullptr) {
374 if (parent->definesInterfaces()) {
375 return parent->getInterface();
376 }
377 parent = parent->parent();
378 }
379 return std::nullopt;
380 }
381
hidlIncludeFile(const NamedType * type)382 static const std::string hidlIncludeFile(const NamedType* type) {
383 std::optional<const Interface*> parent = getParentInterface(type);
384 if (parent) {
385 return "#include \"" + getHidlPackagePath(type) + "/" + type->fqName().version() + "/" +
386 parent.value()->fqName().getInterfaceName() + ".h\"\n";
387 } else {
388 return "#include \"" + getHidlPackagePath(type) + "/" + type->fqName().version() +
389 "/types.h\"\n";
390 }
391 }
392
aidlIncludeFile(const NamedType * type,AidlBackend backend)393 static const std::string aidlIncludeFile(const NamedType* type, AidlBackend backend) {
394 const std::string prefix = (backend == AidlBackend::NDK) ? "aidl/" : std::string();
395 return "#include \"" + prefix + AidlHelper::getAidlPackagePath(type->fqName()) + "/" +
396 AidlHelper::getAidlType(*type, type->fqName()) + ".h\"\n";
397 }
398
emitCppTranslateHeader(const Coordinator & coordinator,const FQName & fqName,const std::set<const NamedType * > & namedTypes,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes,AidlBackend backend)399 static void emitCppTranslateHeader(
400 const Coordinator& coordinator, const FQName& fqName,
401 const std::set<const NamedType*>& namedTypes,
402 const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes,
403 AidlBackend backend) {
404 CHECK(backend == AidlBackend::CPP || backend == AidlBackend::NDK);
405 Formatter out =
406 coordinator.getFormatter(fqName, Coordinator::Location::DIRECT,
407 "include/" + AidlHelper::translateHeaderFile(fqName, backend));
408
409 AidlHelper::emitFileHeader(out);
410 out << "// FIXME Remove this file if you don't need to translate types in this backend.\n\n";
411 out << "#pragma once\n\n";
412
413 std::set<std::string> includes = {"#include <limits>"};
414 for (const auto& type : namedTypes) {
415 const auto& it = processedTypes.find(type);
416 if (it == processedTypes.end() && !type->isEnum()) {
417 continue;
418 }
419 includes.insert(aidlIncludeFile(type, backend));
420 includes.insert(hidlIncludeFile(type));
421 }
422 out << base::Join(includes, "") << "\n\n";
423
424 out << "namespace android::h2a {\n\n";
425 for (const auto& type : namedTypes) {
426 const auto& it = processedTypes.find(type);
427 if (it == processedTypes.end()) {
428 continue;
429 }
430 out << declareAidlFunctionSignature(type, backend) << ";\n";
431 }
432 out << "\n} // namespace android::h2a\n";
433 }
434
emitTranslateSource(const Coordinator & coordinator,const FQName & fqName,const std::set<const NamedType * > & namedTypes,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes,AidlBackend backend)435 static void emitTranslateSource(
436 const Coordinator& coordinator, const FQName& fqName,
437 const std::set<const NamedType*>& namedTypes,
438 const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes,
439 AidlBackend backend) {
440 Formatter out = coordinator.getFormatter(fqName, Coordinator::Location::DIRECT,
441 AidlHelper::translateSourceFile(fqName, backend));
442 AidlHelper::emitFileHeader(out);
443 out << "// FIXME Remove this file if you don't need to translate types in this backend.\n\n";
444 if (backend == AidlBackend::JAVA) {
445 out << "package " << AidlHelper::getAidlPackage(fqName) + ";\n\n";
446 out << "public class Translate {\n";
447 } else {
448 out << "#include \""
449 << AidlHelper::translateHeaderFile((*namedTypes.begin())->fqName(), backend) + "\"\n\n";
450 out << "namespace android::h2a {\n\n";
451 emitStaticAsserts(out, namedTypes, backend);
452 }
453 for (const auto& type : namedTypes) {
454 const auto& it = processedTypes.find(type);
455 if (it == processedTypes.end()) {
456 continue;
457 }
458 CHECK(type->isCompoundType()) << "Unexpected type: " << type->fqName().string();
459 const CompoundType* compound = static_cast<const CompoundType*>(type);
460
461 if (compound->style() == CompoundType::STYLE_UNION) {
462 // HIDL Java backend doesn't support union so don't add a comment.
463 if (backend != AidlBackend::JAVA) {
464 out << "// FIXME not enough information to safely convert. Remove this function or "
465 "fill it out using the custom discriminators.\n";
466 out << "// " << declareAidlFunctionSignature(type, backend) << "\n\n";
467 }
468 continue;
469 }
470
471 out << declareAidlFunctionSignature(type, backend) << " {\n";
472 if (compound->style() == CompoundType::STYLE_SAFE_UNION) {
473 out.indent([&] {
474 if (backend == AidlBackend::JAVA) {
475 out << aidlTypePackage(*type, backend) << " out = new "
476 << aidlTypePackage(*type, backend) << "();\n";
477 }
478 out << "switch (in.getDiscriminator()) {\n";
479 out.indent([&] {
480 const ProcessedCompoundType& processedType = it->second;
481 for (const auto& field : processedType.fields) {
482 if (backend == AidlBackend::JAVA) {
483 out << "case " << compound->fullJavaName() << ".hidl_discriminator."
484 << field.field->name() << ":\n";
485 } else {
486 out << "case " << compound->fullName()
487 << "::hidl_discriminator::" << field.field->name() << ":\n";
488 }
489 out.indent([&] {
490 h2aFieldTranslation(out, namedTypes, compound, field, backend);
491 out << "break;\n";
492 });
493 }
494 out << "default:\n";
495 if (backend == AidlBackend::JAVA) {
496 out.indent([&] {
497 out << "throw new RuntimeException(\"Unknown discriminator value: \" + "
498 "Integer.toString(in.getDiscriminator()));\n";
499 });
500 } else {
501 out.indent([&] { out << "return false;\n"; });
502 }
503 });
504 out << "}\n";
505 });
506 } else {
507 out.indent([&] {
508 if (backend == AidlBackend::JAVA) {
509 out << aidlTypePackage(*type, backend) << " out = new "
510 << aidlTypePackage(*type, backend) << "();\n";
511 }
512 const ProcessedCompoundType& processedType = it->second;
513 for (const auto& field : processedType.fields) {
514 h2aFieldTranslation(out, namedTypes, compound, field, backend);
515 }
516 });
517 }
518 if (backend == AidlBackend::JAVA) {
519 out.indent([&] { out << "return out;\n"; });
520 } else {
521 out.indent([&] { out << "return true;\n"; });
522 }
523 out << "}\n\n";
524 }
525 if (backend == AidlBackend::JAVA) {
526 out << "}";
527 } else {
528 out << "} // namespace android::h2a";
529 }
530 }
531
emitTranslation(const Coordinator & coordinator,const FQName & fqName,const std::set<const NamedType * > & namedTypes,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes)532 void AidlHelper::emitTranslation(
533 const Coordinator& coordinator, const FQName& fqName,
534 const std::set<const NamedType*>& namedTypes,
535 const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes) {
536 if (processedTypes.empty()) return;
537 for (auto backend : {AidlBackend::NDK, AidlBackend::CPP, AidlBackend::JAVA}) {
538 if (backend != AidlBackend::JAVA) {
539 emitCppTranslateHeader(coordinator, fqName, namedTypes, processedTypes, backend);
540 }
541 emitTranslateSource(coordinator, fqName, namedTypes, processedTypes, backend);
542 }
543 }
544
545 } // namespace android
546