diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 1f549f93554..fa86b494eb2 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -993,7 +993,7 @@ class Parser : public ParserState { std::string file_identifier_; std::string file_extension_; - std::map included_files_; + std::map included_files_; std::map> files_included_per_file_; std::vector native_included_files_; diff --git a/src/idl_gen_ts.cpp b/src/idl_gen_ts.cpp index 915b05e41fd..50279ac3bc4 100644 --- a/src/idl_gen_ts.cpp +++ b/src/idl_gen_ts.cpp @@ -308,28 +308,6 @@ class TsGenerator : public BaseGenerator { return "NS" + NumToString(HashFnv1a(file.c_str())); } - std::string GenPrefixedImport(const std::string &full_file_name, - const std::string &base_name) { - // Either keep the include path as it was - // or use only the base_name + kGeneratedFileNamePostfix - std::string path; - if (parser_.opts.keep_include_path) { - auto it = parser_.included_files_.find(full_file_name); - FLATBUFFERS_ASSERT(it != parser_.included_files_.end()); - path = flatbuffers::StripExtension(it->second) + - parser_.opts.filename_suffix; - } else { - path = base_name + parser_.opts.filename_suffix; - } - - // Add the include prefix and make the path always relative - path = flatbuffers::ConCatPathFileName(parser_.opts.include_prefix, path); - path = std::string(".") + kPathSeparator + path; - - return "import * as " + GenFileNamespacePrefix(full_file_name) + - " from \"" + path + "\";\n"; - } - // Adds a source-dependent prefix, for of import * statements. std::string GenPrefixedTypeName(const std::string &typeName, const std::string &file) { diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 7cdddaffd7e..89828a46513 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -3153,13 +3153,32 @@ CheckedError Parser::ParseRoot(const char *source, const char **include_paths, return NoError(); } +// Generate a unique hash for a file based on its name and contents (if any). +static uint64_t HashFile(const char *source_filename, const char *source) { + uint64_t hash = 0; + + if (source_filename) + hash = HashFnv1a(StripPath(source_filename).c_str()); + + if (source && *source) hash ^= HashFnv1a(source); + + return hash; +} + CheckedError Parser::DoParse(const char *source, const char **include_paths, const char *source_filename, const char *include_filename) { + uint64_t source_hash = 0; if (source_filename) { - if (included_files_.find(source_filename) == included_files_.end()) { - included_files_[source_filename] = - include_filename ? include_filename : ""; + // If the file is in-memory, don't include its contents in the hash as we + // won't be able to load them later. + if (FileExists(source_filename)) + source_hash = HashFile(source_filename, source); + else + source_hash = HashFile(source_filename, nullptr); + + if (included_files_.find(source_hash) == included_files_.end()) { + included_files_[source_hash] = include_filename ? include_filename : ""; files_included_per_file_[source_filename] = std::set(); } else { return NoError(); @@ -3210,12 +3229,14 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths, return Error("unable to locate include file: " + name); if (source_filename) files_included_per_file_[source_filename].insert(filepath); - if (included_files_.find(filepath) == included_files_.end()) { + + std::string contents; + bool file_loaded = LoadFile(filepath.c_str(), true, &contents); + if (included_files_.find(HashFile(filepath.c_str(), contents.c_str())) == + included_files_.end()) { // We found an include file that we have not parsed yet. - // Load it and parse it. - std::string contents; - if (!LoadFile(filepath.c_str(), true, &contents)) - return Error("unable to load include file: " + name); + // Parse it. + if (!file_loaded) return Error("unable to load include file: " + name); ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(), name.c_str())); // We generally do not want to output code for any included files: @@ -3232,7 +3253,7 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths, // entered into included_files_. // This is recursive, but only go as deep as the number of include // statements. - if (source_filename) { included_files_.erase(source_filename); } + included_files_.erase(source_hash); return DoParse(source, include_paths, source_filename, include_filename); } diff --git a/tests/monster_test_generated.rs b/tests/monster_test_generated.rs index a514c7a57c4..ddda9a9423a 100644 --- a/tests/monster_test_generated.rs +++ b/tests/monster_test_generated.rs @@ -2,8 +2,8 @@ -use crate::include_test1_generated::*; use crate::include_test2_generated::*; +use crate::include_test1_generated::*; use std::mem; use std::cmp::Ordering; @@ -13,8 +13,8 @@ use self::flatbuffers::EndianScalar; #[allow(unused_imports, dead_code)] pub mod my_game { - use crate::include_test1_generated::*; use crate::include_test2_generated::*; + use crate::include_test1_generated::*; use std::mem; use std::cmp::Ordering; @@ -121,8 +121,8 @@ impl InParentNamespaceT { #[allow(unused_imports, dead_code)] pub mod example_2 { - use crate::include_test1_generated::*; use crate::include_test2_generated::*; + use crate::include_test1_generated::*; use std::mem; use std::cmp::Ordering; @@ -231,8 +231,8 @@ impl MonsterT { #[allow(unused_imports, dead_code)] pub mod example { - use crate::include_test1_generated::*; use crate::include_test2_generated::*; + use crate::include_test1_generated::*; use std::mem; use std::cmp::Ordering;