1 /*
2  * Copyright (C) 2019 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 "AidlHelper.h"
18 #include "CompoundType.h"
19 #include "Coordinator.h"
20 #include "EnumType.h"
21 #include "Interface.h"
22 #include "NamedType.h"
23 #include "TypeDef.h"
24 
25 namespace android {
26 
emitConversionNotes(Formatter & out,const NamedType & namedType)27 static void emitConversionNotes(Formatter& out, const NamedType& namedType) {
28     out << "// This is the HIDL definition of " << namedType.fqName().string() << "\n";
29     out.pushLinePrefix("// ");
30     namedType.emitHidlDefinition(out);
31     out.popLinePrefix();
32     out << "\n";
33 }
34 
emitTypeDefAidlDefinition(Formatter & out,const TypeDef & typeDef)35 static void emitTypeDefAidlDefinition(Formatter& out, const TypeDef& typeDef) {
36     out << "// Cannot convert typedef " << typeDef.referencedType()->definedName() << " "
37         << typeDef.fqName().string() << " since AIDL does not support typedefs.\n";
38     emitConversionNotes(out, typeDef);
39 }
40 
emitEnumAidlDefinition(Formatter & out,const EnumType & enumType)41 static void emitEnumAidlDefinition(Formatter& out, const EnumType& enumType) {
42     const ScalarType* scalar = enumType.storageType()->resolveToScalarType();
43     CHECK(scalar != nullptr) << enumType.typeName();
44 
45     enumType.emitDocComment(out);
46     out << "@VintfStability\n";
47     out << "@Backing(type=\"" << AidlHelper::getAidlType(*scalar, enumType.fqName()) << "\")\n";
48     out << "enum " << AidlHelper::getAidlType(enumType, enumType.fqName()) << " ";
49 
50     std::vector<const EnumValue*> values;
51     const EnumType* skippedType = nullptr;
52     for (const EnumType* type : enumType.typeChain()) {
53         if (!AidlHelper::shouldBeExpanded(enumType.fqName(), type->fqName())) {
54             skippedType = type;
55             break;
56         }
57         values.insert(values.end(), type->values().rbegin(), type->values().rend());
58     }
59     out.block([&] {
60         if (skippedType != nullptr) {
61             out << "// Not expanding values from " << skippedType->fqName().string()
62                 << ". See \'-e\' argument.\n";
63         }
64         for (auto it = values.rbegin(); it != values.rend(); ++it) {
65             (*it)->emitDocComment(out);
66             out << (*it)->name();
67             if (!(*it)->isAutoFill()) {
68                 out << " = " << (*it)->constExpr()->expression();
69             }
70             out << ",\n";
71         };
72     });
73 }
74 
emitCompoundTypeAidlDefinition(Formatter & out,const CompoundType & compoundType,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes)75 static void emitCompoundTypeAidlDefinition(
76         Formatter& out, const CompoundType& compoundType,
77         const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes) {
78     // Get all of the subtypes and fields from this type and any older versions
79     // that it references.
80     const auto& it = processedTypes.find(&compoundType);
81     CHECK(it != processedTypes.end()) << "Failed to find " << compoundType.fullName();
82     const ProcessedCompoundType& processedType = it->second;
83 
84     compoundType.emitDocComment(out);
85     out << "@VintfStability\n";
86     if (compoundType.style() == CompoundType::STYLE_STRUCT) {
87         out << "parcelable " << AidlHelper::getAidlName(compoundType.fqName()) << " ";
88     } else {
89         if (compoundType.style() == CompoundType::STYLE_UNION) {
90             out << "// FIXME Any discriminators should be removed since they are automatically "
91                    "added.\n";
92         }
93         out << "union " << AidlHelper::getAidlName(compoundType.fqName()) << " ";
94     }
95     out.block([&] {
96         // Emit all of the fields from the processed type
97         for (auto const& fieldWithVersion : processedType.fields) {
98             fieldWithVersion.field->emitDocComment(out);
99             std::string aidlType =
100                     AidlHelper::getAidlType(*fieldWithVersion.field->get(), compoundType.fqName());
101             out << aidlType << " " << fieldWithVersion.field->name() << ";\n";
102         }
103     });
104     out << "\n\n";
105 }
106 
107 // TODO: Enum/Typedef should just emit to hidl-error.log or similar
emitAidl(const NamedType & namedType,const Coordinator & coordinator,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes)108 void AidlHelper::emitAidl(
109         const NamedType& namedType, const Coordinator& coordinator,
110         const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes) {
111     Formatter out = getFileWithHeader(namedType, coordinator, processedTypes);
112     if (namedType.isTypeDef()) {
113         const TypeDef& typeDef = static_cast<const TypeDef&>(namedType);
114         emitTypeDefAidlDefinition(out, typeDef);
115     } else if (namedType.isCompoundType()) {
116         const CompoundType& compoundType = static_cast<const CompoundType&>(namedType);
117         emitCompoundTypeAidlDefinition(out, compoundType, processedTypes);
118     } else if (namedType.isEnum()) {
119         const EnumType& enumType = static_cast<const EnumType&>(namedType);
120         emitEnumAidlDefinition(out, enumType);
121     } else if (namedType.isInterface()) {
122         const Interface& iface = static_cast<const Interface&>(namedType);
123         emitAidl(iface, coordinator, processedTypes);
124     } else {
125         out << "// TODO: Fix this " << namedType.definedName() << "\n";
126     }
127 }
128 
129 }  // namespace android
130