blob: 50dd392aac60d46b96758863f3565a55bb7fecc9 [file] [log] [blame]
Christopher Wileyeb1acc12015-09-16 11:25:13 -07001/*
2 * Copyright (C) 2015, 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 "generate_cpp.h"
Casey Dahlina834dd42015-09-23 11:52:15 -070018#include "parse_helpers.h"
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070019
Casey Dahlin082f1d12015-09-21 14:06:25 -070020#include <cctype>
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070021#include <memory>
Casey Dahlin082f1d12015-09-21 14:06:25 -070022#include <random>
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070023#include <string>
24
Christopher Wileye3550c62015-09-29 13:26:10 -070025#include <base/stringprintf.h>
26
Casey Dahlina834dd42015-09-23 11:52:15 -070027#include "aidl_language.h"
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070028#include "ast_cpp.h"
29#include "code_writer.h"
Christopher Wileyeb1acc12015-09-16 11:25:13 -070030#include "logging.h"
31
Christopher Wileye3550c62015-09-29 13:26:10 -070032using android::base::StringPrintf;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070033using std::string;
Casey Dahlin082f1d12015-09-21 14:06:25 -070034using std::unique_ptr;
Casey Dahlina834dd42015-09-23 11:52:15 -070035using std::vector;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070036
Christopher Wileyeb1acc12015-09-16 11:25:13 -070037namespace android {
38namespace aidl {
Christopher Wileyf944e792015-09-29 10:00:46 -070039namespace cpp {
Casey Dahlina834dd42015-09-23 11:52:15 -070040namespace internals {
Christopher Wiley0c732db2015-09-29 14:36:44 -070041namespace {
Christopher Wileyeb1acc12015-09-16 11:25:13 -070042
Christopher Wiley0c732db2015-09-29 14:36:44 -070043const char kAndroidStatusLiteral[] = "android::status_t";
44const char kIBinderHeader[] = "binder/IBinder.h";
45const char kIInterfaceHeader[] = "binder/IInterface.h";
Casey Dahlin082f1d12015-09-21 14:06:25 -070046
Christopher Wiley0c732db2015-09-29 14:36:44 -070047string UpperCase(const std::string& s) {
48 string result = s;
49 for (char& c : result)
50 c = toupper(c);
51 return result;
Casey Dahlina834dd42015-09-23 11:52:15 -070052}
Casey Dahlin082f1d12015-09-21 14:06:25 -070053
Casey Dahlin0ee37582015-09-30 16:31:55 -070054string GetCPPVarDec(const TypeNamespace& types, const AidlType& type,
Christopher Wileye3550c62015-09-29 13:26:10 -070055 const string& var_name, bool use_pointer) {
Casey Dahlin0ee37582015-09-30 16:31:55 -070056 const Type* cpp_type = types.Find(type.type.data);
Christopher Wileye3550c62015-09-29 13:26:10 -070057 if (cpp_type == nullptr) {
58 // We should have caught this in type resolution.
59 LOG(FATAL) << "internal error";
60 }
61 return StringPrintf("%s%s %s%s",
62 cpp_type->CppType().c_str(),
63 (use_pointer) ? "*" : "",
64 var_name.c_str(),
Casey Dahlin0ee37582015-09-30 16:31:55 -070065 type.Brackets().c_str());
Casey Dahlina834dd42015-09-23 11:52:15 -070066}
67
Christopher Wiley0c732db2015-09-29 14:36:44 -070068unique_ptr<Declaration> BuildMethodDecl(const method_type* method,
69 const TypeNamespace& types,
70 bool for_interface) {
71 vector<string> args;
72 for (const unique_ptr<AidlArgument>& arg : *method->args) {
73 args.push_back(GetCPPVarDec(
Casey Dahlin0ee37582015-09-30 16:31:55 -070074 types, arg->GetType(), arg->GetName(),
Casey Dahlinc378c992015-09-29 16:50:40 -070075 AidlArgument::OUT_DIR & arg->GetDirection()));
Christopher Wiley0c732db2015-09-29 14:36:44 -070076 }
77
Casey Dahlin0ee37582015-09-30 16:31:55 -070078 string return_arg = GetCPPVarDec(types, *method->type, "_aidl_return", true);
Christopher Wiley0c732db2015-09-29 14:36:44 -070079 args.push_back(return_arg);
80
81 uint32_t modifiers = 0;
82 if (for_interface) {
83 modifiers |= MethodDecl::IS_VIRTUAL;
84 modifiers |= MethodDecl::IS_PURE_VIRTUAL;
85 } else {
86 modifiers |= MethodDecl::IS_OVERRIDE;
87 }
88
89 return unique_ptr<Declaration>{
90 new MethodDecl{kAndroidStatusLiteral,
91 method->name.Literal(),
92 args,
93 modifiers}};
94}
95
96unique_ptr<CppNamespace> NestInNamespaces(unique_ptr<Declaration> decl) {
97 using N = CppNamespace;
98 using NPtr = unique_ptr<N>;
99 return NPtr{new N{"android", NPtr{new N{"generated", std::move(decl)}}}};
100}
101
102} // namespace
103
104enum class ClassNames { BASE, CLIENT, SERVER, INTERFACE };
105
106string ClassName(const interface_type& interface, ClassNames type) {
107 string c_name = interface.name.Literal();
108
109 if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1]))
110 c_name = c_name.substr(1);
111
112 switch (type) {
113 case ClassNames::CLIENT:
114 c_name = "Bp" + c_name;
115 break;
116 case ClassNames::SERVER:
117 c_name = "Bn" + c_name;
118 break;
119 case ClassNames::INTERFACE:
120 c_name = "I" + c_name;
121 break;
122 case ClassNames::BASE:
123 break;
124 }
125 return c_name;
126}
127
Christopher Wileye3550c62015-09-29 13:26:10 -0700128unique_ptr<Document> BuildClientSource(const TypeNamespace& types,
129 const interface_type& parsed_doc) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700130 unique_ptr<CppNamespace> ns{new CppNamespace{"android"}};
Christopher Wileyf944e792015-09-29 10:00:46 -0700131 return unique_ptr<Document>{new CppSource{ {}, std::move(ns)}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700132}
133
Christopher Wileye3550c62015-09-29 13:26:10 -0700134unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
135 const interface_type& parsed_doc) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700136 unique_ptr<CppNamespace> ns{new CppNamespace{"android"}};
Christopher Wileyf944e792015-09-29 10:00:46 -0700137 return unique_ptr<Document>{new CppSource{ {}, std::move(ns)}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700138}
139
Christopher Wileye3550c62015-09-29 13:26:10 -0700140unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& types,
141 const interface_type& parsed_doc) {
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700142 const string i_name = ClassName(parsed_doc, ClassNames::INTERFACE);
143 const string bp_name = ClassName(parsed_doc, ClassNames::CLIENT);
144 vector<string> include_list{i_name + ".h", bp_name + ".h"};
145
146 string fq_name = i_name;
147 if (parsed_doc.package != nullptr && strlen(parsed_doc.package) > 0) {
148 fq_name = StringPrintf("%s.%s", parsed_doc.package, i_name.c_str());
149 }
150
151 unique_ptr<ConstructorDecl> meta_if{new ConstructorDecl{
152 "IMPLEMENT_META_INTERFACE",
153 {ClassName(parsed_doc, ClassNames::BASE), '"' + fq_name + '"'}
154 }};
155
156 return unique_ptr<Document>{new CppSource{
157 include_list,
158 NestInNamespaces(std::move(meta_if))}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700159}
160
Christopher Wileye3550c62015-09-29 13:26:10 -0700161unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
162 const interface_type& parsed_doc) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700163 const string i_name = ClassName(parsed_doc, ClassNames::INTERFACE);
164 const string bp_name = ClassName(parsed_doc, ClassNames::CLIENT);
Casey Dahlina834dd42015-09-23 11:52:15 -0700165
Christopher Wiley0c732db2015-09-29 14:36:44 -0700166 unique_ptr<ConstructorDecl> constructor{new ConstructorDecl(bp_name, {})};
Christopher Wileyf944e792015-09-29 10:00:46 -0700167 unique_ptr<ConstructorDecl> destructor{
Christopher Wiley0c732db2015-09-29 14:36:44 -0700168 new ConstructorDecl("~" + bp_name, {})};
Casey Dahlina834dd42015-09-23 11:52:15 -0700169
Christopher Wileyf944e792015-09-29 10:00:46 -0700170 vector<unique_ptr<Declaration>> publics;
Casey Dahlina834dd42015-09-23 11:52:15 -0700171 publics.push_back(std::move(constructor));
172 publics.push_back(std::move(destructor));
173
Christopher Wileye3550c62015-09-29 13:26:10 -0700174 for (method_type *item = parsed_doc.interface_items;
Casey Dahlina834dd42015-09-23 11:52:15 -0700175 item;
176 item = item->next) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700177 publics.push_back(BuildMethodDecl(item, types, false));
Casey Dahlina834dd42015-09-23 11:52:15 -0700178 }
179
Christopher Wileyf944e792015-09-29 10:00:46 -0700180 unique_ptr<ClassDecl> bp_class{
181 new ClassDecl{bp_name,
182 "public android::BpInterface<" + i_name + ">",
183 std::move(publics),
184 {}
Casey Dahlina834dd42015-09-23 11:52:15 -0700185 }};
186
Christopher Wiley0c732db2015-09-29 14:36:44 -0700187 return unique_ptr<Document>{new CppHeader{
188 bp_name + "_H",
189 {kIBinderHeader,
190 kIInterfaceHeader,
191 "utils/Errors.h",
192 i_name + ".h"},
193 NestInNamespaces(std::move(bp_class))}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700194}
195
Christopher Wileye3550c62015-09-29 13:26:10 -0700196unique_ptr<Document> BuildServerHeader(const TypeNamespace& types,
197 const interface_type& parsed_doc) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700198 const string i_name = ClassName(parsed_doc, ClassNames::INTERFACE);
199 const string bn_name = ClassName(parsed_doc, ClassNames::SERVER);
Casey Dahlin082f1d12015-09-21 14:06:25 -0700200
Christopher Wileyf944e792015-09-29 10:00:46 -0700201 unique_ptr<Declaration> on_transact{
Christopher Wiley0c732db2015-09-29 14:36:44 -0700202 new MethodDecl(kAndroidStatusLiteral, "onTransact",
Christopher Wileyf944e792015-09-29 10:00:46 -0700203 { "uint32_t code",
204 "const android::Parcel& data",
205 "android::Parcel* reply",
206 "uint32_t flags = 0"
207 })};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700208
Christopher Wileyf944e792015-09-29 10:00:46 -0700209 std::vector<unique_ptr<Declaration>> publics;
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700210 publics.push_back(std::move(on_transact));
211
Christopher Wileyf944e792015-09-29 10:00:46 -0700212 unique_ptr<ClassDecl> bn_class{
213 new ClassDecl{bn_name,
214 "public android::BnInterface<" + i_name + ">",
215 std::move(publics),
216 {}
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700217 }};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700218
Christopher Wiley0c732db2015-09-29 14:36:44 -0700219 return unique_ptr<Document>{new CppHeader{
220 bn_name + "_H",
221 {"binder/IInterface.h",
222 i_name + ".h"},
223 NestInNamespaces(std::move(bn_class))}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700224}
225
Christopher Wileye3550c62015-09-29 13:26:10 -0700226unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
227 const interface_type& parsed_doc) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700228 unique_ptr<ClassDecl> if_class{
229 new ClassDecl{ClassName(parsed_doc, ClassNames::INTERFACE),
230 "public android::IInterface"}};
231 if_class->AddPublic(unique_ptr<Declaration>{
232 new ConstructorDecl{
233 "DECLARE_META_INTERFACE",
234 {ClassName(parsed_doc, ClassNames::BASE)}}});
235
236 unique_ptr<Enum> call_enum{new Enum{"Call"}};
237 for (const method_type* method = parsed_doc.interface_items;
238 method;
239 method = method->next) {
240 if_class->AddPublic(BuildMethodDecl(method, types, true));
241 call_enum->AddValue(
242 UpperCase(method->name.data),
243 StringPrintf("android::IBinder::FIRST_CALL_TRANSACTION + %d",
244 method->assigned_id));
245 }
246 if_class->AddPublic(std::move(call_enum));
247
248 return unique_ptr<Document>{new CppSource{
249 {kIBinderHeader,
250 kIInterfaceHeader},
251 NestInNamespaces(std::move(if_class))}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700252}
253
Christopher Wileyf944e792015-09-29 10:00:46 -0700254bool GenerateCppForFile(const std::string& name, unique_ptr<Document> doc) {
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700255 if (!doc) {
256 return false;
257 }
258 unique_ptr<CodeWriter> writer = GetFileWriter(name);
259 doc->Write(writer.get());
260 return true;
261}
262
Casey Dahlina834dd42015-09-23 11:52:15 -0700263} // namespace internals
264
265using namespace internals;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700266
Christopher Wileye3550c62015-09-29 13:26:10 -0700267bool GenerateCpp(const CppOptions& options,
268 const TypeNamespace& types,
269 const interface_type& parsed_doc) {
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700270 bool success = true;
271
272 success &= GenerateCppForFile(options.ClientCppFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700273 BuildClientSource(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700274 success &= GenerateCppForFile(options.ClientHeaderFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700275 BuildClientHeader(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700276 success &= GenerateCppForFile(options.ServerCppFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700277 BuildServerSource(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700278 success &= GenerateCppForFile(options.ServerHeaderFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700279 BuildServerHeader(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700280 success &= GenerateCppForFile(options.InterfaceCppFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700281 BuildInterfaceSource(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700282 success &= GenerateCppForFile(options.InterfaceHeaderFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700283 BuildInterfaceHeader(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700284
285 return success;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700286}
287
Christopher Wileyf944e792015-09-29 10:00:46 -0700288} // namespace cpp
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700289} // namespace aidl
Christopher Wileyf944e792015-09-29 10:00:46 -0700290} // namespace android