From 249f71a12bb950eefa9768d461db9bf084432d55 Mon Sep 17 00:00:00 2001 From: Brett Cooley Date: Tue, 5 May 2015 17:10:53 -0700 Subject: [PATCH] Initial support for propagating namespaces from schema files to generated code Change-Id: Ifc10c54845ea7553586d1896d509314d68e9ab0f --- .gitignore | 2 ++ include/flatbuffers/idl.h | 6 ++++++ samples/monster_generated.h | 6 +++--- src/idl_gen_cpp.cpp | 33 ++++++++++++++++++++++++++------- src/idl_parser.cpp | 27 ++++++++++++++++++++++++--- tests/monster_test_generated.h | 8 ++++---- 6 files changed, 65 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 24994897b..c95336eb0 100755 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,9 @@ **/*.dir/** **/CMakeFiles/** **/cmake_install.cmake +**/install_manifest.txt **/CMakeCache.txt +**/CMakeTestfile.cmake **/Debug/** **/Release/** build.xml diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 14d3364a9..e06521d07 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -313,6 +313,12 @@ class Parser { // Mark all definitions as already having code generated. void MarkGenerated(); + // Given a (potentally unqualified) name, return the "fully qualified" name + // which has a full namespaced descriptor. If the parser has no current + // namespace context, or if the name passed is partially qualified the input + // is simply returned. + std::string GetFullyQualifiedName(const std::string &name) const; + // Get the files recursively included by the given file. The returned // container will have at least the given file. std::set GetIncludedFilesRecursive( diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 2d0b00266..b761d6fca 100755 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -127,13 +127,13 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An } } -inline const Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); } +inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); } inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); } -inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); } +inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); } -inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root); } +inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root); } } // namespace Sample } // namespace MyGame diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 37d968e8a..f336cc812 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -44,6 +44,18 @@ static std::string WrapInNameSpace(const Parser &parser, return WrapInNameSpace(parser, def.defined_namespace, def.name); } +// Translates a qualified name in flatbuffer text format to the same name in +// the equivalent C++ namepsace. +static std::string TranslateNameSpace(const std::string &qualified_name) { + std::string cpp_qualified_name = qualified_name; + size_t start_pos = 0; + while((start_pos = cpp_qualified_name.find(".", start_pos)) != + std::string::npos) { + cpp_qualified_name.replace(start_pos, 1, "::"); + } + return cpp_qualified_name; +} + // Return a C++ type from the table in idl.h static std::string GenTypeBasic(const Parser &parser, const Type &type, @@ -258,11 +270,15 @@ static void GenTable(const Parser &parser, StructDef &struct_def, } auto nested = field.attributes.Lookup("nested_flatbuffer"); if (nested) { - auto nested_root = parser.structs_.Lookup(nested->constant); + std::string qualified_name = parser.GetFullyQualifiedName( + nested->constant); + auto nested_root = parser.structs_.Lookup(qualified_name); assert(nested_root); // Guaranteed to exist by parser. - code += " const " + nested_root->name + " *" + field.name; + std::string cpp_qualified_name = TranslateNameSpace(qualified_name); + + code += " const " + cpp_qualified_name + " *" + field.name; code += "_nested_root() const { return flatbuffers::GetRoot<"; - code += nested_root->name + ">(" + field.name + "()->Data()); }\n"; + code += cpp_qualified_name + ">(" + field.name + "()->Data()); }\n"; } // Generate a comparison function for this field if it is a key. if (field.key) { @@ -685,11 +701,14 @@ std::string GenerateCPP(const Parser &parser, // Generate convenient global helper functions: if (parser.root_struct_def) { auto &name = parser.root_struct_def->name; + std::string qualified_name = parser.GetFullyQualifiedName(name); + std::string cpp_qualified_name = TranslateNameSpace(qualified_name); + // The root datatype accessor: - code += "inline const " + name + " *Get"; + code += "inline const " + cpp_qualified_name + " *Get"; code += name; code += "(const void *buf) { return flatbuffers::GetRoot<"; - code += name + ">(buf); }\n\n"; + code += cpp_qualified_name + ">(buf); }\n\n"; if (opts.mutable_buffer) { code += "inline " + name + " *GetMutable"; code += name; @@ -702,7 +721,7 @@ std::string GenerateCPP(const Parser &parser, code += name; code += "Buffer(flatbuffers::Verifier &verifier) { " "return verifier.VerifyBuffer<"; - code += name + ">(); }\n\n"; + code += cpp_qualified_name + ">(); }\n\n"; if (parser.file_identifier_.length()) { // Return the identifier @@ -727,7 +746,7 @@ std::string GenerateCPP(const Parser &parser, // Finish a buffer with a given root object: code += "inline void Finish" + name; code += "Buffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<"; - code += name + "> root) { fbb.Finish(root"; + code += cpp_qualified_name + "> root) { fbb.Finish(root"; if (parser.file_identifier_.length()) code += ", " + name + "Identifier()"; code += "); }\n\n"; diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 9cc99d623..2340cea2e 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -773,12 +773,13 @@ void Parser::ParseSingleValue(Value &e) { } StructDef *Parser::LookupCreateStruct(const std::string &name) { - auto struct_def = structs_.Lookup(name); + std::string qualified_name = GetFullyQualifiedName(name); + auto struct_def = structs_.Lookup(qualified_name); if (!struct_def) { // Rather than failing, we create a "pre declared" StructDef, due to // circular references, and check for errors at the end of parsing. struct_def = new StructDef(); - structs_.Add(name, struct_def); + structs_.Add(qualified_name, struct_def); struct_def->name = name; struct_def->predecl = true; struct_def->defined_namespace = namespaces_.back(); @@ -951,10 +952,30 @@ void Parser::ParseDecl() { } bool Parser::SetRootType(const char *name) { - root_struct_def = structs_.Lookup(name); + root_struct_def = structs_.Lookup(GetFullyQualifiedName(name)); return root_struct_def != nullptr; } +std::string Parser::GetFullyQualifiedName(const std::string &name) const { + Namespace *ns = namespaces_.back(); + + // Early exit if we don't have a defined namespace, or if the name is already + // partially qualified + if (ns->components.size() == 0 || name.find(".") != std::string::npos) { + return name; + } + std::stringstream stream; + for (size_t i = 0; i != ns->components.size(); ++i) { + if (i != 0) { + stream << "."; + } + stream << ns->components[i]; + } + + stream << "." << name; + return stream.str(); +} + void Parser::MarkGenerated() { // Since the Parser object retains definitions across files, we must // ensure we only output code for definitions once, in the file they are first diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 5de3da024..7fb698b06 100755 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -167,7 +167,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { Monster *mutable_enemy() { return GetPointer(28); } const flatbuffers::Vector *testnestedflatbuffer() const { return GetPointer *>(30); } flatbuffers::Vector *mutable_testnestedflatbuffer() { return GetPointer *>(30); } - const Monster *testnestedflatbuffer_nested_root() const { return flatbuffers::GetRoot(testnestedflatbuffer()->Data()); } + const MyGame::Example::Monster *testnestedflatbuffer_nested_root() const { return flatbuffers::GetRoot(testnestedflatbuffer()->Data()); } const Stat *testempty() const { return GetPointer(32); } Stat *mutable_testempty() { return GetPointer(32); } uint8_t testbool() const { return GetField(34, 0); } @@ -322,11 +322,11 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An } } -inline const Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); } +inline const MyGame::Example::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); } inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); } -inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); } +inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); } inline const char *MonsterIdentifier() { return "MONS"; } @@ -334,7 +334,7 @@ inline bool MonsterBufferHasIdentifier(const void *buf) { return flatbuffers::Bu inline const char *MonsterExtension() { return "mon"; } -inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root, MonsterIdentifier()); } +inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root, MonsterIdentifier()); } } // namespace Example } // namespace MyGame