From c58ae942256577ab4c20137ead6f4e1b2a03ff3c Mon Sep 17 00:00:00 2001 From: Casper Date: Thu, 17 Jun 2021 11:50:04 -0400 Subject: [PATCH] Add the file a symbol is declared in to Reflection (#6613) * Add the file a symbol is declared in to Reflection If we move a code-generator to depend on Reflection, it may need to know which file something was declared in to properly name generated files. * Doc comments in reflection, and more precise tests * Add --project-root flag to flatc, normalize declaraion_file to this root * fix --project-root stuff * posixpath * fix scripts * format * rename --project-root to --bfbs-filenames Also, make it optional, rather than defaulting to `./`, if its not specified, then don't serialize the filenames. * bfbs generation * fix some tests * uncomment a thing * add to project root directory conditionally * fix * git clang format * Added help description and removed != nullptr * " * Remove accidental change to docs * Remove accidental change to docs * Pool strings Co-authored-by: Casper Neo --- CMakeLists.txt | 2 + grpc/examples/generate.sh | 8 +- include/flatbuffers/idl.h | 19 +- include/flatbuffers/reflection_generated.h | 95 +- include/flatbuffers/util.h | 5 + reflection/reflection.fbs | 11 +- samples/monster.bfbs | Bin 1856 -> 1920 bytes scripts/check-grpc-generated-code.sh | 0 scripts/clang-format-all.sh | 0 scripts/clang-format-git.sh | 0 src/flatc.cpp | 11 +- src/idl_parser.cpp | 126 ++- src/util.cpp | 24 + tests/arrays_test.bfbs | Bin 1288 -> 1328 bytes tests/generate_code.bat | 2 +- tests/generate_code.sh | 10 +- tests/monster_test.bfbs | Bin 12864 -> 13120 bytes tests/monster_test_bfbs_generated.h | 1173 ++++++++++---------- tests/rust_usage_test/outdir/build.rs | 5 +- tests/test.cpp | 41 +- 20 files changed, 863 insertions(+), 669 deletions(-) mode change 100644 => 100755 scripts/check-grpc-generated-code.sh mode change 100644 => 100755 scripts/clang-format-all.sh mode change 100644 => 100755 scripts/clang-format-git.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d677f1c446..249f46bd739 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -443,6 +443,7 @@ function(compile_flatbuffers_schema_to_binary SRC_FBS) OUTPUT ${GEN_BINARY_SCHEMA} COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -b --schema --bfbs-comments --bfbs-builtins + --bfbs-filenames ${SRC_FBS_DIR} -I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test" -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" @@ -468,6 +469,7 @@ function(compile_flatbuffers_schema_to_embedded_binary SRC_FBS OPT) --cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs ${OPT} --bfbs-comments --bfbs-builtins --bfbs-gen-embed + --bfbs-filenames ${SRC_FBS_DIR} -I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test" -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" diff --git a/grpc/examples/generate.sh b/grpc/examples/generate.sh index b0740d8ad11..39ca6620c3a 100755 --- a/grpc/examples/generate.sh +++ b/grpc/examples/generate.sh @@ -41,7 +41,7 @@ generator="--grpc $current_dir/greeter.fbs" cd go cd greeter -fbc --go ${generator} +fbc --bfbs-filenames ../.. --go ${generator} cd ${current_dir} @@ -50,7 +50,7 @@ cd python cd greeter -fbc --python ${generator} +fbc --bfbs-filenames ../.. --python ${generator} cd ${current_dir} @@ -58,7 +58,7 @@ cd ${current_dir} cd swift cd Greeter/Sources/Model -fbc --swift ${generator} +fbc --bfbs-filenames ../../../.. --swift ${generator} cd ${current_dir} @@ -66,6 +66,6 @@ cd ${current_dir} cd ts cd greeter/src -fbc --ts ${generator} +fbc --bfbs-filenames ../../.. --ts ${generator} cd ${current_dir} diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index fa9bfefe47a..71de8254c16 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -266,7 +266,8 @@ struct Definition { defined_namespace(nullptr), serialized_location(0), index(-1), - refcount(1) {} + refcount(1), + declaration_file(nullptr) {} flatbuffers::Offset< flatbuffers::Vector>> @@ -286,6 +287,7 @@ struct Definition { uoffset_t serialized_location; int index; // Inside the vector it is stored. int refcount; + const std::string *declaration_file; }; struct FieldDef : public Definition { @@ -591,6 +593,7 @@ struct IDLOptions { std::string filename_suffix; std::string filename_extension; bool no_warnings; + std::string project_root; // Possible options for the more general generator below. enum Language { @@ -677,6 +680,7 @@ struct IDLOptions { filename_suffix("_generated"), filename_extension(), no_warnings(false), + project_root(""), lang(IDLOptions::kJava), mini_reflect(IDLOptions::kNone), require_explicit_ids(false), @@ -941,14 +945,15 @@ class Parser : public ParserState { StructDef *LookupCreateStruct(const std::string &name, bool create_if_new = true, bool definition = false); - FLATBUFFERS_CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest); + FLATBUFFERS_CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest, + const char *filename); FLATBUFFERS_CHECKED_ERROR ParseNamespace(); FLATBUFFERS_CHECKED_ERROR StartStruct(const std::string &name, StructDef **dest); FLATBUFFERS_CHECKED_ERROR StartEnum(const std::string &name, bool is_union, EnumDef **dest); - FLATBUFFERS_CHECKED_ERROR ParseDecl(); - FLATBUFFERS_CHECKED_ERROR ParseService(); + FLATBUFFERS_CHECKED_ERROR ParseDecl(const char *filename); + FLATBUFFERS_CHECKED_ERROR ParseService(const char *filename); FLATBUFFERS_CHECKED_ERROR ParseProtoFields(StructDef *struct_def, bool isextend, bool inside_oneof); FLATBUFFERS_CHECKED_ERROR ParseProtoOption(); @@ -985,6 +990,8 @@ class Parser : public ParserState { FLATBUFFERS_CHECKED_ERROR RecurseError(); template CheckedError Recurse(F f); + const std::string &GetPooledString(const std::string &s) const; + public: SymbolTable types_; SymbolTable structs_; @@ -1020,6 +1027,10 @@ class Parser : public ParserState { std::vector> field_stack_; + // TODO(cneo): Refactor parser to use string_cache more often to save + // on memory usage. + mutable std::set string_cache_; + int anonymous_counter_; int parse_depth_counter_; // stack-overflow guard }; diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h index 32905046ef2..d0be270bfa0 100644 --- a/include/flatbuffers/reflection_generated.h +++ b/include/flatbuffers/reflection_generated.h @@ -114,6 +114,7 @@ inline const char *EnumNameBaseType(BaseType e) { return EnumNamesBaseType()[index]; } +/// New schema language features that are not supported by old code generators. enum AdvancedFeatures { AdvancedArrayFeatures = 1ULL, AdvancedUnionFeatures = 2ULL, @@ -401,7 +402,8 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_IS_UNION = 8, VT_UNDERLYING_TYPE = 10, VT_ATTRIBUTES = 12, - VT_DOCUMENTATION = 14 + VT_DOCUMENTATION = 14, + VT_DECLARATION_FILE = 16 }; const flatbuffers::String *name() const { return GetPointer(VT_NAME); @@ -427,6 +429,10 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::Vector> *documentation() const { return GetPointer> *>(VT_DOCUMENTATION); } + /// File that this Enum is declared in. + const flatbuffers::String *declaration_file() const { + return GetPointer(VT_DECLARATION_FILE); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyOffsetRequired(verifier, VT_NAME) && @@ -443,6 +449,8 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyOffset(verifier, VT_DOCUMENTATION) && verifier.VerifyVector(documentation()) && verifier.VerifyVectorOfStrings(documentation()) && + VerifyOffset(verifier, VT_DECLARATION_FILE) && + verifier.VerifyString(declaration_file()) && verifier.EndTable(); } }; @@ -469,6 +477,9 @@ struct EnumBuilder { void add_documentation(flatbuffers::Offset>> documentation) { fbb_.AddOffset(Enum::VT_DOCUMENTATION, documentation); } + void add_declaration_file(flatbuffers::Offset declaration_file) { + fbb_.AddOffset(Enum::VT_DECLARATION_FILE, declaration_file); + } explicit EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -490,8 +501,10 @@ inline flatbuffers::Offset CreateEnum( bool is_union = false, flatbuffers::Offset underlying_type = 0, flatbuffers::Offset>> attributes = 0, - flatbuffers::Offset>> documentation = 0) { + flatbuffers::Offset>> documentation = 0, + flatbuffers::Offset declaration_file = 0) { EnumBuilder builder_(_fbb); + builder_.add_declaration_file(declaration_file); builder_.add_documentation(documentation); builder_.add_attributes(attributes); builder_.add_underlying_type(underlying_type); @@ -508,11 +521,13 @@ inline flatbuffers::Offset CreateEnumDirect( bool is_union = false, flatbuffers::Offset underlying_type = 0, std::vector> *attributes = nullptr, - const std::vector> *documentation = nullptr) { + const std::vector> *documentation = nullptr, + const char *declaration_file = nullptr) { auto name__ = name ? _fbb.CreateString(name) : 0; auto values__ = values ? _fbb.CreateVectorOfSortedTables(values) : 0; auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables(attributes) : 0; auto documentation__ = documentation ? _fbb.CreateVector>(*documentation) : 0; + auto declaration_file__ = declaration_file ? _fbb.CreateString(declaration_file) : 0; return reflection::CreateEnum( _fbb, name__, @@ -520,7 +535,8 @@ inline flatbuffers::Offset CreateEnumDirect( is_union, underlying_type, attributes__, - documentation__); + documentation__, + declaration_file__); } struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { @@ -730,7 +746,8 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_MINALIGN = 10, VT_BYTESIZE = 12, VT_ATTRIBUTES = 14, - VT_DOCUMENTATION = 16 + VT_DOCUMENTATION = 16, + VT_DECLARATION_FILE = 18 }; const flatbuffers::String *name() const { return GetPointer(VT_NAME); @@ -759,6 +776,10 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::Vector> *documentation() const { return GetPointer> *>(VT_DOCUMENTATION); } + /// File that this Object is declared in. + const flatbuffers::String *declaration_file() const { + return GetPointer(VT_DECLARATION_FILE); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyOffsetRequired(verifier, VT_NAME) && @@ -775,6 +796,8 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyOffset(verifier, VT_DOCUMENTATION) && verifier.VerifyVector(documentation()) && verifier.VerifyVectorOfStrings(documentation()) && + VerifyOffset(verifier, VT_DECLARATION_FILE) && + verifier.VerifyString(declaration_file()) && verifier.EndTable(); } }; @@ -804,6 +827,9 @@ struct ObjectBuilder { void add_documentation(flatbuffers::Offset>> documentation) { fbb_.AddOffset(Object::VT_DOCUMENTATION, documentation); } + void add_declaration_file(flatbuffers::Offset declaration_file) { + fbb_.AddOffset(Object::VT_DECLARATION_FILE, declaration_file); + } explicit ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -825,8 +851,10 @@ inline flatbuffers::Offset CreateObject( int32_t minalign = 0, int32_t bytesize = 0, flatbuffers::Offset>> attributes = 0, - flatbuffers::Offset>> documentation = 0) { + flatbuffers::Offset>> documentation = 0, + flatbuffers::Offset declaration_file = 0) { ObjectBuilder builder_(_fbb); + builder_.add_declaration_file(declaration_file); builder_.add_documentation(documentation); builder_.add_attributes(attributes); builder_.add_bytesize(bytesize); @@ -845,11 +873,13 @@ inline flatbuffers::Offset CreateObjectDirect( int32_t minalign = 0, int32_t bytesize = 0, std::vector> *attributes = nullptr, - const std::vector> *documentation = nullptr) { + const std::vector> *documentation = nullptr, + const char *declaration_file = nullptr) { auto name__ = name ? _fbb.CreateString(name) : 0; auto fields__ = fields ? _fbb.CreateVectorOfSortedTables(fields) : 0; auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables(attributes) : 0; auto documentation__ = documentation ? _fbb.CreateVector>(*documentation) : 0; + auto declaration_file__ = declaration_file ? _fbb.CreateString(declaration_file) : 0; return reflection::CreateObject( _fbb, name__, @@ -858,7 +888,8 @@ inline flatbuffers::Offset CreateObjectDirect( minalign, bytesize, attributes__, - documentation__); + documentation__, + declaration_file__); } struct RPCCall FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { @@ -983,7 +1014,8 @@ struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_NAME = 4, VT_CALLS = 6, VT_ATTRIBUTES = 8, - VT_DOCUMENTATION = 10 + VT_DOCUMENTATION = 10, + VT_DECLARATION_FILE = 12 }; const flatbuffers::String *name() const { return GetPointer(VT_NAME); @@ -1003,6 +1035,10 @@ struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::Vector> *documentation() const { return GetPointer> *>(VT_DOCUMENTATION); } + /// File that this Service is declared in. + const flatbuffers::String *declaration_file() const { + return GetPointer(VT_DECLARATION_FILE); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyOffsetRequired(verifier, VT_NAME) && @@ -1016,6 +1052,8 @@ struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyOffset(verifier, VT_DOCUMENTATION) && verifier.VerifyVector(documentation()) && verifier.VerifyVectorOfStrings(documentation()) && + VerifyOffset(verifier, VT_DECLARATION_FILE) && + verifier.VerifyString(declaration_file()) && verifier.EndTable(); } }; @@ -1036,6 +1074,9 @@ struct ServiceBuilder { void add_documentation(flatbuffers::Offset>> documentation) { fbb_.AddOffset(Service::VT_DOCUMENTATION, documentation); } + void add_declaration_file(flatbuffers::Offset declaration_file) { + fbb_.AddOffset(Service::VT_DECLARATION_FILE, declaration_file); + } explicit ServiceBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -1053,8 +1094,10 @@ inline flatbuffers::Offset CreateService( flatbuffers::Offset name = 0, flatbuffers::Offset>> calls = 0, flatbuffers::Offset>> attributes = 0, - flatbuffers::Offset>> documentation = 0) { + flatbuffers::Offset>> documentation = 0, + flatbuffers::Offset declaration_file = 0) { ServiceBuilder builder_(_fbb); + builder_.add_declaration_file(declaration_file); builder_.add_documentation(documentation); builder_.add_attributes(attributes); builder_.add_calls(calls); @@ -1067,17 +1110,20 @@ inline flatbuffers::Offset CreateServiceDirect( const char *name = nullptr, std::vector> *calls = nullptr, std::vector> *attributes = nullptr, - const std::vector> *documentation = nullptr) { + const std::vector> *documentation = nullptr, + const char *declaration_file = nullptr) { auto name__ = name ? _fbb.CreateString(name) : 0; auto calls__ = calls ? _fbb.CreateVectorOfSortedTables(calls) : 0; auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables(attributes) : 0; auto documentation__ = documentation ? _fbb.CreateVector>(*documentation) : 0; + auto declaration_file__ = declaration_file ? _fbb.CreateString(declaration_file) : 0; return reflection::CreateService( _fbb, name__, calls__, attributes__, - documentation__); + documentation__, + declaration_file__); } struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { @@ -1089,7 +1135,8 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_FILE_EXT = 10, VT_ROOT_TABLE = 12, VT_SERVICES = 14, - VT_ADVANCED_FEATURES = 16 + VT_ADVANCED_FEATURES = 16, + VT_FBS_FILES = 18 }; const flatbuffers::Vector> *objects() const { return GetPointer> *>(VT_OBJECTS); @@ -1112,6 +1159,11 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { reflection::AdvancedFeatures advanced_features() const { return static_cast(GetField(VT_ADVANCED_FEATURES, 0)); } + /// All the files used in this compilation. Files are relative to where + /// flatc was invoked. + const flatbuffers::Vector> *fbs_files() const { + return GetPointer> *>(VT_FBS_FILES); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyOffsetRequired(verifier, VT_OBJECTS) && @@ -1130,6 +1182,9 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { verifier.VerifyVector(services()) && verifier.VerifyVectorOfTables(services()) && VerifyField(verifier, VT_ADVANCED_FEATURES) && + VerifyOffset(verifier, VT_FBS_FILES) && + verifier.VerifyVector(fbs_files()) && + verifier.VerifyVectorOfStrings(fbs_files()) && verifier.EndTable(); } }; @@ -1159,6 +1214,9 @@ struct SchemaBuilder { void add_advanced_features(reflection::AdvancedFeatures advanced_features) { fbb_.AddElement(Schema::VT_ADVANCED_FEATURES, static_cast(advanced_features), 0); } + void add_fbs_files(flatbuffers::Offset>> fbs_files) { + fbb_.AddOffset(Schema::VT_FBS_FILES, fbs_files); + } explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -1180,9 +1238,11 @@ inline flatbuffers::Offset CreateSchema( flatbuffers::Offset file_ext = 0, flatbuffers::Offset root_table = 0, flatbuffers::Offset>> services = 0, - reflection::AdvancedFeatures advanced_features = static_cast(0)) { + reflection::AdvancedFeatures advanced_features = static_cast(0), + flatbuffers::Offset>> fbs_files = 0) { SchemaBuilder builder_(_fbb); builder_.add_advanced_features(advanced_features); + builder_.add_fbs_files(fbs_files); builder_.add_services(services); builder_.add_root_table(root_table); builder_.add_file_ext(file_ext); @@ -1200,12 +1260,14 @@ inline flatbuffers::Offset CreateSchemaDirect( const char *file_ext = nullptr, flatbuffers::Offset root_table = 0, std::vector> *services = nullptr, - reflection::AdvancedFeatures advanced_features = static_cast(0)) { + reflection::AdvancedFeatures advanced_features = static_cast(0), + const std::vector> *fbs_files = nullptr) { auto objects__ = objects ? _fbb.CreateVectorOfSortedTables(objects) : 0; auto enums__ = enums ? _fbb.CreateVectorOfSortedTables(enums) : 0; auto file_ident__ = file_ident ? _fbb.CreateString(file_ident) : 0; auto file_ext__ = file_ext ? _fbb.CreateString(file_ext) : 0; auto services__ = services ? _fbb.CreateVectorOfSortedTables(services) : 0; + auto fbs_files__ = fbs_files ? _fbb.CreateVector>(*fbs_files) : 0; return reflection::CreateSchema( _fbb, objects__, @@ -1214,7 +1276,8 @@ inline flatbuffers::Offset CreateSchemaDirect( file_ext__, root_table, services__, - advanced_features); + advanced_features, + fbs_files__); } inline const reflection::Schema *GetSchema(const void *buf) { diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h index f30bd98c9a0..edbee649569 100644 --- a/include/flatbuffers/util.h +++ b/include/flatbuffers/util.h @@ -468,6 +468,7 @@ std::string ConCatPathFileName(const std::string &path, // Replaces any '\\' separators with '/' std::string PosixPath(const char *path); +std::string PosixPath(const std::string &path); // This function ensure a directory exists, by recursively // creating dirs for any parts of the path that don't exist yet. @@ -477,6 +478,10 @@ void EnsureDirExists(const std::string &filepath); // Returns the input path if the absolute path couldn't be resolved. std::string AbsolutePath(const std::string &filepath); +// Returns files relative to the --project_root path, prefixed with `//`. +std::string RelativeToRootPath(const std::string &project, + const std::string &filepath); + // To and from UTF-8 unicode conversion functions // Convert a unicode code point into a UTF-8 representation by appending it diff --git a/reflection/reflection.fbs b/reflection/reflection.fbs index c80f3567275..5072471055e 100644 --- a/reflection/reflection.fbs +++ b/reflection/reflection.fbs @@ -60,6 +60,8 @@ table Enum { underlying_type:Type (required); attributes:[KeyValue]; documentation:[string]; + /// File that this Enum is declared in. + declaration_file: string; } table Field { @@ -85,6 +87,8 @@ table Object { // Used for both tables and structs. bytesize:int; // For structs. attributes:[KeyValue]; documentation:[string]; + /// File that this Object is declared in. + declaration_file: string; } table RPCCall { @@ -100,9 +104,11 @@ table Service { calls:[RPCCall]; attributes:[KeyValue]; documentation:[string]; + /// File that this Service is declared in. + declaration_file: string; } -// New schema language features that are not supported by old code generators. +/// New schema language features that are not supported by old code generators. enum AdvancedFeatures : ulong (bit_flags) { AdvancedArrayFeatures, AdvancedUnionFeatures, @@ -118,6 +124,9 @@ table Schema { root_table:Object; services:[Service]; // Sorted. advanced_features:AdvancedFeatures; + /// All the files used in this compilation. Files are relative to where + /// flatc was invoked. + fbs_files:[string]; } root_type Schema; diff --git a/samples/monster.bfbs b/samples/monster.bfbs index 8af5da1ffccd3d274662a4751207772632e0df08..4fa92c1f63d86cf66945fa9924b0286696379d04 100644 GIT binary patch delta 755 zcmZ`%&r4KM6h3F(dnTddkC~iN2YiqV5gl5DpbL?StVNBGV(sdI4_nMQBD4?$GsLxW zvPIA?qBiYUtclx7IMX zJ}qp2J4q5Mt}oOtQbE~yO`Xs$1)K*$AS1sLV1da0bmTPR+&sm28<+qJz}3x5Q8TVC zM$Pp`T)oh0v^J2tu_(^iI4aNnk&+X#lRr_ z0|sH1u(1e($zU`H;`N;SBIPE}J@=mXx#v93X}78`e4P;@O7*8k5y(#wGN_WgI0Y$; zou~_l1I*+5fktE$k~M|l%BdIJTLB%&BmZm?T?podRh0_$BB*vyL>o4);{^!o zAP77ol%NdIQ8;a`CGsgb+>|Bx5aaS*G;Th)PpX;j0VZrKpIah|I*t>>y}Z01Ic}96 zO7|f^N>EvJS$-w01Nr~5QtwI@J5%;{5hq< argc) Error("missing path following: " + arg, true); + opts.project_root = argv[argi]; + if (!DirExists(opts.project_root.c_str())) + Error(arg + " is not a directory: " + opts.project_root); } else if (arg == "--conform") { if (++argi >= argc) Error("missing path following: " + arg, true); conform_to_schema = flatbuffers::PosixPath(argv[argi]); @@ -436,8 +443,8 @@ int FlatCompiler::Compile(int argc, const char **argv) { bool is_binary = static_cast(file_it - filenames.begin()) >= binary_files_from; auto ext = flatbuffers::GetExtension(filename); - auto is_schema = ext == "fbs" || ext == "proto"; - auto is_binary_schema = ext == reflection::SchemaExtension(); + const bool is_schema = ext == "fbs" || ext == "proto"; + const bool is_binary_schema = ext == reflection::SchemaExtension(); if (is_binary) { parser->builder_.Clear(); parser->builder_.PushFlatBuffer( diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 16397c0a3c2..31af814310a 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -158,6 +158,10 @@ CheckedError Parser::RecurseError() { " reached"); } +const std::string &Parser::GetPooledString(const std::string &s) const { + return *(string_cache_.insert(s).first); +} + class Parser::ParseDepthGuard { public: explicit ParseDepthGuard(Parser *parser_not_null) @@ -2281,13 +2285,18 @@ struct EnumValBuilder { bool user_value; }; -CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) { +CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest, + const char *filename) { std::vector enum_comment = doc_comment_; NEXT(); std::string enum_name = attribute_; EXPECT(kTokenIdentifier); EnumDef *enum_def; ECHECK(StartEnum(enum_name, is_union, &enum_def)); + if (filename != nullptr && !opts.project_root.empty()) { + enum_def->declaration_file = + &GetPooledString(RelativeToRootPath(opts.project_root, filename)); + } enum_def->doc_comment = enum_comment; if (!is_union && !opts.proto_mode) { // Give specialized error message, since this type spec used to @@ -2516,7 +2525,7 @@ static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) { return a_id < b_id; } -CheckedError Parser::ParseDecl() { +CheckedError Parser::ParseDecl(const char *filename) { std::vector dc = doc_comment_; bool fixed = IsIdent("struct"); if (!fixed && !IsIdent("table")) return Error("declaration expected"); @@ -2527,6 +2536,10 @@ CheckedError Parser::ParseDecl() { ECHECK(StartStruct(name, &struct_def)); struct_def->doc_comment = dc; struct_def->fixed = fixed; + if (filename && !opts.project_root.empty()) { + struct_def->declaration_file = + &GetPooledString(RelativeToRootPath(opts.project_root, filename)); + } ECHECK(ParseMetaData(&struct_def->attributes)); struct_def->sortbysize = struct_def->attributes.Lookup("original_order") == nullptr && !fixed; @@ -2606,7 +2619,7 @@ CheckedError Parser::ParseDecl() { return NoError(); } -CheckedError Parser::ParseService() { +CheckedError Parser::ParseService(const char *filename) { std::vector service_comment = doc_comment_; NEXT(); auto service_name = attribute_; @@ -2616,6 +2629,10 @@ CheckedError Parser::ParseService() { service_def.file = file_being_parsed_; service_def.doc_comment = service_comment; service_def.defined_namespace = current_namespace_; + if (filename != nullptr && !opts.project_root.empty()) { + service_def.declaration_file = + &GetPooledString(RelativeToRootPath(opts.project_root, filename)); + } if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name), &service_def)) return Error("service already exists: " + service_name); @@ -2731,7 +2748,7 @@ CheckedError Parser::ParseProtoDecl() { } else if (IsIdent("enum")) { // These are almost the same, just with different terminator: EnumDef *enum_def; - ECHECK(ParseEnum(false, &enum_def)); + ECHECK(ParseEnum(false, &enum_def, nullptr)); if (Is(';')) NEXT(); // Temp: remove any duplicates, as .fbs files can't handle them. enum_def->RemoveDuplicates(); @@ -3371,9 +3388,9 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths, } else if (token_ == '{') { return NoError(); } else if (IsIdent("enum")) { - ECHECK(ParseEnum(false, nullptr)); + ECHECK(ParseEnum(false, nullptr, source_filename)); } else if (IsIdent("union")) { - ECHECK(ParseEnum(true, nullptr)); + ECHECK(ParseEnum(true, nullptr, source_filename)); } else if (IsIdent("root_type")) { NEXT(); auto root_type = attribute_; @@ -3412,9 +3429,9 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths, EXPECT(';'); known_attributes_[name] = false; } else if (IsIdent("rpc_service")) { - ECHECK(ParseService()); + ECHECK(ParseService(source_filename)); } else { - ECHECK(ParseDecl()); + ECHECK(ParseDecl(source_filename)); } } return NoError(); @@ -3491,32 +3508,44 @@ void Parser::Serialize() { AssignIndices(structs_.vec); AssignIndices(enums_.vec); std::vector> object_offsets; + std::set files; for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) { auto offset = (*it)->Serialize(&builder_, *this); object_offsets.push_back(offset); (*it)->serialized_location = offset.o; + const std::string *file = (*it)->declaration_file; + if (file) files.insert(*file); } std::vector> enum_offsets; for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { auto offset = (*it)->Serialize(&builder_, *this); enum_offsets.push_back(offset); - (*it)->serialized_location = offset.o; + const std::string *file = (*it)->declaration_file; + if (file) files.insert(*file); } std::vector> service_offsets; for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) { auto offset = (*it)->Serialize(&builder_, *this); service_offsets.push_back(offset); - (*it)->serialized_location = offset.o; - } - auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets); - auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets); - auto fiid__ = builder_.CreateString(file_identifier_); - auto fext__ = builder_.CreateString(file_extension_); - auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets); - auto schema_offset = reflection::CreateSchema( + const std::string *file = (*it)->declaration_file; + if (file) files.insert(*file); + } + // TODO(caspern): CreateVectorOfSharedStrings + std::vector> file_offsets; + for (auto it = files.begin(); it != files.end(); it++) { + file_offsets.push_back(builder_.CreateSharedString(*it)); + } + + const auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets); + const auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets); + const auto fiid__ = builder_.CreateString(file_identifier_); + const auto fext__ = builder_.CreateString(file_extension_); + const auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets); + const auto files__ = builder_.CreateVector(file_offsets); + const auto schema_offset = reflection::CreateSchema( builder_, objs__, enum__, fiid__, fext__, (root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__, - static_cast(advanced_features_)); + static_cast(advanced_features_), files__); if (opts.size_prefixed) { builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier()); } else { @@ -3557,16 +3586,18 @@ Offset StructDef::Serialize(FlatBufferBuilder *builder, field_offsets.push_back((*it)->Serialize( builder, static_cast(it - fields.vec.begin()), parser)); } - auto qualified_name = defined_namespace->GetFullyQualifiedName(name); - auto name__ = builder->CreateString(qualified_name); - auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets); - auto attr__ = SerializeAttributes(builder, parser); - auto docs__ = parser.opts.binary_schema_comments - ? builder->CreateVectorOfStrings(doc_comment) - : 0; - return reflection::CreateObject(*builder, name__, flds__, fixed, - static_cast(minalign), - static_cast(bytesize), attr__, docs__); + const auto qualified_name = defined_namespace->GetFullyQualifiedName(name); + const auto name__ = builder->CreateString(qualified_name); + const auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets); + const auto attr__ = SerializeAttributes(builder, parser); + const auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + std::string decl_file_in_project = declaration_file ? *declaration_file : ""; + const auto file__ = builder->CreateSharedString(decl_file_in_project); + return reflection::CreateObject( + *builder, name__, flds__, fixed, static_cast(minalign), + static_cast(bytesize), attr__, docs__, file__); } bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) { @@ -3685,14 +3716,17 @@ Offset ServiceDef::Serialize(FlatBufferBuilder *builder, for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) { servicecall_offsets.push_back((*it)->Serialize(builder, parser)); } - auto qualified_name = defined_namespace->GetFullyQualifiedName(name); - auto name__ = builder->CreateString(qualified_name); - auto call__ = builder->CreateVector(servicecall_offsets); - auto attr__ = SerializeAttributes(builder, parser); - auto docs__ = parser.opts.binary_schema_comments - ? builder->CreateVectorOfStrings(doc_comment) - : 0; - return reflection::CreateService(*builder, name__, call__, attr__, docs__); + const auto qualified_name = defined_namespace->GetFullyQualifiedName(name); + const auto name__ = builder->CreateString(qualified_name); + const auto call__ = builder->CreateVector(servicecall_offsets); + const auto attr__ = SerializeAttributes(builder, parser); + const auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + std::string decl_file_in_project = declaration_file ? *declaration_file : ""; + const auto file__ = builder->CreateSharedString(decl_file_in_project); + return reflection::CreateService(*builder, name__, call__, attr__, docs__, + file__); } bool ServiceDef::Deserialize(Parser &parser, @@ -3719,16 +3753,18 @@ Offset EnumDef::Serialize(FlatBufferBuilder *builder, for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) { enumval_offsets.push_back((*it)->Serialize(builder, parser)); } - auto qualified_name = defined_namespace->GetFullyQualifiedName(name); - auto name__ = builder->CreateString(qualified_name); - auto vals__ = builder->CreateVector(enumval_offsets); - auto type__ = underlying_type.Serialize(builder); - auto attr__ = SerializeAttributes(builder, parser); - auto docs__ = parser.opts.binary_schema_comments - ? builder->CreateVectorOfStrings(doc_comment) - : 0; + const auto qualified_name = defined_namespace->GetFullyQualifiedName(name); + const auto name__ = builder->CreateString(qualified_name); + const auto vals__ = builder->CreateVector(enumval_offsets); + const auto type__ = underlying_type.Serialize(builder); + const auto attr__ = SerializeAttributes(builder, parser); + const auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + std::string decl_file_in_project = declaration_file ? *declaration_file : ""; + const auto file__ = builder->CreateSharedString(decl_file_in_project); return reflection::CreateEnum(*builder, name__, vals__, is_union, type__, - attr__, docs__); + attr__, docs__, file__); } bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) { diff --git a/src/util.cpp b/src/util.cpp index 3f61dd51481..464c128b2da 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -178,6 +178,9 @@ std::string PosixPath(const char *path) { std::replace(p.begin(), p.end(), '\\', '/'); return p; } +std::string PosixPath(const std::string &path) { + return PosixPath(path.c_str()); +} void EnsureDirExists(const std::string &filepath) { auto parent = StripFileName(filepath); @@ -217,6 +220,27 @@ std::string AbsolutePath(const std::string &filepath) { // clang-format on } +std::string RelativeToRootPath(const std::string &project, + const std::string &filepath) { + std::string absolute_project = PosixPath(AbsolutePath(project)); + if (absolute_project.back() != '/') absolute_project += "/"; + std::string absolute_filepath = PosixPath(AbsolutePath(filepath)); + if (absolute_filepath.size() < absolute_project.size() || + absolute_filepath.substr(0, absolute_project.size()) != + absolute_project) { + printf( + "The --bfbs-filenames directory must contain all files and included " + "files.\n"); + printf("project: %s\n", project.c_str()); + printf("filepath: %s\n", filepath.c_str()); + printf("absolute_project: %s\n", absolute_project.c_str()); + printf("absolute_filepath:%s\n", absolute_filepath.c_str()); + FLATBUFFERS_ASSERT(0); + } + const std::string relpath = absolute_filepath.substr(absolute_project.size()); + return "//" + relpath; +} + // Locale-independent code. #if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \ (FLATBUFFERS_LOCALE_INDEPENDENT > 0) diff --git a/tests/arrays_test.bfbs b/tests/arrays_test.bfbs index d6b6f73167ea871254c6f3df668a36e6478162a4..64dd12eee045847e87ea6f447b419a381bbcb185 100644 GIT binary patch delta 518 zcmYjOJxc>Y6r9~8s38y|5yTI&XdnqBaEOIsBc}!g8?lXuBK`nt%M_NLn<9mUrFM#y zKf}iVU?cXT=geLLS(tn8?VFvQcY9NOE*>}laW_6@KoxD|F^v*tnJ>U$nGrZ7c8G|m z6FmcVK^DL?TgleiNt0=gcocz%RA7!|$%4WdD5A@cNWH FHUEIpK(YV; delta 423 zcmY*UyGjE=6g_ulKoca{T_P+d5W$6D6iK0lslrMGJ4J15L=h{0!Ny9&W*I*qg@|^7 zUtyWQ5yXt=POxy{?Apg-yv|QeD1+{Lkz0VuE3|#t-g}=NeF?) z*h7QyF1l&O203+X5wVWnk#Ujz%hoQsg5J{>>f_*FjZPiv+ zm=Kf|w7#;P&YI4wnCMetF@2VkT%YLX_S znT$mb%}mm?qfY9yOlq-{W*oB)K`o_x8M1HR+csGKXdjz z&iirCz1zRMzx5f95Td%a`r8;pitq@Nu!>lbfO#5roEU{z4yXZC0P+CNSfOK0m`4C& z%Y^t&xe#xc3L&xHzPnP}_Df(Jln@=DxN8yOf?0?UtU|5St7eZhfgnt0oj5%|s=q5rbjAU7CPyzs=MT$-%Kp}Sjp~{jC z6{dWOlQtPkIdZnSKN`AdgS5-_v{OEAt^socotB#V^BEeJxoQ+cu8j&+sreM_=p(hlQ_4=<4+Nk>PQ#A}5Y(9foB7*+%D{5~I55ZQZ|dtZjuIoZRLf}{7tc6^M9iNe z#0;7hq1mQ}V-Uu+QF_JX*wz}3LJ$h>1p=HABtTb!K{&C;3Ku-J;0az|e(=?X-a=6M zJ7&n0Y=~|s#%@3ZfPI`n&CjEDCb<^yWM6YkeE?2Y@Cgj(dvjMQavbtVa+hyIa_97lEW zchyj&>t{hDly3IQO*G4#A*;!c`7zpQ&QPzMrCxJxmIVp^e|DcaOT%W{tT#p-^0v;^jaf;G`uc`;u6&^SOFrO{*Bd z+=Kc5ism%nak50sv;K{(7*}H*9?6C=nmL_o{cW_*l2Hp)`UeKl1FUZRy0#X9s5(&< zR_q760OBlq0NVlU0W$%NUz1OZBWK8N`bp$uwf`@4Byy|lqe|-!Wg-2}`i-iU(7;~Q zwJgVP5n(t@2WDRK4rf3r3O0 z2!|e;&;xOfGNY4=j*d}81JA(=rLYb%cU%M?flWwMEBT}Cm3#iG%Zz2CTc=itUFQP< zE0l+GA2H}+bh;_!;$1ovZBM;u>_+o$C%6Z|ZK2ae$%)Z$1DjEdSp|%RWQ@JC+}O41 z^pH~gcTPj>BiiZ>x=5WHbc^X}aKB*eT6FHRsbVX*6#^7)Yp+3P*117i#`v}ag^PmgMsM}dzSy&J zJ9SQKSGNY}>ZD?sP3dv7WiR>TO5~fgJ5EyvF3`caYBl;X-H2P}YWim&z{%!<% zD&-=%?YZ(XDogaqm9!+$r+O~ZKuQ6Rm(5Y*5m@!eTkMP z7RaM?D9NYpeM|#M^|FR4lQq>es4Lh(&n5fhJM^pM5;ZtT=acuy&9pW}Q$3&PcyOlp z)X*oa8m%-c^;@o{%M+DPLF9wVx6p>vpUO0vWYbi|zjX->^t8<hFbx&s8W7>Mr{o{$y|iXoN;&C`IK3~WH@Zfy zhVhh+^FXbmQLZ7sR8FHJO;fEyG*_#4_g$OFTON|pfgyTdTZ(>=>C{yH z6`J9k&IxlitD);O;B+X{uiCSq8TH#w^+RP%r1w0@)aNc#LqND8a)cc2TnUjGy2uQO9HBT*miq7-^=8z%Mn@(Z zTo#f71m81REx1nQo?5olqp7|BA$Mk$`sg|x!5*TKsV53K+P&Y>CURE!f>Mtg*;JV0e=8R{r zP=mMWe6~Xk-=I6$b#f6snWMRu-qZuaM_2Gg-O7D~zU&{1z8LUhHerB1)Cqs?60E7#)(joL%$c^Qd(?L7wIuFg&QHImk3bP<1^ zrViewt$B5|BVSB32<75D(<5|>_l1}gwBnSpmW9~l{>>3(i{N2|*lVU61=Hm@D)MQm%MceJ z;sLs!%}hm0e45-tUB21n=fm)R;7=KQG7s~hbdDXvUK0)bisf8#724INFKB9EojQD< z9e?Js!DbB_nIf{mV!XfjN^}a3ZX~40mH3%6CenkE8$64Di}QnzQ^HQ=(e1(?rysz( z4vTmWDFYWO-oxS~{jA9D_{hMTm^FySb5lIHPbZ6PRRsn*Hi$y+76o|le%0N#*r1JJ z^*;dAQD(7y+t!fXF66h9}OR8*2d4W=};3vT7uTs!av1Kqm2J6bk2a%PHK zm$lQT(t@fjVBsY5(PfsPZywA`N>;TsujyRgqO(j`l(7Iohe|bck3W^#tLh;KEb(|h z=yKQ@E~xRxp%Gy=+N0wPIu6BAN-ukWynG!_IE3aE&rv5v+* zoHR|W^mHQ9pjjeW}J>@qGKJ$X=c<(V#bMB2^!x)e8gB|)$MowpA}frf9CxE z?s>VG~Y~jJFW;K}8@R$O-C?7tj$xg4Tgd zp!O9VI&bd0nuYi)VnAD=v`7ij28DhwjztUcj#-EV$eQvX2hM9bLe%AoGEo;4;!%MR z_a+KqjT2%@J`@UtI00&dcUv*!_|1WFfc(pfcNX@3V7_ZW?s!qe8j+${~u?gfhjo-wmC-Ls7Z1YEr`;R zjt=?5x{Wvy%|B>kl;*lSB;lg6>uFVVy6mH#=zu&<2cy$f_Gi=^ovjK& z9AkUyXTveZ!fx)0j@4bwo#Jng#>Tl7ypeI{qv+pN@WTeCiFKLwf?fmFQBO>|JVX0p zv~f<@@@&j(TZ%|?W7BDu$+}?1<@Wp!kk1XlRA)TrZS$i#Gh228t52IksGWOebSARp}YJ8@pZ} zpjGBy$jNlm{Jm#Z!U>08+uQ^I=Tkt2XFyETm^s)<&2g*kJ3kMFsvu=8VKxIN{P)J+k3z01p)_2gd+M z>7>P7)@^X(b?&4RaRb(|!al}&yP;=cy*045pQE&R*VN+%JC4~cV3(caG9`>LA2jsL zx;fl5QhU6crdwl6Vs%rnUWchkSjL!^pVi}z(M^j>#rt$9-fdrMaHDl=aC^_uV9=#D zpQR`975+~Rsh*P-?iCt4|U($9*w)`Xg#hxdR&`G=p=v#Z9dcU8t z9rdz{Haawp)DchzE-{L{M0Xs8%6XYSNGhc|=ZoH5mq+`bGdRO8 zcc{$gQB`;7RJvcq4ANR(C9ln=VKY1L%T${ONo7=W`Z7?9yVU3NE7vW0J)?p#!Rx+7 zH!{jq>em$Xd(_(7ROzpjsFuHwXT`rPE&1N)K#NB-Z}%Ol$lT3o&Riy|=!aQLxL>lC zr8(~p8}V#nT%V?-^J^-fP%D2;Jrgu}k>10*l|GtK$bCIQQ`PsVuh2#L*)t?MEBjaS z8hw+UsjLsk6Y!{<2UHsH%PaJwz>n3g2Xr{-;c*FQ$!ovSlQWKIvZJA0-~4xC-=@@@ ze3?bFb2MA8p%Tr-S-uhn(W8JbN#cUWTgY@!_)vL^E=+Kv+YaSus`fth=G00nUC4FN z^jvdx>wk1diDnq^PPKByYGHX03h_l~#5UiV+aW)Mk)}R>$Rpt2X4qN6tL{$-OwhQzJ;cY8neZ2H}uAZ-IcK( zc1k|0_>kp18DFZ;EA#f_++?xBO(gP4cbxX+IlQ)^%ap`zB~s%)UC5i2TaN1&FcLxf zj@*E6slk)H(y&`IWngrc=leV_;Eo{?3MYQ#xn_AtJM(MRvBzBCscQ`kb9gBNXPNKm zor&+}so?03Y{F*-h^ynHj6}CAqUMRePf_p$Rw5^qsjGQ)7p7gDp>YLnZ;2s|;(CUq z=yMT+HJd0S-r@QHw>B`WVJT)@lsuus@viY#3{gBc`dUyu^%S@lBp8r7_Z4t!@IP{y zLvD4QpX_^QIKuhum`)!?r(z7w7rIj}4wWvPVop;O z6OAugJoA(xHF0!}pad)_GLE~3PBiN@fJ!kp;aOl_6df!I*gGP*f)a{@6L*6>y7ys$ zhYfii_^Q09p|P#`IU!!9o?`bijj#YS5vQ`Q)rf_Tyi~Cr*K-sqT`vAjo*lgKU75Qn TS=VD2A70`9G8X?)$;name()->c_str(), "MyGame.Example.Monster"); + TEST_EQ_STR(root_table->declaration_file()->c_str(), "//monster_test.fbs"); + TEST_EQ_STR( + schema.objects()->LookupByKey("TableA")->declaration_file()->c_str(), + "//include_test/include_test1.fbs"); + TEST_EQ_STR(schema.objects() + ->LookupByKey("MyGame.OtherNameSpace.Unused") + ->declaration_file() + ->c_str(), + "//include_test/sub/include_test2.fbs"); + TEST_EQ_STR(schema.enums() + ->LookupByKey("MyGame.OtherNameSpace.FromInclude") + ->declaration_file() + ->c_str(), + "//include_test/sub/include_test2.fbs"); + TEST_EQ(schema.fbs_files()->size(), 3); + TEST_EQ_STR(schema.fbs_files()->Get(0)->c_str(), + "//include_test/include_test1.fbs"); + TEST_EQ_STR(schema.fbs_files()->Get(1)->c_str(), + "//include_test/sub/include_test2.fbs"); + TEST_EQ_STR(schema.fbs_files()->Get(2)->c_str(), "//monster_test.fbs"); + + // Check Root table fields auto fields = root_table->fields(); auto hp_field_ptr = fields->LookupByKey("hp"); TEST_NOTNULL(hp_field_ptr); @@ -1290,6 +1313,7 @@ void ParseProtoTestWithIncludes() { flatbuffers::IDLOptions opts; opts.include_dependence_headers = true; opts.proto_mode = true; + opts.project_root = test_data_path; // Parse proto. flatbuffers::Parser parser(opts); @@ -1307,10 +1331,16 @@ void ParseProtoTestWithIncludes() { auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test"); // Ensure generated file is parsable. - flatbuffers::Parser parser2; - TEST_EQ( - parser2.Parse(import_fbs.c_str(), include_directories, "imported.fbs"), - true); + flatbuffers::IDLOptions opts2; + opts2.project_root = protopath; + flatbuffers::Parser parser2(opts2); + // Since `imported.fbs` isn't in the filesystem AbsolutePath can't figure it + // out by itself. We manually construct it so Parser works. + std::string imported_fbs = flatbuffers::PosixPath( + flatbuffers::AbsolutePath(protopath) + "/imported.fbs"); + TEST_EQ(parser2.Parse(import_fbs.c_str(), include_directories, + imported_fbs.c_str()), + true); TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true); TEST_EQ_STR(fbs.c_str(), goldenfile.c_str()); @@ -1324,7 +1354,8 @@ void ParseProtoTestWithIncludes() { // Ensure generated file is parsable. flatbuffers::Parser parser4; - TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, "imported.fbs"), true); + TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, imported_fbs.c_str()), + true); TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true); TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str()); }