summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ast_cpp.cpp42
-rw-r--r--ast_cpp.h27
-rw-r--r--ast_cpp_unittest.cpp25
-rw-r--r--generate_cpp.cpp186
-rw-r--r--generate_cpp_unittest.cpp79
5 files changed, 251 insertions, 108 deletions
diff --git a/ast_cpp.cpp b/ast_cpp.cpp
index 5c5c137..0cdbdd4 100644
--- a/ast_cpp.cpp
+++ b/ast_cpp.cpp
@@ -9,6 +9,10 @@ namespace android {
namespace aidl {
namespace cpp {
+ClassDecl::ClassDecl(const std::string& name, const std::string& parent)
+ : name_(name),
+ parent_(parent) {}
+
ClassDecl::ClassDecl(const std::string& name, const std::string& parent,
std::vector<unique_ptr<Declaration>> public_members,
std::vector<unique_ptr<Declaration>> private_members)
@@ -40,6 +44,14 @@ void ClassDecl::Write(CodeWriter* to) const {
to->Write("}; // class %s\n", name_.c_str());
}
+void ClassDecl::AddPublic(std::unique_ptr<Declaration> member) {
+ public_members_.push_back(std::move(member));
+}
+
+void ClassDecl::AddPrivate(std::unique_ptr<Declaration> member) {
+ private_members_.push_back(std::move(member));
+}
+
Enum::EnumField::EnumField(const string& k, const string&v)
: key(k),
value(v) {}
@@ -96,14 +108,22 @@ void ConstructorDecl::Write(CodeWriter* to) const {
MethodDecl::MethodDecl(const std::string& return_type,
const std::string& name,
+ std::vector<std::string> arguments)
+ : return_type_(return_type),
+ name_(name),
+ arguments_(arguments) {}
+
+MethodDecl::MethodDecl(const std::string& return_type,
+ const std::string& name,
std::vector<std::string> arguments,
- bool is_const,
- bool is_virtual)
+ uint32_t modifiers)
: return_type_(return_type),
name_(name),
arguments_(arguments),
- is_const_(is_const),
- is_virtual_(is_virtual) {}
+ is_const_(modifiers & IS_CONST),
+ is_virtual_(modifiers & IS_VIRTUAL),
+ is_override_(modifiers & IS_OVERRIDE),
+ is_pure_virtual_(modifiers & IS_PURE_VIRTUAL) {}
void MethodDecl::Write(CodeWriter* to) const {
if (is_virtual_)
@@ -125,6 +145,12 @@ void MethodDecl::Write(CodeWriter* to) const {
if (is_const_)
to->Write(" const");
+ if (is_override_)
+ to->Write(" override");
+
+ if (is_pure_virtual_)
+ to->Write(" = 0");
+
to->Write(";\n");
}
@@ -133,6 +159,14 @@ CppNamespace::CppNamespace(const std::string& name,
: declarations_(std::move(declarations)),
name_(name) {}
+CppNamespace::CppNamespace(const std::string& name,
+ unique_ptr<Declaration> declaration)
+ : name_(name) {
+ declarations_.push_back(std::move(declaration));
+}
+CppNamespace::CppNamespace(const std::string& name)
+ : name_(name) {}
+
void CppNamespace::Write(CodeWriter* to) const {
to->Write("namespace %s {\n\n", name_.c_str());
diff --git a/ast_cpp.h b/ast_cpp.h
index e4102cf..ec96a62 100644
--- a/ast_cpp.h
+++ b/ast_cpp.h
@@ -56,6 +56,8 @@ class Declaration : public AstNode {
class ClassDecl : public Declaration {
public:
ClassDecl(const std::string& name,
+ const std::string& parent);
+ ClassDecl(const std::string& name,
const std::string& parent,
std::vector<std::unique_ptr<Declaration>> public_members,
std::vector<std::unique_ptr<Declaration>> private_members);
@@ -63,6 +65,9 @@ class ClassDecl : public Declaration {
void Write(CodeWriter* to) const override;
+ void AddPublic(std::unique_ptr<Declaration> member);
+ void AddPrivate(std::unique_ptr<Declaration> member);
+
private:
std::string name_;
std::string parent_;
@@ -116,11 +121,20 @@ class ConstructorDecl : public Declaration {
class MethodDecl : public Declaration {
public:
+ enum Modifiers {
+ IS_CONST = 1 << 0,
+ IS_VIRTUAL = 1 << 1,
+ IS_OVERRIDE = 1 << 2,
+ IS_PURE_VIRTUAL = 1 << 3,
+ };
+
+ MethodDecl(const std::string& return_type,
+ const std::string& name,
+ std::vector<std::string> arguments);
MethodDecl(const std::string& return_type,
const std::string& name,
std::vector<std::string> arguments,
- bool is_const = false,
- bool is_virtual = false);
+ uint32_t modifiers);
virtual ~MethodDecl() = default;
void Write(CodeWriter* to) const override;
@@ -129,8 +143,10 @@ class MethodDecl : public Declaration {
const std::string return_type_;
const std::string name_;
std::vector<std::string> arguments_;
- bool is_const_;
- bool is_virtual_;
+ bool is_const_ = false;
+ bool is_virtual_ = false;
+ bool is_override_ = false;
+ bool is_pure_virtual_ = false;
DISALLOW_COPY_AND_ASSIGN(MethodDecl);
};
@@ -139,6 +155,9 @@ class CppNamespace : public Declaration {
public:
CppNamespace(const std::string& name,
std::vector<std::unique_ptr<Declaration>> declarations);
+ CppNamespace(const std::string& name,
+ std::unique_ptr<Declaration> declaration);
+ CppNamespace(const std::string& name);
virtual ~CppNamespace() = default;
void Write(CodeWriter* to) const override;
diff --git a/ast_cpp_unittest.cpp b/ast_cpp_unittest.cpp
index bd55bf5..cf40a55 100644
--- a/ast_cpp_unittest.cpp
+++ b/ast_cpp_unittest.cpp
@@ -68,20 +68,17 @@ R"(enum Foo {
} // namespace
TEST(AstCppTests, GeneratesHeader) {
- unique_ptr<MethodDecl> norm{new MethodDecl("void",
- "NormalMethod",
- { "int normalarg",
- "float normal2" })};
- unique_ptr<MethodDecl> sub{new MethodDecl("void",
- "SubMethod",
- { "int subarg" },
- true,
- true)};
- unique_ptr<MethodDecl> sub2{new MethodDecl("void",
- "SubMethod",
- { "int subarg" },
- true,
- true)};
+ unique_ptr<MethodDecl> norm{
+ new MethodDecl("void", "NormalMethod",
+ { "int normalarg", "float normal2" })};
+ unique_ptr<MethodDecl> sub{
+ new MethodDecl("void", "SubMethod",
+ { "int subarg" },
+ MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)};
+ unique_ptr<MethodDecl> sub2{
+ new MethodDecl("void", "SubMethod",
+ { "int subarg" },
+ MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)};
vector<unique_ptr<Declaration>> test_methods;
test_methods.push_back(std::move(norm));
test_methods.push_back(std::move(sub));
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 1a93a8f..93a6282 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -38,18 +38,17 @@ namespace android {
namespace aidl {
namespace cpp {
namespace internals {
+namespace {
-string StrippedLiteral(const buffer_type& buffer) {
- std::string i_name = buffer.Literal();
+const char kAndroidStatusLiteral[] = "android::status_t";
+const char kIBinderHeader[] = "binder/IBinder.h";
+const char kIInterfaceHeader[] = "binder/IInterface.h";
- string c_name;
-
- if (i_name.length() >= 2 && i_name[0] == 'I' && isupper(i_name[1]))
- c_name = i_name.substr(1);
- else
- c_name = i_name;
-
- return c_name;
+string UpperCase(const std::string& s) {
+ string result = s;
+ for (char& c : result)
+ c = toupper(c);
+ return result;
}
string GetCPPVarDec(const TypeNamespace& types, const type_type* type,
@@ -66,34 +65,92 @@ string GetCPPVarDec(const TypeNamespace& types, const type_type* type,
type->Brackets().c_str());
}
+unique_ptr<Declaration> BuildMethodDecl(const method_type* method,
+ const TypeNamespace& types,
+ bool for_interface) {
+ vector<string> args;
+ for (const unique_ptr<AidlArgument>& arg : *method->args) {
+ args.push_back(GetCPPVarDec(
+ types, &arg->type, arg->name.Literal(),
+ OUT_PARAMETER & convert_direction(arg->direction.data)));
+ }
+
+ string return_arg = GetCPPVarDec(types, &method->type, "_aidl_return", true);
+ args.push_back(return_arg);
+
+ uint32_t modifiers = 0;
+ if (for_interface) {
+ modifiers |= MethodDecl::IS_VIRTUAL;
+ modifiers |= MethodDecl::IS_PURE_VIRTUAL;
+ } else {
+ modifiers |= MethodDecl::IS_OVERRIDE;
+ }
+
+ return unique_ptr<Declaration>{
+ new MethodDecl{kAndroidStatusLiteral,
+ method->name.Literal(),
+ args,
+ modifiers}};
+}
+
+unique_ptr<CppNamespace> NestInNamespaces(unique_ptr<Declaration> decl) {
+ using N = CppNamespace;
+ using NPtr = unique_ptr<N>;
+ return NPtr{new N{"android", NPtr{new N{"generated", std::move(decl)}}}};
+}
+
+} // namespace
+
+enum class ClassNames { BASE, CLIENT, SERVER, INTERFACE };
+
+string ClassName(const interface_type& interface, ClassNames type) {
+ string c_name = interface.name.Literal();
+
+ if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1]))
+ c_name = c_name.substr(1);
+
+ switch (type) {
+ case ClassNames::CLIENT:
+ c_name = "Bp" + c_name;
+ break;
+ case ClassNames::SERVER:
+ c_name = "Bn" + c_name;
+ break;
+ case ClassNames::INTERFACE:
+ c_name = "I" + c_name;
+ break;
+ case ClassNames::BASE:
+ break;
+ }
+ return c_name;
+}
+
unique_ptr<Document> BuildClientSource(const TypeNamespace& types,
const interface_type& parsed_doc) {
- unique_ptr<CppNamespace> ns{new CppNamespace{"android", {}}};
+ unique_ptr<CppNamespace> ns{new CppNamespace{"android"}};
return unique_ptr<Document>{new CppSource{ {}, std::move(ns)}};
}
unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
const interface_type& parsed_doc) {
- unique_ptr<CppNamespace> ns{new CppNamespace{"android", {}}};
+ unique_ptr<CppNamespace> ns{new CppNamespace{"android"}};
return unique_ptr<Document>{new CppSource{ {}, std::move(ns)}};
}
unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& types,
const interface_type& parsed_doc) {
- unique_ptr<CppNamespace> ns{new CppNamespace{"android", {}}};
+ unique_ptr<CppNamespace> ns{new CppNamespace{"android"}};
return unique_ptr<Document>{new CppSource{ {}, std::move(ns)}};
}
unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
const interface_type& parsed_doc) {
- string i_name = parsed_doc.name.Literal();
- string c_name = StrippedLiteral(parsed_doc.name);
- string bp_name = "Bp" + c_name;
+ const string i_name = ClassName(parsed_doc, ClassNames::INTERFACE);
+ const string bp_name = ClassName(parsed_doc, ClassNames::CLIENT);
- unique_ptr<ConstructorDecl> constructor{
- new ConstructorDecl(bp_name, {})};
+ unique_ptr<ConstructorDecl> constructor{new ConstructorDecl(bp_name, {})};
unique_ptr<ConstructorDecl> destructor{
- new ConstructorDecl("~" + bp_name, {})};
+ new ConstructorDecl("~" + bp_name, {})};
vector<unique_ptr<Declaration>> publics;
publics.push_back(std::move(constructor));
@@ -102,25 +159,7 @@ unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
for (method_type *item = parsed_doc.interface_items;
item;
item = item->next) {
- string method_name = item->name.Literal();
- string return_arg =
- GetCPPVarDec(types, &item->type, "_aidl_return", true);
-
- vector<string> args;
-
- for (const std::unique_ptr<AidlArgument>& arg : *item->args)
- args.push_back(GetCPPVarDec(
- types, &arg->type, arg->name.Literal(),
- OUT_PARAMETER & convert_direction(arg->direction.data)));
-
- args.push_back(return_arg);
-
- unique_ptr<Declaration> meth {
- new MethodDecl("android::status_t", method_name,
- args, false, true)
- };
-
- publics.push_back(std::move(meth));
+ publics.push_back(BuildMethodDecl(item, types, false));
}
unique_ptr<ClassDecl> bp_class{
@@ -130,30 +169,22 @@ unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
{}
}};
- vector<unique_ptr<Declaration>> bp_class_vec;
- bp_class_vec.push_back(std::move(bp_class));
-
- unique_ptr<CppNamespace> ns {new CppNamespace{"android",
- std::move(bp_class_vec)}};
-
- unique_ptr<Document> bp_header{new CppHeader{bp_name + "_H",
- {"binder/IBinder.h",
- "binder/IInterface.h",
- "utils/Errors.h",
- i_name + ".h"},
- std::move(ns) }};
-
- return bp_header;
+ return unique_ptr<Document>{new CppHeader{
+ bp_name + "_H",
+ {kIBinderHeader,
+ kIInterfaceHeader,
+ "utils/Errors.h",
+ i_name + ".h"},
+ NestInNamespaces(std::move(bp_class))}};
}
unique_ptr<Document> BuildServerHeader(const TypeNamespace& types,
const interface_type& parsed_doc) {
- string i_name = parsed_doc.name.Literal();;
- string c_name = StrippedLiteral(parsed_doc.name);
- string bn_name = "Bn" + c_name;
+ const string i_name = ClassName(parsed_doc, ClassNames::INTERFACE);
+ const string bn_name = ClassName(parsed_doc, ClassNames::SERVER);
unique_ptr<Declaration> on_transact{
- new MethodDecl("android::status_t", "onTransact",
+ new MethodDecl(kAndroidStatusLiteral, "onTransact",
{ "uint32_t code",
"const android::Parcel& data",
"android::Parcel* reply",
@@ -170,24 +201,39 @@ unique_ptr<Document> BuildServerHeader(const TypeNamespace& types,
{}
}};
- std::vector<unique_ptr<Declaration>> declarations;
- declarations.push_back(std::move(bn_class));
-
- unique_ptr<CppNamespace> ns{
- new CppNamespace{"android", std::move(declarations)}};
-
- unique_ptr<Document> bn_header{new CppHeader{bn_name + "_H",
- {"binder/IInterface.h",
- i_name + ".h"},
- std::move(ns) }};
-
- return bn_header;
+ return unique_ptr<Document>{new CppHeader{
+ bn_name + "_H",
+ {"binder/IInterface.h",
+ i_name + ".h"},
+ NestInNamespaces(std::move(bn_class))}};
}
unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
const interface_type& parsed_doc) {
- unique_ptr<CppNamespace> ns{new CppNamespace{"android", {}}};
- return unique_ptr<Document>{new CppSource{ {}, std::move(ns)}};
+ unique_ptr<ClassDecl> if_class{
+ new ClassDecl{ClassName(parsed_doc, ClassNames::INTERFACE),
+ "public android::IInterface"}};
+ if_class->AddPublic(unique_ptr<Declaration>{
+ new ConstructorDecl{
+ "DECLARE_META_INTERFACE",
+ {ClassName(parsed_doc, ClassNames::BASE)}}});
+
+ unique_ptr<Enum> call_enum{new Enum{"Call"}};
+ for (const method_type* method = parsed_doc.interface_items;
+ method;
+ method = method->next) {
+ if_class->AddPublic(BuildMethodDecl(method, types, true));
+ call_enum->AddValue(
+ UpperCase(method->name.data),
+ StringPrintf("android::IBinder::FIRST_CALL_TRANSACTION + %d",
+ method->assigned_id));
+ }
+ if_class->AddPublic(std::move(call_enum));
+
+ return unique_ptr<Document>{new CppSource{
+ {kIBinderHeader,
+ kIInterfaceHeader},
+ NestInNamespaces(std::move(if_class))}};
}
bool GenerateCppForFile(const std::string& name, unique_ptr<Document> doc) {
diff --git a/generate_cpp_unittest.cpp b/generate_cpp_unittest.cpp
index 0974e5a..d0fef07 100644
--- a/generate_cpp_unittest.cpp
+++ b/generate_cpp_unittest.cpp
@@ -33,6 +33,8 @@ namespace cpp {
namespace internals {
unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
const interface_type& parsed_doc);
+unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
+ const interface_type& parsed_doc);
}
namespace {
@@ -53,42 +55,87 @@ R"(#ifndef BpPingResponder_H
namespace android {
+namespace generated {
+
class BpPingResponder : public public android::BpInterface<IPingResponder> {
public:
BpPingResponder();
~BpPingResponder();
-virtual android::status_t Ping(int32_t token, int32_t* _aidl_return);
+android::status_t Ping(int32_t token, int32_t* _aidl_return) override;
}; // class BpPingResponder
+} // namespace generated
+
} // namespace android
#endif // BpPingResponder_H)";
+const char kExpectedTrivialInterfaceHeaderOutput[] =
+R"(#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+namespace android {
+
+namespace generated {
+
+class IPingResponder : public public android::IInterface {
+public:
+DECLARE_META_INTERFACE(PingResponder);
+virtual android::status_t Ping(int32_t token, int32_t* _aidl_return) = 0;
+enum Call {
+ PING = android::IBinder::FIRST_CALL_TRANSACTION + 0,
+}
+}; // class IPingResponder
+
+} // namespace generated
+
+} // namespace android
+)";
+
} // namespace
-TEST(GenerateCPPTests, GeneratesClientHeader) {
- Parser p{"BpExampleInterface.h"};
- p.SetFileContents(kTrivialInterfaceAIDL);
+class TrivialInterfaceASTTest : public ::testing::Test {
+ protected:
+ interface_type* Parse() {
+ Parser p{"BpExampleInterface.h"};
+ p.SetFileContents(kTrivialInterfaceAIDL);
- ASSERT_TRUE(p.RunParser());
+ EXPECT_TRUE(p.RunParser());
- document_item_type *parsed_doc = p.GetDocument();
+ document_item_type *parsed_doc = p.GetDocument();
+ if (parsed_doc == nullptr) return nullptr;
- ASSERT_NE(nullptr, parsed_doc);
- EXPECT_EQ(nullptr, parsed_doc->next);
- ASSERT_EQ(INTERFACE_TYPE_BINDER, parsed_doc->item_type);
+ EXPECT_NE(nullptr, parsed_doc);
+ EXPECT_EQ(nullptr, parsed_doc->next);
+ EXPECT_EQ(INTERFACE_TYPE_BINDER, parsed_doc->item_type);
- interface_type *interface = (interface_type*)parsed_doc;
+ return (interface_type*)parsed_doc;
+ }
- TypeNamespace types;
- unique_ptr<Document> doc = internals::BuildClientHeader(types, *interface);
+ void Compare(Document* doc, const char* expected) {
+ string output;
+ unique_ptr<CodeWriter> cw = GetStringWriter(&output);
- string output;
- unique_ptr<CodeWriter> cw = GetStringWriter(&output);
+ doc->Write(cw.get());
- doc->Write(cw.get());
+ EXPECT_EQ(expected, output);
+ }
+};
- EXPECT_EQ(kExpectedTrivialClientHeaderOutput, output);
+TEST_F(TrivialInterfaceASTTest, GeneratesClientHeader) {
+ interface_type* interface = Parse();
+ ASSERT_NE(interface, nullptr);
+ TypeNamespace types;
+ unique_ptr<Document> doc = internals::BuildClientHeader(types, *interface);
+ Compare(doc.get(), kExpectedTrivialClientHeaderOutput);
+}
+
+TEST_F(TrivialInterfaceASTTest, GeneratesInterfaceHeader) {
+ interface_type* interface = Parse();
+ ASSERT_NE(interface, nullptr);
+ TypeNamespace types;
+ unique_ptr<Document> doc = internals::BuildInterfaceHeader(types, *interface);
+ Compare(doc.get(), kExpectedTrivialInterfaceHeaderOutput);
}
} // namespace cpp