[llvm-branch-commits] [clang-tools-extra] release/21.x: [clangd] Use resolved path when checking AngledHeaders/QuotedHeaders in IncludeInserter (#148371) (PR #152659)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Aug 8 01:08:19 PDT 2025
https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/152659
Backport ff0093cecd0c807d122cfb6b74634074c962ade9
Requested by: @HighCommander4
>From 000544f455cbdadbeb961c50c923d0bedf31888e Mon Sep 17 00:00:00 2001
From: Harald-R <rotuna.razvan at gmail.com>
Date: Fri, 8 Aug 2025 10:57:28 +0300
Subject: [PATCH] [clangd] Use resolved path when checking
AngledHeaders/QuotedHeaders in IncludeInserter (#148371)
This makes IncludeInserter's behavior consistent with include-cleaner,
as discussed in https://github.com/llvm/llvm-project/pull/140594.
(cherry picked from commit ff0093cecd0c807d122cfb6b74634074c962ade9)
---
clang-tools-extra/clangd/ConfigFragment.h | 4 ++--
clang-tools-extra/clangd/Headers.cpp | 7 ++++---
.../clangd/unittests/CodeCompleteTests.cpp | 4 ++--
clang-tools-extra/clangd/unittests/HeadersTests.cpp | 11 +++++++++++
.../include/clang-include-cleaner/Types.h | 2 +-
5 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h
index 9e00dbc9dc90a..c5488c2378a1e 100644
--- a/clang-tools-extra/clangd/ConfigFragment.h
+++ b/clang-tools-extra/clangd/ConfigFragment.h
@@ -315,7 +315,7 @@ struct Fragment {
/// AngledHeaders (i.e. a header matches a regex in both QuotedHeaders and
/// AngledHeaders), system headers use <> and non-system headers use "".
/// These can match any suffix of the header file in question.
- /// Matching is performed against the header text, not its absolute path
+ /// Matching is performed against the absolute path of the header
/// within the project.
std::vector<Located<std::string>> QuotedHeaders;
/// List of regexes for headers that should always be included with a
@@ -323,7 +323,7 @@ struct Fragment {
/// AngledHeaders (i.e. a header matches a regex in both QuotedHeaders and
/// AngledHeaders), system headers use <> and non-system headers use "".
/// These can match any suffix of the header file in question.
- /// Matching is performed against the header text, not its absolute path
+ /// Matching is performed against the absolute path of the header
/// within the project.
std::vector<Located<std::string>> AngledHeaders;
};
diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp
index 87fd261b906e6..b9d67cc6a1602 100644
--- a/clang-tools-extra/clangd/Headers.cpp
+++ b/clang-tools-extra/clangd/Headers.cpp
@@ -304,16 +304,17 @@ IncludeInserter::calculateIncludePath(const HeaderFile &InsertedHeader,
// FIXME: should we allow (some limited number of) "../header.h"?
if (llvm::sys::path::is_absolute(Suggested))
return std::nullopt;
+ auto HeaderPath = llvm::sys::path::convert_to_slash(InsertedHeader.File);
bool IsAngled = false;
for (auto &Filter : AngledHeaders) {
- if (Filter(Suggested)) {
+ if (Filter(HeaderPath)) {
IsAngled = true;
break;
}
}
bool IsQuoted = false;
for (auto &Filter : QuotedHeaders) {
- if (Filter(Suggested)) {
+ if (Filter(HeaderPath)) {
IsQuoted = true;
break;
}
@@ -324,7 +325,7 @@ IncludeInserter::calculateIncludePath(const HeaderFile &InsertedHeader,
if (IsAngled && IsQuoted) {
elog("Header '{0}' matches both quoted and angled regexes, default will "
"be used.",
- Suggested);
+ HeaderPath);
}
IsAngled = IsAngledByDefault;
}
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index b7c64c7a06745..3c107504e6253 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -938,7 +938,7 @@ TEST(CompletionTest, IncludeInsertionRespectsQuotedAngledConfig) {
{
Config C;
C.Style.AngledHeaders.push_back(
- [](auto header) { return header == "bar.h"; });
+ [](auto header) { return header.contains("bar.h"); });
WithContextValue WithCfg(Config::Key, std::move(C));
Results = completions(TU, Test.point(), {Sym});
EXPECT_THAT(Results.Completions,
@@ -947,7 +947,7 @@ TEST(CompletionTest, IncludeInsertionRespectsQuotedAngledConfig) {
{
Config C;
C.Style.QuotedHeaders.push_back(
- [](auto header) { return header == "bar.h"; });
+ [](auto header) { return header.contains("bar.h"); });
WithContextValue WithCfg(Config::Key, std::move(C));
Results = completions(TU, Test.point(), {Sym});
EXPECT_THAT(Results.Completions,
diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp
index 751383e3b4650..440582e14239a 100644
--- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp
@@ -344,6 +344,17 @@ TEST_F(HeadersTest, ShortenIncludesInSearchPathBracketed) {
EXPECT_EQ(calculate(BarHeader), "<sub/bar.h>");
}
+TEST_F(HeadersTest, ShortenIncludesInSearchPathBracketedFilterByFullPath) {
+ // The filter receives the full path of the header, so it is able to filter by
+ // the parent directory, even if it is part of the include search path
+ AngledHeaders.push_back([](auto Path) {
+ llvm::Regex Pattern("sub/.*");
+ return Pattern.match(Path);
+ });
+ std::string BarHeader = testPath("sub/bar.h");
+ EXPECT_EQ(calculate(BarHeader), "<bar.h>");
+}
+
TEST_F(HeadersTest, ShortenedIncludeNotInSearchPath) {
std::string BarHeader =
llvm::sys::path::convert_to_slash(testPath("sub-2/bar.h"));
diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
index 2888e25226755..057b92c147047 100644
--- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
@@ -136,7 +136,7 @@ struct Header {
}
StringRef verbatim() const { return std::get<Verbatim>(Storage); }
- /// For phiscal files, either absolute path or path relative to the execution
+ /// For physical files, either absolute path or path relative to the execution
/// root. Otherwise just the spelling without surrounding quotes/brackets.
llvm::StringRef resolvedPath() const;
More information about the llvm-branch-commits
mailing list