Skip to content

Commit aa8ba6a

Browse files
SC llvm teamSC llvm team
SC llvm team
authored and
SC llvm team
committed
Merged main:48bf0a9457fd into amd-gfx:ee6d737e2b45
Local branch amd-gfx ee6d737 Merged main:ca28fcc6fce5 into amd-gfx:09c430c738aa Remote branch main 48bf0a9 [Clang][ASTMatcher] Add `dependentScopeDeclRefExpr` matcher (llvm#120996)
2 parents ee6d737 + 48bf0a9 commit aa8ba6a

File tree

96 files changed

+9000
-9591
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+9000
-9591
lines changed

clang-tools-extra/clangd/CodeComplete.cpp

+9-5
Original file line numberDiff line numberDiff line change
@@ -807,8 +807,8 @@ SpecifiedScope getQueryScopes(CodeCompletionContext &CCContext,
807807
llvm::StringRef SpelledSpecifier = Lexer::getSourceText(
808808
CharSourceRange::getCharRange(SemaSpecifier->getRange()),
809809
CCSema.SourceMgr, clang::LangOptions());
810-
if (SpelledSpecifier.consume_front("::"))
811-
Scopes.QueryScopes = {""};
810+
if (SpelledSpecifier.consume_front("::"))
811+
Scopes.QueryScopes = {""};
812812
Scopes.UnresolvedQualifier = std::string(SpelledSpecifier);
813813
// Sema excludes the trailing "::".
814814
if (!Scopes.UnresolvedQualifier->empty())
@@ -1604,7 +1604,7 @@ class CodeCompleteFlow {
16041604
CompletionPrefix HeuristicPrefix;
16051605
std::optional<FuzzyMatcher> Filter; // Initialized once Sema runs.
16061606
Range ReplacedRange;
1607-
std::vector<std::string> QueryScopes; // Initialized once Sema runs.
1607+
std::vector<std::string> QueryScopes; // Initialized once Sema runs.
16081608
std::vector<std::string> AccessibleScopes; // Initialized once Sema runs.
16091609
// Initialized once QueryScopes is initialized, if there are scopes.
16101610
std::optional<ScopeDistance> ScopeProximity;
@@ -1663,7 +1663,9 @@ class CodeCompleteFlow {
16631663
Inserter.emplace(
16641664
SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, Style,
16651665
SemaCCInput.ParseInput.CompileCommand.Directory,
1666-
&Recorder->CCSema->getPreprocessor().getHeaderSearchInfo());
1666+
&Recorder->CCSema->getPreprocessor().getHeaderSearchInfo(),
1667+
Config::current().Style.QuotedHeaders,
1668+
Config::current().Style.AngledHeaders);
16671669
for (const auto &Inc : Includes.MainFileIncludes)
16681670
Inserter->addExisting(Inc);
16691671

@@ -1746,7 +1748,9 @@ class CodeCompleteFlow {
17461748
auto Style = getFormatStyleForFile(FileName, Content, TFS, false);
17471749
// This will only insert verbatim headers.
17481750
Inserter.emplace(FileName, Content, Style,
1749-
/*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr);
1751+
/*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr,
1752+
Config::current().Style.QuotedHeaders,
1753+
Config::current().Style.AngledHeaders);
17501754

17511755
auto Identifiers = collectIdentifiers(Content, Style);
17521756
std::vector<RawIdentifier> IdentifierResults;

clang-tools-extra/clangd/Config.h

+4
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ struct Config {
124124
// declarations, always spell out the whole name (with or without leading
125125
// ::). All nested namespaces are affected as well.
126126
std::vector<std::string> FullyQualifiedNamespaces;
127+
128+
// List of matcher functions for inserting certain headers with <> or "".
129+
std::vector<std::function<bool(llvm::StringRef)>> QuotedHeaders;
130+
std::vector<std::function<bool(llvm::StringRef)>> AngledHeaders;
127131
} Style;
128132

129133
/// controls the completion options for argument lists.

clang-tools-extra/clangd/ConfigCompile.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,55 @@ struct FragmentCompiler {
482482
FullyQualifiedNamespaces.begin(), FullyQualifiedNamespaces.end());
483483
});
484484
}
485+
auto QuotedFilter = compileHeaderRegexes(F.QuotedHeaders);
486+
if (QuotedFilter.has_value()) {
487+
Out.Apply.push_back(
488+
[QuotedFilter = *QuotedFilter](const Params &, Config &C) {
489+
C.Style.QuotedHeaders.emplace_back(QuotedFilter);
490+
});
491+
}
492+
auto AngledFilter = compileHeaderRegexes(F.AngledHeaders);
493+
if (AngledFilter.has_value()) {
494+
Out.Apply.push_back(
495+
[AngledFilter = *AngledFilter](const Params &, Config &C) {
496+
C.Style.AngledHeaders.emplace_back(AngledFilter);
497+
});
498+
}
499+
}
500+
501+
auto compileHeaderRegexes(llvm::ArrayRef<Located<std::string>> HeaderPatterns)
502+
-> std::optional<std::function<bool(llvm::StringRef)>> {
503+
// TODO: Share this code with Diagnostics.Includes.IgnoreHeader
504+
#ifdef CLANGD_PATH_CASE_INSENSITIVE
505+
static llvm::Regex::RegexFlags Flags = llvm::Regex::IgnoreCase;
506+
#else
507+
static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags;
508+
#endif
509+
auto Filters = std::make_shared<std::vector<llvm::Regex>>();
510+
for (auto &HeaderPattern : HeaderPatterns) {
511+
// Anchor on the right.
512+
std::string AnchoredPattern = "(" + *HeaderPattern + ")$";
513+
llvm::Regex CompiledRegex(AnchoredPattern, Flags);
514+
std::string RegexError;
515+
if (!CompiledRegex.isValid(RegexError)) {
516+
diag(Warning,
517+
llvm::formatv("Invalid regular expression '{0}': {1}",
518+
*HeaderPattern, RegexError)
519+
.str(),
520+
HeaderPattern.Range);
521+
continue;
522+
}
523+
Filters->push_back(std::move(CompiledRegex));
524+
}
525+
if (Filters->empty())
526+
return std::nullopt;
527+
auto Filter = [Filters](llvm::StringRef Path) {
528+
for (auto &Regex : *Filters)
529+
if (Regex.match(Path))
530+
return true;
531+
return false;
532+
};
533+
return Filter;
485534
}
486535

487536
void appendTidyCheckSpec(std::string &CurSpec,

clang-tools-extra/clangd/ConfigFragment.h

+17
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,23 @@ struct Fragment {
301301
// ::). All nested namespaces are affected as well.
302302
// Affects availability of the AddUsing tweak.
303303
std::vector<Located<std::string>> FullyQualifiedNamespaces;
304+
305+
/// List of regexes for headers that should always be included with a
306+
/// ""-style include. By default, and in case of a conflict with
307+
/// AngledHeaders (i.e. a header matches a regex in both QuotedHeaders and
308+
/// AngledHeaders), system headers use <> and non-system headers use "".
309+
/// These can match any suffix of the header file in question.
310+
/// Matching is performed against the header text, not its absolute path
311+
/// within the project.
312+
std::vector<Located<std::string>> QuotedHeaders;
313+
/// List of regexes for headers that should always be included with a
314+
/// <>-style include. By default, and in case of a conflict with
315+
/// AngledHeaders (i.e. a header matches a regex in both QuotedHeaders and
316+
/// AngledHeaders), system headers use <> and non-system headers use "".
317+
/// These can match any suffix of the header file in question.
318+
/// Matching is performed against the header text, not its absolute path
319+
/// within the project.
320+
std::vector<Located<std::string>> AngledHeaders;
304321
};
305322
StyleBlock Style;
306323

clang-tools-extra/clangd/ConfigYAML.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@ class Parser {
116116
if (auto Values = scalarValues(N))
117117
F.FullyQualifiedNamespaces = std::move(*Values);
118118
});
119+
Dict.handle("QuotedHeaders", [&](Node &N) {
120+
if (auto Values = scalarValues(N))
121+
F.QuotedHeaders = std::move(*Values);
122+
});
123+
Dict.handle("AngledHeaders", [&](Node &N) {
124+
if (auto Values = scalarValues(N))
125+
F.AngledHeaders = std::move(*Values);
126+
});
119127
Dict.parse(N);
120128
}
121129

clang-tools-extra/clangd/Headers.cpp

+29-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "Headers.h"
1010
#include "Preamble.h"
1111
#include "SourceCode.h"
12+
#include "support/Logger.h"
1213
#include "clang/Basic/SourceLocation.h"
1314
#include "clang/Basic/SourceManager.h"
1415
#include "clang/Frontend/CompilerInstance.h"
@@ -30,8 +31,7 @@ namespace clangd {
3031
class IncludeStructure::RecordHeaders : public PPCallbacks {
3132
public:
3233
RecordHeaders(const CompilerInstance &CI, IncludeStructure *Out)
33-
: SM(CI.getSourceManager()),
34-
Out(Out) {}
34+
: SM(CI.getSourceManager()), Out(Out) {}
3535

3636
// Record existing #includes - both written and resolved paths. Only #includes
3737
// in the main file are collected.
@@ -287,11 +287,11 @@ IncludeInserter::calculateIncludePath(const HeaderFile &InsertedHeader,
287287
assert(InsertedHeader.valid());
288288
if (InsertedHeader.Verbatim)
289289
return InsertedHeader.File;
290-
bool IsAngled = false;
290+
bool IsAngledByDefault = false;
291291
std::string Suggested;
292292
if (HeaderSearchInfo) {
293293
Suggested = HeaderSearchInfo->suggestPathToFileForDiagnostics(
294-
InsertedHeader.File, BuildDir, IncludingFile, &IsAngled);
294+
InsertedHeader.File, BuildDir, IncludingFile, &IsAngledByDefault);
295295
} else {
296296
// Calculate include relative to including file only.
297297
StringRef IncludingDir = llvm::sys::path::parent_path(IncludingFile);
@@ -304,9 +304,33 @@ IncludeInserter::calculateIncludePath(const HeaderFile &InsertedHeader,
304304
// FIXME: should we allow (some limited number of) "../header.h"?
305305
if (llvm::sys::path::is_absolute(Suggested))
306306
return std::nullopt;
307+
bool IsAngled = false;
308+
for (auto Filter : AngledHeaders) {
309+
if (Filter(Suggested)) {
310+
IsAngled = true;
311+
break;
312+
}
313+
}
314+
bool IsQuoted = false;
315+
for (auto Filter : QuotedHeaders) {
316+
if (Filter(Suggested)) {
317+
IsQuoted = true;
318+
break;
319+
}
320+
}
321+
// No filters apply, or both filters apply (a bug), use system default.
322+
if (IsAngled == IsQuoted) {
323+
// Probably a bug in the config regex.
324+
if (IsAngled && IsQuoted) {
325+
elog("Header '{0}' matches both quoted and angled regexes, default will "
326+
"be used.",
327+
Suggested);
328+
}
329+
IsAngled = IsAngledByDefault;
330+
}
307331
if (IsAngled)
308332
Suggested = "<" + Suggested + ">";
309-
else
333+
else // if (IsQuoted)
310334
Suggested = "\"" + Suggested + "\"";
311335
return Suggested;
312336
}

clang-tools-extra/clangd/Headers.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
namespace clang {
3434
namespace clangd {
3535

36+
using HeaderFilter = llvm::ArrayRef<std::function<bool(llvm::StringRef)>>;
37+
3638
/// Returns true if \p Include is literal include like "path" or <path>.
3739
bool isLiteralInclude(llvm::StringRef Include);
3840

@@ -211,10 +213,12 @@ class IncludeInserter {
211213
// include path of non-verbatim header will not be shortened.
212214
IncludeInserter(StringRef FileName, StringRef Code,
213215
const format::FormatStyle &Style, StringRef BuildDir,
214-
HeaderSearch *HeaderSearchInfo)
216+
HeaderSearch *HeaderSearchInfo, HeaderFilter QuotedHeaders,
217+
HeaderFilter AngledHeaders)
215218
: FileName(FileName), Code(Code), BuildDir(BuildDir),
216219
HeaderSearchInfo(HeaderSearchInfo),
217-
Inserter(FileName, Code, Style.IncludeStyle) {}
220+
Inserter(FileName, Code, Style.IncludeStyle),
221+
QuotedHeaders(QuotedHeaders), AngledHeaders(AngledHeaders) {}
218222

219223
void addExisting(const Inclusion &Inc);
220224

@@ -258,6 +262,8 @@ class IncludeInserter {
258262
HeaderSearch *HeaderSearchInfo = nullptr;
259263
llvm::StringSet<> IncludedHeaders; // Both written and resolved.
260264
tooling::HeaderIncludes Inserter; // Computers insertion replacement.
265+
HeaderFilter QuotedHeaders;
266+
HeaderFilter AngledHeaders;
261267
};
262268

263269
} // namespace clangd

clang-tools-extra/clangd/IncludeCleaner.h

-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ IncludeCleanerFindings
5757
computeIncludeCleanerFindings(ParsedAST &AST,
5858
bool AnalyzeAngledIncludes = false);
5959

60-
using HeaderFilter = llvm::ArrayRef<std::function<bool(llvm::StringRef)>>;
6160
std::vector<Diag>
6261
issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code,
6362
const IncludeCleanerFindings &Findings,

clang-tools-extra/clangd/ParsedAST.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
639639
getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS, false);
640640
auto Inserter = std::make_shared<IncludeInserter>(
641641
Filename, Inputs.Contents, Style, BuildDir.get(),
642-
&Clang->getPreprocessor().getHeaderSearchInfo());
642+
&Clang->getPreprocessor().getHeaderSearchInfo(),
643+
Cfg.Style.QuotedHeaders, Cfg.Style.AngledHeaders);
643644
ArrayRef<Inclusion> MainFileIncludes;
644645
if (Preamble) {
645646
MainFileIncludes = Preamble->Includes.MainFileIncludes;

clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp

+45-10
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,41 @@ TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
920920
AllOf(named("Y"), Not(insertInclude()))));
921921
}
922922

923+
TEST(CompletionTest, IncludeInsertionRespectsQuotedAngledConfig) {
924+
TestTU TU;
925+
TU.ExtraArgs.push_back("-I" + testPath("sub"));
926+
TU.AdditionalFiles["sub/bar.h"] = "";
927+
auto BarURI = URI::create(testPath("sub/bar.h")).toString();
928+
929+
Symbol Sym = cls("ns::X");
930+
Sym.CanonicalDeclaration.FileURI = BarURI.c_str();
931+
Sym.IncludeHeaders.emplace_back(BarURI, 1, Symbol::Include);
932+
Annotations Test("int main() { ns::^ }");
933+
TU.Code = Test.code().str();
934+
auto Results = completions(TU, Test.point(), {Sym});
935+
// Default for a local path is quoted include
936+
EXPECT_THAT(Results.Completions,
937+
ElementsAre(AllOf(named("X"), insertInclude("\"bar.h\""))));
938+
{
939+
Config C;
940+
C.Style.AngledHeaders.push_back(
941+
[](auto header) { return header == "bar.h"; });
942+
WithContextValue WithCfg(Config::Key, std::move(C));
943+
Results = completions(TU, Test.point(), {Sym});
944+
EXPECT_THAT(Results.Completions,
945+
ElementsAre(AllOf(named("X"), insertInclude("<bar.h>"))));
946+
}
947+
{
948+
Config C;
949+
C.Style.QuotedHeaders.push_back(
950+
[](auto header) { return header == "bar.h"; });
951+
WithContextValue WithCfg(Config::Key, std::move(C));
952+
Results = completions(TU, Test.point(), {Sym});
953+
EXPECT_THAT(Results.Completions,
954+
ElementsAre(AllOf(named("X"), insertInclude("\"bar.h\""))));
955+
}
956+
}
957+
923958
TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
924959
Annotations Test(R"cpp(
925960
#include "bar.h"
@@ -1138,8 +1173,8 @@ TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
11381173
}
11391174

11401175
TEST(CompletionTests, EmptySnippetDoesNotCrash) {
1141-
// See https://github.com/clangd/clangd/issues/1216
1142-
auto Results = completions(R"cpp(
1176+
// See https://github.com/clangd/clangd/issues/1216
1177+
auto Results = completions(R"cpp(
11431178
int main() {
11441179
auto w = [&](auto &&f) { return f(f); };
11451180
auto f = w([&](auto &&f) {
@@ -1155,18 +1190,18 @@ TEST(CompletionTests, EmptySnippetDoesNotCrash) {
11551190
}
11561191

11571192
TEST(CompletionTest, Issue1427Crash) {
1158-
// Need to provide main file signals to ensure that the branch in
1159-
// SymbolRelevanceSignals::computeASTSignals() that tries to
1160-
// compute a symbol ID is taken.
1161-
ASTSignals MainFileSignals;
1162-
CodeCompleteOptions Opts;
1163-
Opts.MainFileSignals = &MainFileSignals;
1164-
completions(R"cpp(
1193+
// Need to provide main file signals to ensure that the branch in
1194+
// SymbolRelevanceSignals::computeASTSignals() that tries to
1195+
// compute a symbol ID is taken.
1196+
ASTSignals MainFileSignals;
1197+
CodeCompleteOptions Opts;
1198+
Opts.MainFileSignals = &MainFileSignals;
1199+
completions(R"cpp(
11651200
auto f = []() {
11661201
1.0_^
11671202
};
11681203
)cpp",
1169-
{}, Opts);
1204+
{}, Opts);
11701205
}
11711206

11721207
TEST(CompletionTest, BacktrackCrashes) {

clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,44 @@ TEST_F(ConfigCompileTests, Style) {
545545
Frag.Style.FullyQualifiedNamespaces.push_back(std::string("bar"));
546546
EXPECT_TRUE(compileAndApply());
547547
EXPECT_THAT(Conf.Style.FullyQualifiedNamespaces, ElementsAre("foo", "bar"));
548+
549+
{
550+
Frag = {};
551+
EXPECT_TRUE(Conf.Style.QuotedHeaders.empty())
552+
<< Conf.Style.QuotedHeaders.size();
553+
Frag.Style.QuotedHeaders.push_back(Located<std::string>("foo.h"));
554+
Frag.Style.QuotedHeaders.push_back(Located<std::string>(".*inc"));
555+
EXPECT_TRUE(compileAndApply());
556+
auto HeaderFilter = [this](llvm::StringRef Path) {
557+
for (auto &Filter : Conf.Style.QuotedHeaders) {
558+
if (Filter(Path))
559+
return true;
560+
}
561+
return false;
562+
};
563+
EXPECT_TRUE(HeaderFilter("foo.h"));
564+
EXPECT_TRUE(HeaderFilter("prefix/foo.h"));
565+
EXPECT_FALSE(HeaderFilter("bar.h"));
566+
EXPECT_FALSE(HeaderFilter("foo.h/bar.h"));
567+
}
568+
569+
{
570+
Frag = {};
571+
EXPECT_TRUE(Conf.Style.AngledHeaders.empty())
572+
<< Conf.Style.AngledHeaders.size();
573+
Frag.Style.AngledHeaders.push_back(Located<std::string>("foo.h"));
574+
Frag.Style.AngledHeaders.push_back(Located<std::string>(".*inc"));
575+
EXPECT_TRUE(compileAndApply());
576+
auto HeaderFilter = [this](llvm::StringRef Path) {
577+
for (auto &Filter : Conf.Style.AngledHeaders) {
578+
if (Filter(Path))
579+
return true;
580+
}
581+
return false;
582+
};
583+
EXPECT_TRUE(HeaderFilter("foo.h"));
584+
EXPECT_FALSE(HeaderFilter("bar.h"));
585+
}
548586
}
549587
} // namespace
550588
} // namespace config

0 commit comments

Comments
 (0)