-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[idl_parser] Track included files by hash #6434
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3153,13 +3153,29 @@ 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) { | ||
auto stripped_source_fillename = StripPath(source_filename); | ||
auto hash = HashFnv1a<uint64_t>(stripped_source_fillename.c_str()); | ||
if (source && *source) hash ^= HashFnv1a<uint64_t>(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<std::string>(); | ||
} else { | ||
return NoError(); | ||
|
@@ -3210,12 +3226,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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same, why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we encounter an include directive, we need to answer two questions:
It's necessary to defer query 2 until we know the answer to query 1 is "no", becasue There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mmmspatz thank you for the explanation. |
||
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 +3250,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); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand how it works.
Why parse should continue processing if a schema has
include filename
directive but the file doesn't exist?Can you give an example that covers both paths of this
if (FileExists(source_filename))
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see other reply