diff options
-rw-r--r-- | ast_cpp.cpp | 42 | ||||
-rw-r--r-- | ast_cpp.h | 27 | ||||
-rw-r--r-- | ast_cpp_unittest.cpp | 25 | ||||
-rw-r--r-- | generate_cpp.cpp | 186 | ||||
-rw-r--r-- | generate_cpp_unittest.cpp | 79 |
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()); @@ -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 |