summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlamefire <git@grundis.de>2016-05-05 12:08:32 +0200
committerKim Grasman <kim.grasman@gmail.com>2016-06-08 08:23:26 +0200
commit23119ba66a3186aef334a80f57e4d8754a956e41 (patch)
tree90f96b6acc63ed969c6a705ccb6f2a8df61c1043
parentd9f88454ca3877bf89549949ac6bfde93c4853cb (diff)
Use absolute paths to build include names
This has been a long-standing issue with IWYU (see issues #5, #271 and probably others) where ConvertToQuotedInclude generates absolute paths if IWYU is invoked with the current directory different from the source file path. This patch moves most path building to use absolute paths and path of the includer (rather than the cwd) to produce better results.
-rw-r--r--iwyu_globals.cc4
-rw-r--r--iwyu_include_picker.cc17
-rw-r--r--iwyu_include_picker.h3
-rw-r--r--iwyu_path_util.cc36
-rw-r--r--iwyu_path_util.h12
-rwxr-xr-xrun_iwyu_tests.py3
-rw-r--r--tests/cxx/direct_near.h18
-rw-r--r--tests/cxx/header_in_subfolder.cc30
-rw-r--r--tests/cxx/header_in_subfolder_nopath.cc30
-rw-r--r--tests/cxx/new_header_path_local.cc31
-rw-r--r--tests/cxx/new_header_path_provided.cc31
-rw-r--r--tests/cxx/subfolder/direct_subfolder.h17
-rw-r--r--tests/cxx/subfolder/indirect_subfolder.h16
13 files changed, 229 insertions, 19 deletions
diff --git a/iwyu_globals.cc b/iwyu_globals.cc
index 60ee731..07b4fdb 100644
--- a/iwyu_globals.cc
+++ b/iwyu_globals.cc
@@ -299,7 +299,7 @@ static vector<HeaderSearchPath> ComputeHeaderSearchPaths(
for (auto it = header_search->system_dir_begin();
it != header_search->system_dir_end(); ++it) {
if (const DirectoryEntry* entry = it->getDir()) {
- const string path = NormalizeDirPath(entry->getName());
+ const string path = NormalizeDirPath(MakeAbsolutePath(entry->getName()));
search_path_map[path] = HeaderSearchPath::kSystemPath;
}
}
@@ -309,7 +309,7 @@ static vector<HeaderSearchPath> ComputeHeaderSearchPaths(
// search_dir_begin()/end() includes both system and user paths.
// If it's a system path, it's already in the map, so everything
// new is a user path. The insert only 'takes' for new entries.
- const string path = NormalizeDirPath(entry->getName());
+ const string path = NormalizeDirPath(MakeAbsolutePath(entry->getName()));
search_path_map.insert(make_pair(path, HeaderSearchPath::kUserPath));
}
}
diff --git a/iwyu_include_picker.cc b/iwyu_include_picker.cc
index 4444f11..b8ab9fe 100644
--- a/iwyu_include_picker.cc
+++ b/iwyu_include_picker.cc
@@ -1286,9 +1286,10 @@ vector<string> IncludePicker::GetCandidateHeadersForSymbol(
}
vector<string> IncludePicker::GetCandidateHeadersForFilepath(
- const string& filepath) const {
+ const string& filepath, const string& including_filepath) const {
CHECK_(has_called_finalize_added_include_lines_ && "Must finalize includes");
- const string quoted_header = ConvertToQuotedInclude(filepath);
+ const string quoted_header = ConvertToQuotedInclude(
+ filepath, MakeAbsolutePath(GetParentPath(including_filepath)));
vector<string> retval = GetPublicValues(filepath_include_map_, quoted_header);
if (retval.empty()) {
// the filepath isn't in include_map, so just quote and return it.
@@ -1303,15 +1304,21 @@ vector<string> IncludePicker::GetCandidateHeadersForFilepath(
vector<string> IncludePicker::GetCandidateHeadersForFilepathIncludedFrom(
const string& included_filepath, const string& including_filepath) const {
vector<string> retval;
- const string quoted_includer = ConvertToQuotedInclude(including_filepath);
- const string quoted_includee = ConvertToQuotedInclude(included_filepath);
+ // We pass the own files path to ConvertToQuotedInclude so the quoted include
+ // for the case that there is no matching `-I` option is just the filename
+ // (e.g. "foo.cpp") instead of the absolute file path.
+ const string quoted_includer = ConvertToQuotedInclude(
+ including_filepath, MakeAbsolutePath(GetParentPath(including_filepath)));
+ const string quoted_includee = ConvertToQuotedInclude(
+ included_filepath, MakeAbsolutePath(GetParentPath(including_filepath)));
const set<string>* headers_with_includer_as_friend =
FindInMap(&friend_to_headers_map_, quoted_includer);
if (headers_with_includer_as_friend != nullptr &&
ContainsKey(*headers_with_includer_as_friend, included_filepath)) {
retval.push_back(quoted_includee);
} else {
- retval = GetCandidateHeadersForFilepath(included_filepath);
+ retval =
+ GetCandidateHeadersForFilepath(included_filepath, including_filepath);
if (retval.size() == 1) {
const string& quoted_header = retval[0];
if (GetVisibility(quoted_header) == kPrivate) {
diff --git a/iwyu_include_picker.h b/iwyu_include_picker.h
index 387e044..d7caf54 100644
--- a/iwyu_include_picker.h
+++ b/iwyu_include_picker.h
@@ -121,7 +121,8 @@ class IncludePicker {
// (which is why we return a vector, not a set): all else being
// equal, the first element of the vector is the "best" (or most
// standard) header for the input header.
- vector<string> GetCandidateHeadersForFilepath(const string& filepath) const;
+ vector<string> GetCandidateHeadersForFilepath(
+ const string& filepath, const string& including_filepath = "") const;
// This allows for special-casing of GetCandidateHeadersForFilepath
// -- it's the same, but you give it the filepath that's doing the
diff --git a/iwyu_path_util.cc b/iwyu_path_util.cc
index 1b1d3ef..69ba9b7 100644
--- a/iwyu_path_util.cc
+++ b/iwyu_path_util.cc
@@ -82,9 +82,12 @@ string Basename(const string& path) {
}
string GetCanonicalName(string file_path) {
- // Get rid of any <> and "" in case file_path is really an #include line.
- StripLeft(&file_path, "\"") || StripLeft(&file_path, "<");
- StripRight(&file_path, "\"") || StripRight(&file_path, ">");
+ // For this special 'path' we just return it.
+ // Note that we leave the 'quotes' to make it different from regular paths.
+ if (file_path == "<built-in>")
+ return file_path;
+
+ CHECK_(!IsQuotedInclude(file_path));
file_path = NormalizeFilePath(file_path);
@@ -163,11 +166,24 @@ string GetParentPath(const string& path) {
return parent.str();
}
+bool StripPathPrefix(string* path, const string& prefix_path) {
+ // Only makes sense if both are absolute or both are relative (to same dir).
+ CHECK_(IsAbsolutePath(*path) == IsAbsolutePath(prefix_path));
+ return StripLeft(path, prefix_path);
+}
+
// Converts a file-path, such as /usr/include/stdio.h, to a
// quoted include, such as <stdio.h>.
-string ConvertToQuotedInclude(const string& filepath) {
- // First, get rid of leading ./'s and the like.
- string path = NormalizeFilePath(filepath);
+string ConvertToQuotedInclude(const string& filepath,
+ const string& includer_path) {
+ // includer_path must be given as an absolute path.
+ CHECK_(includer_path.empty() || IsAbsolutePath(includer_path));
+
+ if (filepath == "<built-in>")
+ return filepath;
+
+ // Get path into same format as header search paths: Absolute and normalized.
+ string path = NormalizeFilePath(MakeAbsolutePath(filepath));
// Case 1: Uses an explicit entry on the search path (-I) list.
const vector<HeaderSearchPath>& search_paths = HeaderSearchPaths();
@@ -177,7 +193,8 @@ string ConvertToQuotedInclude(const string& filepath) {
for (Each<HeaderSearchPath> it(&search_paths); !it.AtEnd(); ++it) {
// All header search paths have a trailing "/", so we'll get a perfect
// quoted include by just stripping the prefix.
- if (StripLeft(&path, it->path)) {
+
+ if (StripPathPrefix(&path, it->path)) {
if (it->path_type == HeaderSearchPath::kSystemPath)
return "<" + path + ">";
else
@@ -185,7 +202,10 @@ string ConvertToQuotedInclude(const string& filepath) {
}
}
- // Case 2: Uses the implicit "-I." entry on the search path. Always local.
+ // Case 2:
+ // Uses the implicit "-I <basename current file>" entry on the search path.
+ if (!includer_path.empty())
+ StripPathPrefix(&path, NormalizeDirPath(includer_path));
return "\"" + path + "\"";
}
diff --git a/iwyu_path_util.h b/iwyu_path_util.h
index 33ee9fb..c75667a 100644
--- a/iwyu_path_util.h
+++ b/iwyu_path_util.h
@@ -43,9 +43,9 @@ bool IsHeaderFile(string path);
// else return the input path.
string Basename(const string& path);
-// Removes enclosing <> or "", then strips uninteresting suffixes from
+// Normalizes the file path, then strips uninteresting suffixes from
// the file name. Replaces "/internal/" with "/public/" and
-// "/include/" with "/src". Normalize the file path.
+// "/include/" with "/src".
string GetCanonicalName(string file_path);
// Replaces "\" by "/" (Microsoft platform paths) and collapses all dot
@@ -66,6 +66,11 @@ string MakeAbsolutePath(const string& base_path, const string& relative_path);
// Get the parent of path.
string GetParentPath(const string& path);
+// Try to strip the prefix_path from the front of path.
+// The path assumed to be normalized but either absolute or relative.
+// Return true if path was stripped.
+bool StripPathPrefix(string* path, const string& prefix_path);
+
// Below, we talk 'quoted' includes. A quoted include is something
// that would be written on an #include line, complete with the <> or
// "". In the line '#include <time.h>', "<time.h>" is the quoted
@@ -73,7 +78,8 @@ string GetParentPath(const string& path);
// Converts a file-path, such as /usr/include/stdio.h, to a
// quoted include, such as <stdio.h>.
-string ConvertToQuotedInclude(const string& filepath);
+string ConvertToQuotedInclude(const string& filepath,
+ const string& includer_path = "");
// Returns true if the string is a quoted include.
bool IsQuotedInclude(const string& s);
diff --git a/run_iwyu_tests.py b/run_iwyu_tests.py
index 8ad75ee..38533d5 100755
--- a/run_iwyu_tests.py
+++ b/run_iwyu_tests.py
@@ -113,6 +113,7 @@ class OneIwyuTest(unittest.TestCase):
'badinc.cc': ['.'],
'casts.cc': ['.'],
'catch.cc': ['.'],
+ 'check_also.cc': ['.'],
'clmode.cc': ['.'],
'comment_pragmas.cc': ['.'],
'computed_include.cc': ['.'],
@@ -128,6 +129,7 @@ class OneIwyuTest(unittest.TestCase):
'fwd_decl_class_template.cc': ['.'],
'fwd_decl_static_member.cc': ['.'],
'fwd_decl_with_instantiation.cc': ['.'],
+ 'header_in_subfolder.cc': ['.'],
'implicit_ctor.cc': ['.'],
'include_with_using.cc': ['.'],
'iwyu_stricter_than_cpp.cc': ['.'],
@@ -136,6 +138,7 @@ class OneIwyuTest(unittest.TestCase):
'macro_location.cc': ['.'],
'member_expr.cc': ['.'],
'multiple_include_paths.cc': ['.'],
+ 'new_header_path_provided.cc': ['.'],
'no_comments.cc': ['.'],
'no_h_includes_cc.cc': ['.'],
'non_transitive_include.cc': ['.'],
diff --git a/tests/cxx/direct_near.h b/tests/cxx/direct_near.h
new file mode 100644
index 0000000..8e8dd3e
--- /dev/null
+++ b/tests/cxx/direct_near.h
@@ -0,0 +1,18 @@
+//===--- direct_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 the same as tests/direct.h, only intended to be used without
+// provided header search path -I .
+
+#ifndef INCLUDE_WHAT_YOU_USE_TESTS_DIRECT_NEAR_H_
+#define INCLUDE_WHAT_YOU_USE_TESTS_DIRECT_NEAR_H_
+
+#include "indirect.h"
+
+#endif // INCLUDE_WHAT_YOU_USE_TESTS_DIRECT_NEAR_H_
diff --git a/tests/cxx/header_in_subfolder.cc b/tests/cxx/header_in_subfolder.cc
new file mode 100644
index 0000000..0734ca4
--- /dev/null
+++ b/tests/cxx/header_in_subfolder.cc
@@ -0,0 +1,30 @@
+//===--- header_in_subfolder.cc - 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.
+//
+//===----------------------------------------------------------------------===//
+
+// Test that subfolders are correctly recognized
+
+#include "subfolder/direct_subfolder.h"
+
+void foo() {
+ // IWYU: IndirectSubfolderClass is...*indirect_subfolder.h
+ IndirectSubfolderClass ic;
+}
+
+/**** IWYU_SUMMARY
+
+tests/cxx/header_in_subfolder.cc should add these lines:
+#include "tests/cxx/subfolder/indirect_subfolder.h"
+
+tests/cxx/header_in_subfolder.cc should remove these lines:
+- #include "subfolder/direct_subfolder.h" // lines XX-XX
+
+The full include-list for tests/cxx/header_in_subfolder.cc:
+#include "tests/cxx/subfolder/indirect_subfolder.h" // for IndirectSubfolderClass
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/header_in_subfolder_nopath.cc b/tests/cxx/header_in_subfolder_nopath.cc
new file mode 100644
index 0000000..43525be
--- /dev/null
+++ b/tests/cxx/header_in_subfolder_nopath.cc
@@ -0,0 +1,30 @@
+//===--- header_in_subfolder_nopath.cc - 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.
+//
+//===----------------------------------------------------------------------===//
+
+// Test that subfolders are correctly recognized. Use without "-I ."
+
+#include "subfolder/direct_subfolder.h"
+
+void foo() {
+ // IWYU: IndirectSubfolderClass is...*indirect_subfolder.h
+ IndirectSubfolderClass ic;
+}
+
+/**** IWYU_SUMMARY
+
+tests/cxx/header_in_subfolder_nopath.cc should add these lines:
+#include "subfolder/indirect_subfolder.h"
+
+tests/cxx/header_in_subfolder_nopath.cc should remove these lines:
+- #include "subfolder/direct_subfolder.h" // lines XX-XX
+
+The full include-list for tests/cxx/header_in_subfolder_nopath.cc:
+#include "subfolder/indirect_subfolder.h" // for IndirectSubfolderClass
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/new_header_path_local.cc b/tests/cxx/new_header_path_local.cc
new file mode 100644
index 0000000..9e64463
--- /dev/null
+++ b/tests/cxx/new_header_path_local.cc
@@ -0,0 +1,31 @@
+//===--- new_header_path_local.cc - 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.
+//
+//===----------------------------------------------------------------------===//
+
+// Tests that if include search path is not provided, new includes are added
+// without path (just file name). Compare with new_header_path_provided.cc.
+
+#include "direct_near.h"
+
+void foo() {
+ // IWYU: IndirectClass is...*indirect.h
+ IndirectClass ic;
+}
+
+/**** IWYU_SUMMARY
+
+tests/cxx/new_header_path_local.cc should add these lines:
+#include "indirect.h"
+
+tests/cxx/new_header_path_local.cc should remove these lines:
+- #include "direct_near.h" // lines XX-XX
+
+The full include-list for tests/cxx/new_header_path_local.cc:
+#include "indirect.h" // for IndirectClass
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/new_header_path_provided.cc b/tests/cxx/new_header_path_provided.cc
new file mode 100644
index 0000000..4b5bd4d
--- /dev/null
+++ b/tests/cxx/new_header_path_provided.cc
@@ -0,0 +1,31 @@
+//===--- new_header_path_provided.cc - 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.
+//
+//===----------------------------------------------------------------------===//
+
+// Tests that if include search path is provided, new includes are added with
+// corresponding relative path. Compare with new_header_path_local.cc.
+
+#include "tests/cxx/direct.h"
+
+void foo() {
+ // IWYU: IndirectClass is...*indirect.h
+ IndirectClass ic;
+}
+
+/**** IWYU_SUMMARY
+
+tests/cxx/new_header_path_provided.cc should add these lines:
+#include "tests/cxx/indirect.h"
+
+tests/cxx/new_header_path_provided.cc should remove these lines:
+- #include "tests/cxx/direct.h" // lines XX-XX
+
+The full include-list for tests/cxx/new_header_path_provided.cc:
+#include "tests/cxx/indirect.h" // for IndirectClass
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/subfolder/direct_subfolder.h b/tests/cxx/subfolder/direct_subfolder.h
new file mode 100644
index 0000000..9c1d10a
--- /dev/null
+++ b/tests/cxx/subfolder/direct_subfolder.h
@@ -0,0 +1,17 @@
+//===--- direct_subfolder.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 includes only another file in the subfolder
+
+#ifndef INCLUDE_WHAT_YOU_USE_TESTS_DIRECT_SUBFOLDER_H_
+#define INCLUDE_WHAT_YOU_USE_TESTS_DIRECT_SUBFOLDER_H_
+
+#include "indirect_subfolder.h"
+
+#endif // INCLUDE_WHAT_YOU_USE_TESTS_DIRECT_SUBFOLDER_H_
diff --git a/tests/cxx/subfolder/indirect_subfolder.h b/tests/cxx/subfolder/indirect_subfolder.h
new file mode 100644
index 0000000..5bf5cd6
--- /dev/null
+++ b/tests/cxx/subfolder/indirect_subfolder.h
@@ -0,0 +1,16 @@
+//===--- indirect_subfolder.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.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef INCLUDE_WHAT_YOU_USE_TESTS_INDIRECT_SUBFOLDER_H_
+#define INCLUDE_WHAT_YOU_USE_TESTS_INDIRECT_SUBFOLDER_H_
+
+class IndirectSubfolderClass {};
+
+#endif // INCLUDE_WHAT_YOU_USE_TESTS_INDIRECT_SUBFOLDER_H_