[clangd] Add parantheses while auto-completing functions.
authorKadir Cetinkaya <kadircet@google.com>
Fri, 17 Aug 2018 15:42:54 +0000 (15:42 +0000)
committerKadir Cetinkaya <kadircet@google.com>
Fri, 17 Aug 2018 15:42:54 +0000 (15:42 +0000)
Summary:
Currently we only add parantheses to the functions if snippets are
enabled, which also inserts snippets for parameters into parantheses. Adding a
new option to put only parantheses. Also it moves the cursor within parantheses
or at the end of them by looking at whether completion item has any parameters
or not. Still requires snippets support on the client side.

Reviewers: ioeric, ilya-biryukov, hokein

Reviewed By: ioeric

Subscribers: MaskRay, jkorous, arphaman, cfe-commits

Differential Revision: https://reviews.llvm.org/D50835

llvm-svn: 340040

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

index 36d0f21..df438b4 100644 (file)
@@ -1413,8 +1413,17 @@ CompletionItem CodeCompletion::render(const CodeCompleteOptions &Opts) const {
       LSP.additionalTextEdits.push_back(FixIt);
     }
   }
-  if (Opts.EnableSnippets)
-    LSP.textEdit->newText += SnippetSuffix;
+  if (Opts.EnableSnippets && !SnippetSuffix.empty()) {
+    if (!Opts.EnableFunctionArgSnippets &&
+        ((Kind == CompletionItemKind::Function) ||
+         (Kind == CompletionItemKind::Method)) &&
+        (SnippetSuffix.front() == '(') && (SnippetSuffix.back() == ')'))
+      // Check whether function has any parameters or not.
+      LSP.textEdit->newText += SnippetSuffix.size() > 2 ? "(${0})" : "()";
+    else
+      LSP.textEdit->newText += SnippetSuffix;
+  }
+
   // FIXME(kadircet): Do not even fill insertText after making sure textEdit is
   // compatible with most of the editors.
   LSP.insertText = LSP.textEdit->newText;
index 9ef2b1f..1d85a66 100644 (file)
@@ -82,6 +82,10 @@ struct CodeCompleteOptions {
   /// Include completions that require small corrections, e.g. change '.' to
   /// '->' on member access etc.
   bool IncludeFixIts = false;
+
+  /// Whether to generate snippets for function arguments on code-completion.
+  /// Needs snippets to be enabled as well.
+  bool EnableFunctionArgSnippets = true;
 };
 
 // Semi-structured representation of a code-complete suggestion for our C++ API.
index 5933bb5..3fce866 100644 (file)
@@ -1648,6 +1648,58 @@ TEST(SignatureHelpTest, IndexDocumentation) {
                         SigDoc("Doc from sema"))));
 }
 
+TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) {
+  CodeCompleteOptions Opts;
+  Opts.EnableFunctionArgSnippets = true;
+  {
+    CodeCompletion C;
+    C.RequiredQualifier = "Foo::";
+    C.Name = "x";
+    C.SnippetSuffix = "()";
+
+    auto R = C.render(Opts);
+    EXPECT_EQ(R.textEdit->newText, "Foo::x");
+    EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);
+  }
+
+  Opts.EnableSnippets = true;
+  Opts.EnableFunctionArgSnippets = false;
+  {
+    CodeCompletion C;
+    C.RequiredQualifier = "Foo::";
+    C.Name = "x";
+    C.SnippetSuffix = "";
+
+    auto R = C.render(Opts);
+    EXPECT_EQ(R.textEdit->newText, "Foo::x");
+    EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
+  }
+
+  {
+    CodeCompletion C;
+    C.RequiredQualifier = "Foo::";
+    C.Name = "x";
+    C.SnippetSuffix = "()";
+    C.Kind = CompletionItemKind::Method;
+
+    auto R = C.render(Opts);
+    EXPECT_EQ(R.textEdit->newText, "Foo::x()");
+    EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
+  }
+
+  {
+    CodeCompletion C;
+    C.RequiredQualifier = "Foo::";
+    C.Name = "x";
+    C.SnippetSuffix = "(${0:bool})";
+    C.Kind = CompletionItemKind::Function;
+
+    auto R = C.render(Opts);
+    EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})");
+    EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
+  }
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang