mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-21 14:56:57 +00:00
[clangd] Allow specifying what headers are always included via "" or <> (#67749)
Projects can now add config fragments like this to their .clangd: ```yaml Style: QuotedHeaders: "src/.*" AngledHeaders: ["path/sdk/.*", "third-party/.*"] ``` to force headers inserted via the --header-insertion=iwyu mode matching at least one of the regexes to have <> (AngledHeaders) or "" (QuotedHeaders) around them, respectively. For other headers (and in conflicting cases where both styles have a matching regex), the current system header detection remains. Fixes https://github.com/clangd/clangd/issues/1247
This commit is contained in:
parent
8caeb2e0c2
commit
1f90797f6a
@ -807,8 +807,8 @@ SpecifiedScope getQueryScopes(CodeCompletionContext &CCContext,
|
||||
llvm::StringRef SpelledSpecifier = Lexer::getSourceText(
|
||||
CharSourceRange::getCharRange(SemaSpecifier->getRange()),
|
||||
CCSema.SourceMgr, clang::LangOptions());
|
||||
if (SpelledSpecifier.consume_front("::"))
|
||||
Scopes.QueryScopes = {""};
|
||||
if (SpelledSpecifier.consume_front("::"))
|
||||
Scopes.QueryScopes = {""};
|
||||
Scopes.UnresolvedQualifier = std::string(SpelledSpecifier);
|
||||
// Sema excludes the trailing "::".
|
||||
if (!Scopes.UnresolvedQualifier->empty())
|
||||
@ -1604,7 +1604,7 @@ class CodeCompleteFlow {
|
||||
CompletionPrefix HeuristicPrefix;
|
||||
std::optional<FuzzyMatcher> Filter; // Initialized once Sema runs.
|
||||
Range ReplacedRange;
|
||||
std::vector<std::string> QueryScopes; // Initialized once Sema runs.
|
||||
std::vector<std::string> QueryScopes; // Initialized once Sema runs.
|
||||
std::vector<std::string> AccessibleScopes; // Initialized once Sema runs.
|
||||
// Initialized once QueryScopes is initialized, if there are scopes.
|
||||
std::optional<ScopeDistance> ScopeProximity;
|
||||
@ -1663,7 +1663,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);
|
||||
|
||||
@ -1746,7 +1748,9 @@ public:
|
||||
auto Style = getFormatStyleForFile(FileName, Content, TFS, false);
|
||||
// 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;
|
||||
|
@ -124,6 +124,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;
|
||||
|
||||
/// controls the completion options for argument lists.
|
||||
|
@ -482,6 +482,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,
|
||||
|
@ -301,6 +301,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;
|
||||
|
||||
|
@ -116,6 +116,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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -57,7 +57,6 @@ IncludeCleanerFindings
|
||||
computeIncludeCleanerFindings(ParsedAST &AST,
|
||||
bool AnalyzeAngledIncludes = false);
|
||||
|
||||
using HeaderFilter = llvm::ArrayRef<std::function<bool(llvm::StringRef)>>;
|
||||
std::vector<Diag>
|
||||
issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code,
|
||||
const IncludeCleanerFindings &Findings,
|
||||
|
@ -639,7 +639,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
|
||||
getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS, false);
|
||||
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;
|
||||
|
@ -920,6 +920,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"
|
||||
@ -1138,8 +1173,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) {
|
||||
@ -1155,18 +1190,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) {
|
||||
|
@ -545,6 +545,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
|
||||
|
@ -297,13 +297,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
|
||||
|
@ -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};
|
||||
|
Loading…
x
Reference in New Issue
Block a user