forked from OSchip/llvm-project
[clangd] Drop template argument lists from completions followed by <
Now, given `template <typename T> foo() {}` when user types `fo^<int>()` the completion snippet will not contain `<int>()`. Also, when the next token is opening parenthesis (`(`) and completion snippet contains template argument list, it is still emitted. This patch complements D81380. Related issue: https://github.com/clangd/clangd/issues/387 Reviewed By: kadircet Differential Revision: https://reviews.llvm.org/D89870
This commit is contained in:
parent
a89035d750
commit
19db870a0d
|
@ -452,18 +452,52 @@ private:
|
|||
std::string summarizeSnippet() const {
|
||||
if (IsUsingDeclaration)
|
||||
return "";
|
||||
// Suppress function argument snippets if args are already present.
|
||||
if ((Completion.Kind == CompletionItemKind::Function ||
|
||||
Completion.Kind == CompletionItemKind::Method ||
|
||||
Completion.Kind == CompletionItemKind::Constructor) &&
|
||||
NextTokenKind == tok::l_paren)
|
||||
return "";
|
||||
auto *Snippet = onlyValue<&BundledEntry::SnippetSuffix>();
|
||||
if (!Snippet)
|
||||
// All bundles are function calls.
|
||||
// FIXME(ibiryukov): sometimes add template arguments to a snippet, e.g.
|
||||
// we need to complete 'forward<$1>($0)'.
|
||||
return "($0)";
|
||||
// Suppress function argument snippets cursor is followed by left
|
||||
// parenthesis (and potentially arguments) or if there are potentially
|
||||
// template arguments. There are cases where it would be wrong (e.g. next
|
||||
// '<' token is a comparison rather than template argument list start) but
|
||||
// it is less common and suppressing snippet provides better UX.
|
||||
if (Completion.Kind == CompletionItemKind::Function ||
|
||||
Completion.Kind == CompletionItemKind::Method ||
|
||||
Completion.Kind == CompletionItemKind::Constructor) {
|
||||
// If there is a potential template argument list, drop snippet and just
|
||||
// complete symbol name. Ideally, this could generate an edit that would
|
||||
// paste function arguments after template argument list but it would be
|
||||
// complicated. Example:
|
||||
//
|
||||
// fu^<int> -> function<int>
|
||||
if (NextTokenKind == tok::less && Snippet->front() == '<')
|
||||
return "";
|
||||
// Potentially followed by argument list.
|
||||
if (NextTokenKind == tok::l_paren) {
|
||||
// If snippet contains template arguments we will emit them and drop
|
||||
// function arguments. Example:
|
||||
//
|
||||
// fu^(42) -> function<int>(42);
|
||||
if (Snippet->front() == '<') {
|
||||
// Find matching '>'. Snippet->find('>') will not work in cases like
|
||||
// template <typename T=std::vector<int>>. Hence, iterate through
|
||||
// the snippet until the angle bracket balance reaches zero.
|
||||
int Balance = 0;
|
||||
size_t I = 0;
|
||||
do {
|
||||
if (Snippet->at(I) == '>')
|
||||
--Balance;
|
||||
else if (Snippet->at(I) == '<')
|
||||
++Balance;
|
||||
++I;
|
||||
} while (Balance > 0);
|
||||
return Snippet->substr(0, I);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
if (EnableFunctionArgSnippets)
|
||||
return *Snippet;
|
||||
|
||||
|
|
|
@ -3114,10 +3114,13 @@ TEST(CompletionTest, FunctionArgsExist) {
|
|||
Contains(AllOf(Labeled("Container<typename T>(int Size)"),
|
||||
SnippetSuffix("<${1:typename T}>(${2:int Size})"),
|
||||
Kind(CompletionItemKind::Constructor))));
|
||||
// FIXME(kirillbobyrev): It would be nice to still produce the template
|
||||
// snippet part: in this case it should be "<${1:typename T}>".
|
||||
EXPECT_THAT(
|
||||
completions(Context + "Container c = Cont^()", {}, Opts).Completions,
|
||||
Contains(AllOf(Labeled("Container<typename T>(int Size)"),
|
||||
SnippetSuffix("<${1:typename T}>"),
|
||||
Kind(CompletionItemKind::Constructor))));
|
||||
EXPECT_THAT(
|
||||
completions(Context + "Container c = Cont^<int>()", {}, Opts).Completions,
|
||||
Contains(AllOf(Labeled("Container<typename T>(int Size)"),
|
||||
SnippetSuffix(""),
|
||||
Kind(CompletionItemKind::Constructor))));
|
||||
|
|
Loading…
Reference in New Issue