[PATCH] D89870: [clangd] Drop template argument lists from completions followed by <

Kirill Bobyrev via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 21 04:22:43 PDT 2020


kbobyrev created this revision.
kbobyrev added a reviewer: sammccall.
Herald added subscribers: cfe-commits, usaxena95, kadircet, arphaman.
Herald added a project: clang.
kbobyrev requested review of this revision.
Herald added subscribers: MaskRay, ilya-biryukov.

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 <https://reviews.llvm.org/D81380>.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89870

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp


Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -2979,6 +2979,8 @@
       Container(int Size) {}
     };
   )cpp";
+  // FIXME(kirillbobyrev): Also strip prefix of identifier token before the
+  // cursor from completion item ("fo" in this case).
   EXPECT_THAT(completions(Context + "int y = fo^", {}, Opts).Completions,
               UnorderedElementsAre(
                   AllOf(Labeled("foo(int A)"), SnippetSuffix("(${1:int A})"))));
@@ -3006,10 +3008,13 @@
       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))));
Index: clang-tools-extra/clangd/CodeComplete.cpp
===================================================================
--- clang-tools-extra/clangd/CodeComplete.cpp
+++ clang-tools-extra/clangd/CodeComplete.cpp
@@ -433,13 +433,29 @@
   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>();
+    // 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 (Snippet && (Completion.Kind == CompletionItemKind::Function ||
+                    Completion.Kind == CompletionItemKind::Method ||
+                    Completion.Kind == CompletionItemKind::Constructor)) {
+      // Potentially followed by argument list.
+      if (NextTokenKind == tok::l_paren) {
+        // If snippet contains template arguments we will emit them and drop
+        // function arguments.
+        if (Snippet->front() == '<')
+          return Snippet->substr(0, Snippet->find('('));
+        return "";
+      }
+      // If there is a potential template argument list, drop snippet. Ideally,
+      // this could generate an edit that would paste function arguments after
+      // template argument list but it would be complicated.
+      if (NextTokenKind == tok::less && Snippet->front() == '<')
+        return "";
+    }
     if (!Snippet)
       // All bundles are function calls.
       // FIXME(ibiryukov): sometimes add template arguments to a snippet, e.g.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D89870.299638.patch
Type: text/x-patch
Size: 3648 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20201021/932c9ff5/attachment.bin>


More information about the cfe-commits mailing list