summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorSR_team2024-02-21 22:48:46 +0200
committerSR_team2024-02-21 22:48:46 +0200
commitc8db5ebbe7ed7d341d508758e6f0514e56f5776a (patch)
tree301ad05a2349f7c20217229fdca4808026e6426a
parentf55e51fd6c64a5acf1ae5ee221605084bf7caac3 (diff)
downloadaur-c8db5ebbe7ed7d341d508758e6f0514e56f5776a.tar.gz
Add patch with PR 67749
-rw-r--r--.SRCINFO6
-rw-r--r--PKGBUILD21
-rw-r--r--config-include-style.patch538
3 files changed, 559 insertions, 6 deletions
diff --git a/.SRCINFO b/.SRCINFO
index dc52f58d1894..1bfcaae15503 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,6 +1,6 @@
pkgbase = clangd-opt
pkgdesc = Trunk version of standalone clangd binary, with custom patches (look AUR page or PKGBUILD comments)
- pkgver = 19.r2558.g3d81d48398f0
+ pkgver = 19.r3010.gd4fd20258f63
pkgrel = 1
url = https://llvm.org/
arch = x86_64
@@ -37,12 +37,13 @@ pkgbase = clangd-opt
source = resolve-incomplete-header-includes.patch
source = lsp-remove-files-from-cdb.patch
source = hover-record-paddings.patch
+ source = config-include-style.patch
sha256sums = SKIP
sha256sums = 75b331257caa768c16687fd668ec2b8be62feb283892d601476c3e039f298a54
sha256sums = 614dd012009facb502a7d44e07fc819aa95383c8917537c57968f76ba7881a94
sha256sums = b42d27929fcec3825711c13baf0c5a4ea0da33b8ff5e6f60c3c61d2f1f9525af
sha256sums = 9e5dd128cedc8f37724d9c39c0f8f7efc826b0fd367f3a03c2564ff9f514ced7
- sha256sums = faf5c8b2a5a345be59c33f5de591f39dd35b1a2b97ca067e21023e311610bc0d
+ sha256sums = 71ff16d268122b0ade2d8e071cfb2110cdd75ac54ae67e36bc04be8bc077c121
sha256sums = 221e6439df2ee1ca55f5925f9cc3133cb9fb5a256bdc68743e8d46747e7e85b7
sha256sums = f719fb52edee98f54ba40786d2ecac6ef63f56797c8f52d4d7ce76a3825966eb
sha256sums = 2db1f319f850858ecebdcda1c1600d6dd523f171c5b019740298d43607d5fa00
@@ -57,5 +58,6 @@ pkgbase = clangd-opt
sha256sums = 991fac650864bbf16832a8c8a0689ee44ef2959a79c9b950ff6200cb4c51beff
sha256sums = 459bc42c7366305e562fa710551de909b581aa2358ca739585a0477dd06ebd6d
sha256sums = 0f5f7cc7f984988824bca66a2d08b0fa2b1b6ccdfcc1917e5cb0ed810036cfe7
+ sha256sums = a05f3894ddb881ef77146da6955fc0612de684d7bc09a2ef9b9fc6aa750efcac
pkgname = clangd-opt
diff --git a/PKGBUILD b/PKGBUILD
index 2dbf99baf201..fe03448c4979 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -95,6 +95,11 @@
# CLANGD_HOVERRECORDPAD:
# 'n' - do not apply this patch
# 'y' - apply this patch
+#
+# Allow specifying what headers are always included via "" or <> (PR: 67749)
+# CLANGD_CONFIG_INCLUDE_STYLE:
+# 'n' - do not apply this patch
+# 'y' - apply this patch
: ${CLANGD_DEFAULT_PATCH_STATE:=n}
@@ -115,9 +120,10 @@
: ${CLANGD_RESOLVEINCHEADERS:=$CLANGD_DEFAULT_PATCH_STATE}
: ${CLANGD_LSPREMOVEFROMCDB:=$CLANGD_DEFAULT_PATCH_STATE}
: ${CLANGD_HOVERRECORDPAD:=$CLANGD_DEFAULT_PATCH_STATE}
+: ${CLANGD_CONFIG_INCLUDE_STYLE:=$CLANGD_DEFAULT_PATCH_STATE}
pkgname=clangd-opt
-pkgver=19.r2558.g3d81d48398f0
+pkgver=19.r3010.gd4fd20258f63
pkgrel=1
pkgdesc='Trunk version of standalone clangd binary, with custom patches (look AUR page or PKGBUILD comments)'
arch=('x86_64')
@@ -145,13 +151,14 @@ source=("git+https://github.com/llvm/llvm-project.git#branch=main"
'inlay-hints-blockend-linelimit10.patch'
'resolve-incomplete-header-includes.patch'
'lsp-remove-files-from-cdb.patch'
- 'hover-record-paddings.patch')
+ 'hover-record-paddings.patch'
+ 'config-include-style.patch')
sha256sums=('SKIP'
'75b331257caa768c16687fd668ec2b8be62feb283892d601476c3e039f298a54' # hover-doxygen-trunk
'614dd012009facb502a7d44e07fc819aa95383c8917537c57968f76ba7881a94' # doxygen-extra-render-trunk
'b42d27929fcec3825711c13baf0c5a4ea0da33b8ff5e6f60c3c61d2f1f9525af' # doxygen-more-fields
'9e5dd128cedc8f37724d9c39c0f8f7efc826b0fd367f3a03c2564ff9f514ced7' # hover-resolve-forward-params
- 'faf5c8b2a5a345be59c33f5de591f39dd35b1a2b97ca067e21023e311610bc0d' # lsp-codelens
+ '71ff16d268122b0ade2d8e071cfb2110cdd75ac54ae67e36bc04be8bc077c121' # lsp-codelens
'221e6439df2ee1ca55f5925f9cc3133cb9fb5a256bdc68743e8d46747e7e85b7' # postfix-completion-trunk
'f719fb52edee98f54ba40786d2ecac6ef63f56797c8f52d4d7ce76a3825966eb' # refactor-extract-function
'2db1f319f850858ecebdcda1c1600d6dd523f171c5b019740298d43607d5fa00' # inlay-hints-paddings
@@ -165,7 +172,8 @@ sha256sums=('SKIP'
'3365392bf7d95a02e2fb22dffbba011a3fa1179543426a2558b9ac61a300a7a7' # inlay-hints-blockend-linelimit10
'991fac650864bbf16832a8c8a0689ee44ef2959a79c9b950ff6200cb4c51beff' # resolve-incomplete-header-includes
'459bc42c7366305e562fa710551de909b581aa2358ca739585a0477dd06ebd6d' # lsp-remove-files-from-cdb
- '0f5f7cc7f984988824bca66a2d08b0fa2b1b6ccdfcc1917e5cb0ed810036cfe7') # hover-record-paddings
+ '0f5f7cc7f984988824bca66a2d08b0fa2b1b6ccdfcc1917e5cb0ed810036cfe7' # hover-record-paddings
+ 'a05f3894ddb881ef77146da6955fc0612de684d7bc09a2ef9b9fc6aa750efcac') # config-include-style
pkgver() {
cd llvm-project
@@ -241,6 +249,11 @@ prepare() {
if [ "$CLANGD_RESOLVEINCHEADERS" != "n" ]; then
patch -p1 -i ${srcdir}/resolve-incomplete-header-includes.patch
fi
+
+ # Config patches
+ if [ "$CLANGD_CONFIG_INCLUDE_STYLE" != "n" ]; then
+ patch -p1 -i ${srcdir}/config-include-style.patch
+ fi
}
build() {
diff --git a/config-include-style.patch b/config-include-style.patch
new file mode 100644
index 000000000000..f78c6e06d893
--- /dev/null
+++ b/config-include-style.patch
@@ -0,0 +1,538 @@
+diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
+index 0e5f08cec440..3048f6944eb6 100644
+--- a/clang-tools-extra/clangd/CodeComplete.cpp
++++ b/clang-tools-extra/clangd/CodeComplete.cpp
+@@ -21,6 +21,7 @@
+ #include "AST.h"
+ #include "CodeCompletionStrings.h"
+ #include "Compiler.h"
++#include "Config.h"
+ #include "ExpectedTypes.h"
+ #include "Feature.h"
+ #include "FileDistance.h"
+@@ -1639,7 +1640,9 @@ public:
+ Inserter.emplace(
+ SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, Style,
+ SemaCCInput.ParseInput.CompileCommand.Directory,
+- &Recorder->CCSema->getPreprocessor().getHeaderSearchInfo());
++ &Recorder->CCSema->getPreprocessor().getHeaderSearchInfo(),
++ Config::current().Style.QuotedHeaders,
++ Config::current().Style.AngledHeaders);
+ for (const auto &Inc : Includes.MainFileIncludes)
+ Inserter->addExisting(Inc);
+
+@@ -1722,7 +1725,9 @@ public:
+ auto Style = getFormatStyleForFile(FileName, Content, TFS);
+ // This will only insert verbatim headers.
+ Inserter.emplace(FileName, Content, Style,
+- /*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr);
++ /*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr,
++ Config::current().Style.QuotedHeaders,
++ Config::current().Style.AngledHeaders);
+
+ auto Identifiers = collectIdentifiers(Content, Style);
+ std::vector<RawIdentifier> IdentifierResults;
+diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h
+index 4371c80a6c58..3559591fce00 100644
+--- a/clang-tools-extra/clangd/Config.h
++++ b/clang-tools-extra/clangd/Config.h
+@@ -123,6 +123,10 @@ struct Config {
+ // declarations, always spell out the whole name (with or without leading
+ // ::). All nested namespaces are affected as well.
+ std::vector<std::string> FullyQualifiedNamespaces;
++
++ // List of matcher functions for inserting certain headers with <> or "".
++ std::vector<std::function<bool(llvm::StringRef)>> QuotedHeaders;
++ std::vector<std::function<bool(llvm::StringRef)>> AngledHeaders;
+ } Style;
+
+ /// Configures code completion feature.
+diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp
+index 5bb2eb4a9f80..def0ee30e8fc 100644
+--- a/clang-tools-extra/clangd/ConfigCompile.cpp
++++ b/clang-tools-extra/clangd/ConfigCompile.cpp
+@@ -483,6 +483,55 @@ struct FragmentCompiler {
+ FullyQualifiedNamespaces.begin(), FullyQualifiedNamespaces.end());
+ });
+ }
++ auto QuotedFilter = compileHeaderRegexes(F.QuotedHeaders);
++ if (QuotedFilter.has_value()) {
++ Out.Apply.push_back(
++ [QuotedFilter = *QuotedFilter](const Params &, Config &C) {
++ C.Style.QuotedHeaders.emplace_back(QuotedFilter);
++ });
++ }
++ auto AngledFilter = compileHeaderRegexes(F.AngledHeaders);
++ if (AngledFilter.has_value()) {
++ Out.Apply.push_back(
++ [AngledFilter = *AngledFilter](const Params &, Config &C) {
++ C.Style.AngledHeaders.emplace_back(AngledFilter);
++ });
++ }
++ }
++
++ auto compileHeaderRegexes(llvm::ArrayRef<Located<std::string>> HeaderPatterns)
++ -> std::optional<std::function<bool(llvm::StringRef)>> {
++ // TODO: Share this code with Diagnostics.Includes.IgnoreHeader
++#ifdef CLANGD_PATH_CASE_INSENSITIVE
++ static llvm::Regex::RegexFlags Flags = llvm::Regex::IgnoreCase;
++#else
++ static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags;
++#endif
++ auto Filters = std::make_shared<std::vector<llvm::Regex>>();
++ for (auto &HeaderPattern : HeaderPatterns) {
++ // Anchor on the right.
++ std::string AnchoredPattern = "(" + *HeaderPattern + ")$";
++ llvm::Regex CompiledRegex(AnchoredPattern, Flags);
++ std::string RegexError;
++ if (!CompiledRegex.isValid(RegexError)) {
++ diag(Warning,
++ llvm::formatv("Invalid regular expression '{0}': {1}",
++ *HeaderPattern, RegexError)
++ .str(),
++ HeaderPattern.Range);
++ continue;
++ }
++ Filters->push_back(std::move(CompiledRegex));
++ }
++ if (Filters->empty())
++ return std::nullopt;
++ auto Filter = [Filters](llvm::StringRef Path) {
++ for (auto &Regex : *Filters)
++ if (Regex.match(Path))
++ return true;
++ return false;
++ };
++ return Filter;
+ }
+
+ void appendTidyCheckSpec(std::string &CurSpec,
+diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h
+index 7fa61108c78a..f0d1080f6c83 100644
+--- a/clang-tools-extra/clangd/ConfigFragment.h
++++ b/clang-tools-extra/clangd/ConfigFragment.h
+@@ -296,6 +296,23 @@ struct Fragment {
+ // ::). All nested namespaces are affected as well.
+ // Affects availability of the AddUsing tweak.
+ std::vector<Located<std::string>> FullyQualifiedNamespaces;
++
++ /// List of regexes for headers that should always be included with a
++ /// ""-style include. By default, and in case of a conflict with
++ /// 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
++ /// within the project.
++ std::vector<Located<std::string>> QuotedHeaders;
++ /// List of regexes for headers that should always be included with a
++ /// <>-style include. By default, and in case of a conflict with
++ /// 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
++ /// within the project.
++ std::vector<Located<std::string>> AngledHeaders;
+ };
+ StyleBlock Style;
+
+diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp
+index ce09af819247..ec7c91fe33b0 100644
+--- a/clang-tools-extra/clangd/ConfigYAML.cpp
++++ b/clang-tools-extra/clangd/ConfigYAML.cpp
+@@ -117,6 +117,14 @@ private:
+ if (auto Values = scalarValues(N))
+ F.FullyQualifiedNamespaces = std::move(*Values);
+ });
++ Dict.handle("QuotedHeaders", [&](Node &N) {
++ if (auto Values = scalarValues(N))
++ F.QuotedHeaders = std::move(*Values);
++ });
++ Dict.handle("AngledHeaders", [&](Node &N) {
++ if (auto Values = scalarValues(N))
++ F.AngledHeaders = std::move(*Values);
++ });
+ Dict.parse(N);
+ }
+
+diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp
+index 75f8668e7bef..2e474aaca209 100644
+--- a/clang-tools-extra/clangd/Headers.cpp
++++ b/clang-tools-extra/clangd/Headers.cpp
+@@ -9,6 +9,7 @@
+ #include "Headers.h"
+ #include "Preamble.h"
+ #include "SourceCode.h"
++#include "support/Logger.h"
+ #include "clang/Basic/SourceLocation.h"
+ #include "clang/Basic/SourceManager.h"
+ #include "clang/Frontend/CompilerInstance.h"
+@@ -30,8 +31,7 @@ namespace clangd {
+ class IncludeStructure::RecordHeaders : public PPCallbacks {
+ public:
+ RecordHeaders(const CompilerInstance &CI, IncludeStructure *Out)
+- : SM(CI.getSourceManager()),
+- Out(Out) {}
++ : SM(CI.getSourceManager()), Out(Out) {}
+
+ // Record existing #includes - both written and resolved paths. Only #includes
+ // in the main file are collected.
+@@ -287,11 +287,11 @@ IncludeInserter::calculateIncludePath(const HeaderFile &InsertedHeader,
+ assert(InsertedHeader.valid());
+ if (InsertedHeader.Verbatim)
+ return InsertedHeader.File;
+- bool IsAngled = false;
++ bool IsAngledByDefault = false;
+ std::string Suggested;
+ if (HeaderSearchInfo) {
+ Suggested = HeaderSearchInfo->suggestPathToFileForDiagnostics(
+- InsertedHeader.File, BuildDir, IncludingFile, &IsAngled);
++ InsertedHeader.File, BuildDir, IncludingFile, &IsAngledByDefault);
+ } else {
+ // Calculate include relative to including file only.
+ StringRef IncludingDir = llvm::sys::path::parent_path(IncludingFile);
+@@ -304,9 +304,33 @@ 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;
++ bool IsAngled = false;
++ for (auto Filter : AngledHeaders) {
++ if (Filter(Suggested)) {
++ IsAngled = true;
++ break;
++ }
++ }
++ bool IsQuoted = false;
++ for (auto Filter : QuotedHeaders) {
++ if (Filter(Suggested)) {
++ IsQuoted = true;
++ break;
++ }
++ }
++ // No filters apply, or both filters apply (a bug), use system default.
++ if (IsAngled == IsQuoted) {
++ // Probably a bug in the config regex.
++ if (IsAngled && IsQuoted) {
++ elog("Header '{0}' matches both quoted and angled regexes, default will "
++ "be used.",
++ Suggested);
++ }
++ IsAngled = IsAngledByDefault;
++ }
+ if (IsAngled)
+ Suggested = "<" + Suggested + ">";
+- else
++ else // if (IsQuoted)
+ Suggested = "\"" + Suggested + "\"";
+ return Suggested;
+ }
+diff --git a/clang-tools-extra/clangd/Headers.h b/clang-tools-extra/clangd/Headers.h
+index 41cf3de6bba3..b91179da253e 100644
+--- a/clang-tools-extra/clangd/Headers.h
++++ b/clang-tools-extra/clangd/Headers.h
+@@ -33,6 +33,8 @@
+ namespace clang {
+ namespace clangd {
+
++using HeaderFilter = llvm::ArrayRef<std::function<bool(llvm::StringRef)>>;
++
+ /// Returns true if \p Include is literal include like "path" or <path>.
+ bool isLiteralInclude(llvm::StringRef Include);
+
+@@ -211,10 +213,12 @@ public:
+ // include path of non-verbatim header will not be shortened.
+ IncludeInserter(StringRef FileName, StringRef Code,
+ const format::FormatStyle &Style, StringRef BuildDir,
+- HeaderSearch *HeaderSearchInfo)
++ HeaderSearch *HeaderSearchInfo, HeaderFilter QuotedHeaders,
++ HeaderFilter AngledHeaders)
+ : FileName(FileName), Code(Code), BuildDir(BuildDir),
+ HeaderSearchInfo(HeaderSearchInfo),
+- Inserter(FileName, Code, Style.IncludeStyle) {}
++ Inserter(FileName, Code, Style.IncludeStyle),
++ QuotedHeaders(QuotedHeaders), AngledHeaders(AngledHeaders) {}
+
+ void addExisting(const Inclusion &Inc);
+
+@@ -258,6 +262,8 @@ private:
+ HeaderSearch *HeaderSearchInfo = nullptr;
+ llvm::StringSet<> IncludedHeaders; // Both written and resolved.
+ tooling::HeaderIncludes Inserter; // Computers insertion replacement.
++ HeaderFilter QuotedHeaders;
++ HeaderFilter AngledHeaders;
+ };
+
+ } // namespace clangd
+diff --git a/clang-tools-extra/clangd/IncludeCleaner.h b/clang-tools-extra/clangd/IncludeCleaner.h
+index b3ba3a716083..7e289ef4c135 100644
+--- a/clang-tools-extra/clangd/IncludeCleaner.h
++++ b/clang-tools-extra/clangd/IncludeCleaner.h
+@@ -55,7 +55,6 @@ struct IncludeCleanerFindings {
+
+ IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST);
+
+-using HeaderFilter = llvm::ArrayRef<std::function<bool(llvm::StringRef)>>;
+ std::vector<Diag>
+ issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code,
+ const IncludeCleanerFindings &Findings,
+diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp
+index bbb0e2c77b3f..785fd4162462 100644
+--- a/clang-tools-extra/clangd/ParsedAST.cpp
++++ b/clang-tools-extra/clangd/ParsedAST.cpp
+@@ -628,7 +628,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
+ getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS);
+ auto Inserter = std::make_shared<IncludeInserter>(
+ Filename, Inputs.Contents, Style, BuildDir.get(),
+- &Clang->getPreprocessor().getHeaderSearchInfo());
++ &Clang->getPreprocessor().getHeaderSearchInfo(),
++ Cfg.Style.QuotedHeaders, Cfg.Style.AngledHeaders);
+ ArrayRef<Inclusion> MainFileIncludes;
+ if (Preamble) {
+ MainFileIncludes = Preamble->Includes.MainFileIncludes;
+diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+index 6d387fec9b38..bf264a5a44ee 100644
+--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
++++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+@@ -11,6 +11,7 @@
+ #include "ClangdServer.h"
+ #include "CodeComplete.h"
+ #include "Compiler.h"
++#include "Config.h"
+ #include "Feature.h"
+ #include "Matchers.h"
+ #include "Protocol.h"
+@@ -916,6 +917,41 @@ TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
+ AllOf(named("Y"), Not(insertInclude()))));
+ }
+
++TEST(CompletionTest, IncludeInsertionRespectsQuotedAngledConfig) {
++ TestTU TU;
++ TU.ExtraArgs.push_back("-I" + testPath("sub"));
++ TU.AdditionalFiles["sub/bar.h"] = "";
++ auto BarURI = URI::create(testPath("sub/bar.h")).toString();
++
++ Symbol Sym = cls("ns::X");
++ Sym.CanonicalDeclaration.FileURI = BarURI.c_str();
++ Sym.IncludeHeaders.emplace_back(BarURI, 1, Symbol::Include);
++ Annotations Test("int main() { ns::^ }");
++ TU.Code = Test.code().str();
++ auto Results = completions(TU, Test.point(), {Sym});
++ // Default for a local path is quoted include
++ EXPECT_THAT(Results.Completions,
++ ElementsAre(AllOf(named("X"), insertInclude("\"bar.h\""))));
++ {
++ Config C;
++ C.Style.AngledHeaders.push_back(
++ [](auto header) { return header == "bar.h"; });
++ WithContextValue WithCfg(Config::Key, std::move(C));
++ Results = completions(TU, Test.point(), {Sym});
++ EXPECT_THAT(Results.Completions,
++ ElementsAre(AllOf(named("X"), insertInclude("<bar.h>"))));
++ }
++ {
++ Config C;
++ C.Style.QuotedHeaders.push_back(
++ [](auto header) { return header == "bar.h"; });
++ WithContextValue WithCfg(Config::Key, std::move(C));
++ Results = completions(TU, Test.point(), {Sym});
++ EXPECT_THAT(Results.Completions,
++ ElementsAre(AllOf(named("X"), insertInclude("\"bar.h\""))));
++ }
++}
++
+ TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
+ Annotations Test(R"cpp(
+ #include "bar.h"
+@@ -1134,8 +1170,8 @@ TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
+ }
+
+ TEST(CompletionTests, EmptySnippetDoesNotCrash) {
+- // See https://github.com/clangd/clangd/issues/1216
+- auto Results = completions(R"cpp(
++ // See https://github.com/clangd/clangd/issues/1216
++ auto Results = completions(R"cpp(
+ int main() {
+ auto w = [&](auto &&f) { return f(f); };
+ auto f = w([&](auto &&f) {
+@@ -1151,18 +1187,18 @@ TEST(CompletionTests, EmptySnippetDoesNotCrash) {
+ }
+
+ TEST(CompletionTest, Issue1427Crash) {
+- // Need to provide main file signals to ensure that the branch in
+- // SymbolRelevanceSignals::computeASTSignals() that tries to
+- // compute a symbol ID is taken.
+- ASTSignals MainFileSignals;
+- CodeCompleteOptions Opts;
+- Opts.MainFileSignals = &MainFileSignals;
+- completions(R"cpp(
++ // Need to provide main file signals to ensure that the branch in
++ // SymbolRelevanceSignals::computeASTSignals() that tries to
++ // compute a symbol ID is taken.
++ ASTSignals MainFileSignals;
++ CodeCompleteOptions Opts;
++ Opts.MainFileSignals = &MainFileSignals;
++ completions(R"cpp(
+ auto f = []() {
+ 1.0_^
+ };
+ )cpp",
+- {}, Opts);
++ {}, Opts);
+ }
+
+ TEST(CompletionTest, BacktrackCrashes) {
+diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
+index f0ffc429c0ca..efee23003067 100644
+--- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
++++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
+@@ -539,6 +539,44 @@ TEST_F(ConfigCompileTests, Style) {
+ Frag.Style.FullyQualifiedNamespaces.push_back(std::string("bar"));
+ EXPECT_TRUE(compileAndApply());
+ EXPECT_THAT(Conf.Style.FullyQualifiedNamespaces, ElementsAre("foo", "bar"));
++
++ {
++ Frag = {};
++ EXPECT_TRUE(Conf.Style.QuotedHeaders.empty())
++ << Conf.Style.QuotedHeaders.size();
++ Frag.Style.QuotedHeaders.push_back(Located<std::string>("foo.h"));
++ Frag.Style.QuotedHeaders.push_back(Located<std::string>(".*inc"));
++ EXPECT_TRUE(compileAndApply());
++ auto HeaderFilter = [this](llvm::StringRef Path) {
++ for (auto &Filter : Conf.Style.QuotedHeaders) {
++ if (Filter(Path))
++ return true;
++ }
++ return false;
++ };
++ EXPECT_TRUE(HeaderFilter("foo.h"));
++ EXPECT_TRUE(HeaderFilter("prefix/foo.h"));
++ EXPECT_FALSE(HeaderFilter("bar.h"));
++ EXPECT_FALSE(HeaderFilter("foo.h/bar.h"));
++ }
++
++ {
++ Frag = {};
++ EXPECT_TRUE(Conf.Style.AngledHeaders.empty())
++ << Conf.Style.AngledHeaders.size();
++ Frag.Style.AngledHeaders.push_back(Located<std::string>("foo.h"));
++ Frag.Style.AngledHeaders.push_back(Located<std::string>(".*inc"));
++ EXPECT_TRUE(compileAndApply());
++ auto HeaderFilter = [this](llvm::StringRef Path) {
++ for (auto &Filter : Conf.Style.AngledHeaders) {
++ if (Filter(Path))
++ return true;
++ }
++ return false;
++ };
++ EXPECT_TRUE(HeaderFilter("foo.h"));
++ EXPECT_FALSE(HeaderFilter("bar.h"));
++ }
+ }
+ } // namespace
+ } // namespace config
+diff --git a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
+index 44a6647d4c0a..8f8ecc52b403 100644
+--- a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
++++ b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
+@@ -282,13 +282,19 @@ TEST(ParseYAML, Style) {
+ CapturedDiags Diags;
+ Annotations YAML(R"yaml(
+ Style:
+- FullyQualifiedNamespaces: [foo, bar])yaml");
++ FullyQualifiedNamespaces: [foo, bar]
++ AngledHeaders: ["foo", "bar"]
++ QuotedHeaders: ["baz", "baar"])yaml");
+ auto Results =
+ Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
+ ASSERT_THAT(Diags.Diagnostics, IsEmpty());
+ ASSERT_EQ(Results.size(), 1u);
+ EXPECT_THAT(Results[0].Style.FullyQualifiedNamespaces,
+ ElementsAre(val("foo"), val("bar")));
++ EXPECT_THAT(Results[0].Style.AngledHeaders,
++ ElementsAre(val("foo"), val("bar")));
++ EXPECT_THAT(Results[0].Style.QuotedHeaders,
++ ElementsAre(val("baz"), val("baar")));
+ }
+ } // namespace
+ } // namespace config
+diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp
+index dc6adaee1125..751383e3b465 100644
+--- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp
++++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp
+@@ -107,7 +107,8 @@ protected:
+
+ IncludeInserter Inserter(MainFile, /*Code=*/"", format::getLLVMStyle(),
+ CDB.getCompileCommand(MainFile)->Directory,
+- &Clang->getPreprocessor().getHeaderSearchInfo());
++ &Clang->getPreprocessor().getHeaderSearchInfo(),
++ QuotedHeaders, AngledHeaders);
+ for (const auto &Inc : Inclusions)
+ Inserter.addExisting(Inc);
+ auto Inserted = ToHeaderFile(Preferred);
+@@ -127,7 +128,8 @@ protected:
+
+ IncludeInserter Inserter(MainFile, /*Code=*/"", format::getLLVMStyle(),
+ CDB.getCompileCommand(MainFile)->Directory,
+- &Clang->getPreprocessor().getHeaderSearchInfo());
++ &Clang->getPreprocessor().getHeaderSearchInfo(),
++ QuotedHeaders, AngledHeaders);
+ auto Edit = Inserter.insert(VerbatimHeader, Directive);
+ Action.EndSourceFile();
+ return Edit;
+@@ -139,6 +141,8 @@ protected:
+ std::string Subdir = testPath("sub");
+ std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
+ IgnoringDiagConsumer IgnoreDiags;
++ std::vector<std::function<bool(llvm::StringRef)>> QuotedHeaders;
++ std::vector<std::function<bool(llvm::StringRef)>> AngledHeaders;
+ std::unique_ptr<CompilerInstance> Clang;
+ };
+
+@@ -304,6 +308,9 @@ TEST_F(HeadersTest, InsertInclude) {
+ std::string Path = testPath("sub/bar.h");
+ FS.Files[Path] = "";
+ EXPECT_EQ(calculate(Path), "\"bar.h\"");
++
++ AngledHeaders.push_back([](auto Path) { return true; });
++ EXPECT_EQ(calculate(Path), "<bar.h>");
+ }
+
+ TEST_F(HeadersTest, DoNotInsertIfInSameFile) {
+@@ -326,6 +333,17 @@ TEST_F(HeadersTest, ShortenIncludesInSearchPath) {
+ EXPECT_EQ(calculate(BarHeader), "\"sub/bar.h\"");
+ }
+
++TEST_F(HeadersTest, ShortenIncludesInSearchPathBracketed) {
++ AngledHeaders.push_back([](auto Path) { return true; });
++ std::string BarHeader = testPath("sub/bar.h");
++ EXPECT_EQ(calculate(BarHeader), "<bar.h>");
++
++ SearchDirArg = (llvm::Twine("-I") + Subdir + "/..").str();
++ CDB.ExtraClangFlags = {SearchDirArg.c_str()};
++ BarHeader = testPath("sub/bar.h");
++ EXPECT_EQ(calculate(BarHeader), "<sub/bar.h>");
++}
++
+ TEST_F(HeadersTest, ShortenedIncludeNotInSearchPath) {
+ std::string BarHeader =
+ llvm::sys::path::convert_to_slash(testPath("sub-2/bar.h"));
+@@ -338,6 +356,10 @@ TEST_F(HeadersTest, PreferredHeader) {
+
+ std::string BazHeader = testPath("sub/baz.h");
+ EXPECT_EQ(calculate(BarHeader, BazHeader), "\"baz.h\"");
++
++ AngledHeaders.push_back([](auto Path) { return true; });
++ std::string BiffHeader = testPath("sub/biff.h");
++ EXPECT_EQ(calculate(BarHeader, BiffHeader), "<biff.h>");
+ }
+
+ TEST_F(HeadersTest, DontInsertDuplicatePreferred) {
+@@ -370,7 +392,8 @@ TEST_F(HeadersTest, PreferInserted) {
+ TEST(Headers, NoHeaderSearchInfo) {
+ std::string MainFile = testPath("main.cpp");
+ IncludeInserter Inserter(MainFile, /*Code=*/"", format::getLLVMStyle(),
+- /*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr);
++ /*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr,
++ /*QuotedHeaders=*/{}, /*AngledHeaders=*/{});
+
+ auto HeaderPath = testPath("sub/bar.h");
+ auto Inserting = HeaderFile{HeaderPath, /*Verbatim=*/false};