diff options
author | John Bytheway <jbytheway@gmail.com> | 2019-04-12 21:52:18 +0100 |
---|---|---|
committer | Kim Gräsman <kim.grasman@gmail.com> | 2019-09-01 16:41:53 +0200 |
commit | 151371887144b9140b2541fd381562f8ae1d977e (patch) | |
tree | 6b7c457fa6cf58756cc93c3be3fc8f2cdb079048 | |
parent | fe8e57b44123e782b1f69fae8216eb8aab51e05f (diff) |
Fix combination of pragma export and "" includes
Fix some corner cases that can arise due to interaction between pragma
export and includes that are relative to the including header (i.e.
includes that can only be done using "", not <>).
Because headers are mostly handled as quoted includes for the purposes
of mapping, this can go wrong with relative includes because they are
not always relative to the same place, and at some places in the code we
don't even know what they're relative to.
Fix this by tracking full paths in parallel or instead of quoted
includes in certain places.
-rw-r--r-- | iwyu_include_picker.cc | 21 | ||||
-rw-r--r-- | iwyu_include_picker.h | 9 | ||||
-rw-r--r-- | iwyu_output.cc | 4 | ||||
-rw-r--r-- | iwyu_preprocessor.cc | 13 | ||||
-rw-r--r-- | tests/cxx/export_near.h | 20 | ||||
-rw-r--r-- | tests/cxx/relative_include_of_export.cc | 21 |
6 files changed, 69 insertions, 19 deletions
diff --git a/iwyu_include_picker.cc b/iwyu_include_picker.cc index edc3c9e..d950d9b 100644 --- a/iwyu_include_picker.cc +++ b/iwyu_include_picker.cc @@ -1037,8 +1037,9 @@ string FindFileInSearchPath(const vector<string>& search_path, } // anonymous namespace -MappedInclude::MappedInclude(const string& q) +MappedInclude::MappedInclude(const string& q, const string& p) : quoted_include(q) + , path(p) { CHECK_(IsQuotedInclude(quoted_include)) << "Must be quoted include, was: " << quoted_include; @@ -1094,7 +1095,7 @@ void IncludePicker::AddDirectInclude(const string& includer_filepath, // to our map, but harmless. const string quoted_includer = ConvertToQuotedInclude(includer_filepath); const string quoted_includee = ConvertToQuotedInclude(includee_filepath); - MappedInclude mapped_includer(quoted_includer); + MappedInclude mapped_includer(quoted_includer, includer_filepath); quoted_includes_to_quoted_includers_[quoted_includee].insert(quoted_includer); const pair<string, string> key(includer_filepath, includee_filepath); @@ -1339,7 +1340,7 @@ vector<MappedInclude> IncludePicker::GetCandidateHeadersForFilepath( GetPublicValues(filepath_include_map_, quoted_header); if (retval.empty()) { // the filepath isn't in include_map, so just quote and return it. - retval.push_back(MappedInclude(quoted_header)); + retval.push_back(MappedInclude(quoted_header, filepath)); } return retval; } @@ -1361,7 +1362,8 @@ vector<string> IncludePicker::GetCandidateHeadersForFilepathIncludedFrom( FindInMap(&friend_to_headers_map_, quoted_includer); if (headers_with_includer_as_friend != nullptr && ContainsKey(*headers_with_includer_as_friend, included_filepath)) { - mapped_includes.push_back(MappedInclude(quoted_includee)); + mapped_includes.push_back( + MappedInclude(quoted_includee, including_filepath)); } else { mapped_includes = GetCandidateHeadersForFilepath(included_filepath, including_filepath); @@ -1382,15 +1384,14 @@ vector<string> IncludePicker::GetCandidateHeadersForFilepathIncludedFrom( // ConvertToQuotedInclude because it avoids trouble when the same // file is accessible via different include search-paths, or is // accessed via a symlink. - const string& quoted_include_as_written = - MaybeGetIncludeNameAsWritten(including_filepath, included_filepath); vector<string> retval; for (MappedInclude& mapped_include : mapped_includes) { - if (!quoted_include_as_written.empty() && - mapped_include.quoted_include == quoted_includee) { - retval.push_back(quoted_include_as_written); - } else { + const string& quoted_include_as_written = + MaybeGetIncludeNameAsWritten(including_filepath, mapped_include.path); + if (quoted_include_as_written.empty()) { retval.push_back(mapped_include.quoted_include); + } else { + retval.push_back(quoted_include_as_written); } } return retval; diff --git a/iwyu_include_picker.h b/iwyu_include_picker.h index 872d8d2..49f02ab 100644 --- a/iwyu_include_picker.h +++ b/iwyu_include_picker.h @@ -67,10 +67,15 @@ struct IncludeMapEntry; enum IncludeVisibility { kUnusedVisibility, kPublic, kPrivate }; +// When a symbol or file is mapped to an include, that include is represented +// by this struct. It always has a quoted_include and may also have a path +// (depending on its origin). struct MappedInclude { - explicit MappedInclude(const string& quoted_include); + explicit MappedInclude(const string& quoted_include, + const string& path = {}); string quoted_include; + string path; }; class IncludePicker { @@ -140,6 +145,8 @@ class IncludePicker { // not when #included from "qux/quux.h". In the common case there's // no special-casing, and this falls back on // GetCandidateHeadersForFilepath(). + // Furthermore, knowing the including file allows use to convert each + // MappedInclude in the result to a simple string (quoted include). vector<string> GetCandidateHeadersForFilepathIncludedFrom( const string& included_filepath, const string& including_filepath) const; diff --git a/iwyu_output.cc b/iwyu_output.cc index 3dd54ad..3337df3 100644 --- a/iwyu_output.cc +++ b/iwyu_output.cc @@ -2083,8 +2083,8 @@ void IwyuFileInfo::HandlePreprocessingDone() { ERRSYM(file_) << "Mark " << quoted_file_ << " as public header for " << private_include << " because used macro is defined by includer.\n"; - MutableGlobalIncludePicker()->AddMapping(private_include, - MappedInclude(quoted_file_)); + MutableGlobalIncludePicker()->AddMapping( + private_include, MappedInclude(quoted_file_, GetFilePath(file_))); MutableGlobalIncludePicker()->MarkIncludeAsPrivate(private_include); } } diff --git a/iwyu_preprocessor.cc b/iwyu_preprocessor.cc index e132abc..a70e420 100644 --- a/iwyu_preprocessor.cc +++ b/iwyu_preprocessor.cc @@ -411,13 +411,14 @@ void IwyuPreprocessorInfo::MaybeProtectInclude( LineHasText(includer_loc, "/* IWYU pragma: export") || HasOpenBeginExports(includer)) { protect_reason = "pragma_export"; - const string quoted_includer = - ConvertToQuotedInclude(GetFilePath(includer)); - MutableGlobalIncludePicker()->AddMapping(include_name_as_written, - MappedInclude(quoted_includer)); + const string includer_path = GetFilePath(includer); + const string quoted_includer = ConvertToQuotedInclude(includer_path); + MutableGlobalIncludePicker()->AddMapping( + include_name_as_written, + MappedInclude(quoted_includer, includer_path)); ERRSYM(includer) << "Adding pragma-export mapping: " - << include_name_as_written << " -> " << quoted_includer - << "\n"; + << include_name_as_written << " -> " + << quoted_includer << "\n"; // We also always keep #includes of .c files: iwyu doesn't touch those. // TODO(csilvers): instead of IsHeaderFile, check if the file has diff --git a/tests/cxx/export_near.h b/tests/cxx/export_near.h new file mode 100644 index 0000000..15fef16 --- /dev/null +++ b/tests/cxx/export_near.h @@ -0,0 +1,20 @@ +//===--- export_near.h - test input file for iwyu -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This file is meant to be a generic exporting header. Similarly to +// direct_near.h, it includes indirect.h. However, unlike that file, this one +// exports indirect.h, and therefore is a valid file to include to access +// IndirectClass. + +#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPORT_NEAR_H_ +#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPORT_NEAR_H_ + +#include "indirect.h" // IWYU pragma: export + +#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPORT_NEAR_H_ diff --git a/tests/cxx/relative_include_of_export.cc b/tests/cxx/relative_include_of_export.cc new file mode 100644 index 0000000..4fd76cb --- /dev/null +++ b/tests/cxx/relative_include_of_export.cc @@ -0,0 +1,21 @@ +//===--- relative_include_of_export-d1.h - test input file for iwyu -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// The purpose of this test is to ensure that the following relative include +// (i.e. using "" to include something at a location relative to this file) +// remains a relative include rather than being replaced by a different path. +#include "export_near.h" + +IndirectClass x; + +/**** IWYU_SUMMARY + +(tests/cxx/relative_include_of_export.cc has correct #includes/fwd-decls) + +***** IWYU_SUMMARY */ |