Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/ClangdServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos,
CodeCompleteOpts.InsertIncludes =
Config::current().Completion.HeaderInsertion;
CodeCompleteOpts.CodePatterns = Config::current().Completion.CodePatterns;
CodeCompleteOpts.MacroFilter = Config::current().Completion.MacroFilter;
// FIXME(ibiryukov): even if Preamble is non-null, we may want to check
// both the old and the new version in case only one of them matches.
CodeCompleteResult Result = clangd::codeComplete(
Expand Down
35 changes: 28 additions & 7 deletions clang-tools-extra/clangd/CodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1435,7 +1435,8 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
Clang->setCodeCompletionConsumer(Consumer.release());

if (Input.Preamble.RequiredModules)
Input.Preamble.RequiredModules->adjustHeaderSearchOptions(Clang->getHeaderSearchOpts());
Input.Preamble.RequiredModules->adjustHeaderSearchOptions(
Clang->getHeaderSearchOpts());

SyntaxOnlyAction Action;
if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
Expand Down Expand Up @@ -2037,14 +2038,34 @@ class CodeCompleteFlow {
}

std::optional<float> fuzzyScore(const CompletionCandidate &C) {
// Macros can be very spammy, so we only support prefix completion.
if (((C.SemaResult &&
using MacroFilterPolicy = Config::MacroFilterPolicy;

const auto IsMacroResult =
((C.SemaResult &&
C.SemaResult->Kind == CodeCompletionResult::RK_Macro) ||
(C.IndexResult &&
C.IndexResult->SymInfo.Kind == index::SymbolKind::Macro)) &&
!C.Name.starts_with_insensitive(Filter->pattern()))
return std::nullopt;
return Filter->match(C.Name);
C.IndexResult->SymInfo.Kind == index::SymbolKind::Macro));

if (!IsMacroResult)
return Filter->match(C.Name);

// macros with leading and trailing underscore are probably spammy
switch (Opts.MacroFilter) {
case MacroFilterPolicy::ExactPrefix:
if (C.Name.starts_with_insensitive(Filter->pattern()))
return Filter->match(C.Name);
else
return std::nullopt;
case MacroFilterPolicy::FuzzyMatch:
if (!C.Name.starts_with_insensitive("_") &&
!C.Name.ends_with_insensitive("_"))
return Filter->match(C.Name);
else
return std::nullopt;
}
llvm_unreachable("Unhandled MacroFilter option in fuzzyScore.");

return std::nullopt;
}

CodeCompletion::Scores
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/clangd/CodeComplete.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ struct CodeCompleteOptions {
/// Whether to suggest code patterns & snippets or not in completion
Config::CodePatternsPolicy CodePatterns = Config::CodePatternsPolicy::All;

/// Filter macros using an exact prefix, or with a fuzzy match. In both cases,
/// macros with leading or trailing underscores are strictly filtered
Config::MacroFilterPolicy MacroFilter =
Config::MacroFilterPolicy::ExactPrefix;

/// Whether to use the clang parser, or fallback to text-based completion
/// (using identifiers in the current file and symbol indexes).
enum CodeCompletionParse {
Expand Down
8 changes: 8 additions & 0 deletions clang-tools-extra/clangd/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ struct Config {
None // Suggest none of the code patterns and snippets
};

enum class MacroFilterPolicy {
ExactPrefix, // Suggest macros if the prefix matches exactly
FuzzyMatch, // Fuzzy-match macros if they do not have "_" as prefix or
// suffix
};

/// Configures code completion feature.
struct {
/// Whether code completion includes results that are not visible in current
Expand All @@ -168,6 +174,8 @@ struct Config {
HeaderInsertionPolicy HeaderInsertion = HeaderInsertionPolicy::IWYU;
/// Enables code patterns & snippets suggestions
CodePatternsPolicy CodePatterns = CodePatternsPolicy::All;
/// Controls how macros are filtered
MacroFilterPolicy MacroFilter = MacroFilterPolicy::ExactPrefix;
} Completion;

/// Configures hover feature.
Expand Down
20 changes: 16 additions & 4 deletions clang-tools-extra/clangd/ConfigCompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,10 +564,10 @@ struct FragmentCompiler {
auto Fast = isFastTidyCheck(Str);
if (!Fast.has_value()) {
diag(Warning,
llvm::formatv(
"Latency of clang-tidy check '{0}' is not known. "
"It will only run if ClangTidy.FastCheckFilter is Loose or None",
Str)
llvm::formatv("Latency of clang-tidy check '{0}' is not known. "
"It will only run if ClangTidy.FastCheckFilter is "
"Loose or None",
Str)
.str(),
Arg.Range);
} else if (!*Fast) {
Expand Down Expand Up @@ -719,6 +719,18 @@ struct FragmentCompiler {
C.Completion.CodePatterns = *Val;
});
}

if (F.MacroFilter) {
if (auto Val =
compileEnum<Config::MacroFilterPolicy>("MacroFilter",
*F.MacroFilter)
.map("ExactPrefix", Config::MacroFilterPolicy::ExactPrefix)
.map("FuzzyMatch", Config::MacroFilterPolicy::FuzzyMatch)
.value())
Out.Apply.push_back([Val](const Params &, Config &C) {
C.Completion.MacroFilter = *Val;
});
}
}

void compile(Fragment::HoverBlock &&F) {
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/clangd/ConfigFragment.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,12 @@ struct Fragment {
/// All => enable all code patterns and snippets suggestion
/// None => disable all code patterns and snippets suggestion
std::optional<Located<std::string>> CodePatterns;
/// How to filter macros before offering them as suggestions
/// Values are Config::MacroFilterPolicy:
/// ExactPrefix: Suggest macros if the prefix matches exactly
/// FuzzyMatch: Fuzzy-match macros if they do not have "_" as prefix or
/// suffix
std::optional<Located<std::string>> MacroFilter;
};
CompletionBlock Completion;

Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/ConfigYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ class Parser {
if (auto CodePatterns = scalarValue(N, "CodePatterns"))
F.CodePatterns = *CodePatterns;
});
Dict.handle("MacroFilter", [&](Node &N) {
if (auto MacroFilter = scalarValue(N, "MacroFilter"))
F.MacroFilter = *MacroFilter;
});
Dict.parse(N);
}

Expand Down
29 changes: 29 additions & 0 deletions clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4692,6 +4692,35 @@ TEST(CompletionTest, ListExplicitObjectOverloads) {
}
}

TEST(CompletionTest, FuzzyMatchMacro) {
const auto *const Code = R"cpp(
#define gl_foo() 42
#define _gl_foo() 42
int gl_frob();

int main() {
int x = glf^
}
)cpp";

{
CodeCompleteOptions Opts{};
EXPECT_EQ(Opts.MacroFilter, Config::MacroFilterPolicy::ExactPrefix);

auto Results = completions(Code, {}, Opts);
EXPECT_THAT(Results.Completions, ElementsAre(named("gl_frob")));
}

{
CodeCompleteOptions Opts{};
Opts.MacroFilter = Config::MacroFilterPolicy::FuzzyMatch;

auto Results = completions(Code, {}, Opts);
EXPECT_THAT(Results.Completions,
ElementsAre(named("gl_frob"), named("gl_foo")));
}
}

} // namespace
} // namespace clangd
} // namespace clang
14 changes: 14 additions & 0 deletions clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,20 @@ TEST(ParseYAML, CodePatterns) {
EXPECT_THAT(Results[0].Completion.CodePatterns, llvm::ValueIs(val("None")));
}

TEST(ParseYAML, MacroFilter) {
CapturedDiags Diags;
Annotations YAML(R"yaml(
Completion:
MacroFilter: FuzzyMatch
)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].Completion.MacroFilter,
llvm::ValueIs(val("FuzzyMatch")));
}

TEST(ParseYAML, Hover) {
CapturedDiags Diags;
Annotations YAML(R"yaml(
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ Hover

Code completion
^^^^^^^^^^^^^^^
- Added a new ``MacroFilter`` configuration option to ``Completion`` to
allow fuzzy-matching with the ``FuzzyMatch`` option when suggesting
macros. ``ExactPrefix`` is the default, which retains previous
behavior of suggesting macros which match the prefix exactly.

Code actions
^^^^^^^^^^^^
Expand Down