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 <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 <set>
23 #include <string>
24 #include <vector>
25
26 #include "AidlHelper.h"
27 #include "ArrayType.h"
28 #include "Coordinator.h"
29 #include "Interface.h"
30 #include "Method.h"
31 #include "NamedType.h"
32 #include "Reference.h"
33 #include "Scope.h"
34
35 namespace android {
36
37 Formatter* AidlHelper::notesFormatter = nullptr;
38
notes()39 Formatter& AidlHelper::notes() {
40 CHECK(notesFormatter != nullptr);
41 return *notesFormatter;
42 }
43
setNotes(Formatter * formatter)44 void AidlHelper::setNotes(Formatter* formatter) {
45 CHECK(formatter != nullptr);
46 notesFormatter = formatter;
47 }
48
getAidlName(const FQName & fqName)49 std::string AidlHelper::getAidlName(const FQName& fqName) {
50 std::vector<std::string> names;
51 for (const std::string& name : fqName.names()) {
52 names.push_back(StringHelper::Capitalize(name));
53 }
54 return StringHelper::JoinStrings(names, "");
55 }
56
getAidlPackage(const FQName & fqName)57 std::string AidlHelper::getAidlPackage(const FQName& fqName) {
58 std::string aidlPackage = fqName.package();
59 if (fqName.getPackageMajorVersion() != 1) {
60 aidlPackage += std::to_string(fqName.getPackageMajorVersion());
61 }
62
63 return aidlPackage;
64 }
65
getAidlFQName(const FQName & fqName)66 std::string AidlHelper::getAidlFQName(const FQName& fqName) {
67 return getAidlPackage(fqName) + "." + getAidlName(fqName);
68 }
69
importLocallyReferencedType(const Type & type,std::set<std::string> * imports)70 void AidlHelper::importLocallyReferencedType(const Type& type, std::set<std::string>* imports) {
71 if (type.isArray()) {
72 return importLocallyReferencedType(*static_cast<const ArrayType*>(&type)->getElementType(),
73 imports);
74 }
75 if (type.isTemplatedType()) {
76 return importLocallyReferencedType(
77 *static_cast<const TemplatedType*>(&type)->getElementType(), imports);
78 }
79
80 if (!type.isNamedType()) return;
81 const NamedType& namedType = *static_cast<const NamedType*>(&type);
82
83 std::string import = AidlHelper::getAidlFQName(namedType.fqName());
84 imports->insert(import);
85 }
86
87 // This tries iterating over the HIDL AST which is a bit messy because
88 // it has to encode the logic in the rest of hidl2aidl. It would be better
89 // if we could iterate over the AIDL structure which has already been
90 // processed.
emitFileHeader(Formatter & out,const NamedType & type)91 void AidlHelper::emitFileHeader(Formatter& out, const NamedType& type) {
92 out << "// FIXME: license file if you have one\n\n";
93 out << "package " << getAidlPackage(type.fqName()) << ";\n\n";
94
95 std::set<std::string> imports;
96
97 // Import all the defined types since they will now be in a different file
98 if (type.isScope()) {
99 const Scope& scope = static_cast<const Scope&>(type);
100 for (const NamedType* namedType : scope.getSubTypes()) {
101 importLocallyReferencedType(*namedType, &imports);
102 }
103 }
104
105 // Import all the referenced types
106 if (type.isInterface()) {
107 // This is a separate case because getReferences doesn't traverse all the superTypes and
108 // sometimes includes references to types that would not exist on AIDL
109 const std::vector<const Method*>& methods =
110 getUserDefinedMethods(static_cast<const Interface&>(type));
111 for (const Method* method : methods) {
112 for (const Reference<Type>* ref : method->getReferences()) {
113 importLocallyReferencedType(*ref->get(), &imports);
114 }
115 }
116 } else {
117 for (const Reference<Type>* ref : type.getReferences()) {
118 if (ref->get()->definedName() == type.fqName().name()) {
119 // Don't import the referenced type if this is referencing itself
120 continue;
121 }
122 importLocallyReferencedType(*ref->get(), &imports);
123 }
124 }
125
126 for (const std::string& import : imports) {
127 out << "import " << import << ";\n";
128 }
129
130 if (imports.size() > 0) {
131 out << "\n";
132 }
133 }
134
getFileWithHeader(const NamedType & namedType,const Coordinator & coordinator)135 Formatter AidlHelper::getFileWithHeader(const NamedType& namedType,
136 const Coordinator& coordinator) {
137 std::string aidlPackage = getAidlPackage(namedType.fqName());
138 Formatter out = coordinator.getFormatter(namedType.fqName(), Coordinator::Location::DIRECT,
139 base::Join(base::Split(aidlPackage, "."), "/") + "/" +
140 getAidlName(namedType.fqName()) + ".aidl");
141 emitFileHeader(out, namedType);
142 return out;
143 }
144
145 } // namespace android
146