zyounan created this revision.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan added reviewers: nridge, kadircet.
zyounan published this revision for review.
zyounan added inline comments.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.


================
Comment at: clang-tools-extra/clangd/CodeCompletionStrings.cpp:130
+      return false;
+    return true;
+  }();
----------------
I was cringed that if we should refine the logic based on `CursorKind`: It is 
from libclang; The meaning is sometimes kind of opaque (to me, I don't know it 
very clearly TBH) like `CXCursor_NotImplemented`...


We have a workaround from D128621 <https://reviews.llvm.org/D128621> that makes 
$0 no longer being
a placeholder to conform a vscode feature. However, we have to
refine the logic as it may suppress the last parameter placeholder
for constructor of base class because not all patterns of completion
are compound statements.

This fixes clangd/clangd#1479


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  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
@@ -3450,6 +3450,22 @@
   EXPECT_THAT(Results.Completions,
               Contains(AllOf(named("while_foo"),
                              snippetSuffix("(${1:int a}, ${2:int b})"))));
+
+  Results = completions(R"cpp(
+    struct Base {
+      Base(int a, int b) {}
+    };
+
+    struct Derived : Base {
+      Derived() : Base^
+    };
+  )cpp",
+                        /*IndexSymbols=*/{}, Options);
+  // Constructors from base classes are a kind of pattern that shouldn't end
+  // with $0.
+  EXPECT_THAT(Results.Completions,
+              Contains(AllOf(named("Base"),
+                             snippetSuffix("(${1:int a}, ${2:int b})"))));
 }
 
 TEST(CompletionTest, WorksWithNullType) {
Index: clang-tools-extra/clangd/CodeCompletionStrings.h
===================================================================
--- clang-tools-extra/clangd/CodeCompletionStrings.h
+++ clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -47,7 +47,8 @@
 void getSignature(const CodeCompletionString &CCS, std::string *Signature,
                   std::string *Snippet,
                   std::string *RequiredQualifiers = nullptr,
-                  bool CompletingPattern = false);
+                  bool CompletingPattern = false,
+                  const CodeCompletionResult *CCR = nullptr);
 
 /// Assembles formatted documentation for a completion result. This includes
 /// documentation comments and other relevant information like annotations.
Index: clang-tools-extra/clangd/CodeCompletionStrings.cpp
===================================================================
--- clang-tools-extra/clangd/CodeCompletionStrings.cpp
+++ clang-tools-extra/clangd/CodeCompletionStrings.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CodeCompletionStrings.h"
+#include "clang-c/Index.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RawCommentList.h"
 #include "clang/Basic/SourceManager.h"
@@ -96,7 +97,7 @@
 
 void getSignature(const CodeCompletionString &CCS, std::string *Signature,
                   std::string *Snippet, std::string *RequiredQualifiers,
-                  bool CompletingPattern) {
+                  bool CompletingPattern, const CodeCompletionResult *CCR) {
   // Placeholder with this index will be ${0:…} to mark final cursor position.
   // Usually we do not add $0, so the cursor is placed at end of completed text.
   unsigned CursorSnippetArg = std::numeric_limits<unsigned>::max();
@@ -111,6 +112,23 @@
           return C.Kind == CodeCompletionString::CK_Placeholder;
         });
   }
+  // If the result kind of CCR is `RK_Pattern`, it doesn't always mean we're
+  // completing a chunk of statements.  Constructors defined in base class, for
+  // example, are considered as a type of pattern, with the cursor type set to
+  // CXCursor_Constructor.
+  // We have to discriminate these cases manually in order to avoid providing
+  // incorrect placeholder `$0` which should have been a normal parameter.
+  bool ShouldPatchPlaceholder0 = CompletingPattern && [CCR] {
+    if (!CCR)
+      return true;
+    // The process of CCR construction employs `clang::getCursorKindForDecl` to
+    // obtain cursor kind for Decls, otherwise CursorKind would be set by
+    // constructor. Note that the default value is CXCursor_NotImplemented.
+    if (CCR->CursorKind == CXCursorKind::CXCursor_Constructor ||
+        CCR->CursorKind == CXCursorKind::CXCursor_Destructor)
+      return false;
+    return true;
+  }();
   unsigned SnippetArg = 0;
   bool HadObjCArguments = false;
   bool HadInformativeChunks = false;
@@ -185,14 +203,14 @@
       *Snippet += Chunk.Text;
       break;
     case CodeCompletionString::CK_Optional:
-      assert(Chunk.Optional);      
+      assert(Chunk.Optional);
       // No need to create placeholders for default arguments in Snippet.
       appendOptionalChunk(*Chunk.Optional, Signature);
       break;
     case CodeCompletionString::CK_Placeholder:
       *Signature += Chunk.Text;
       ++SnippetArg;
-      if (SnippetArg == CursorSnippetArg) {
+      if (SnippetArg == CursorSnippetArg && ShouldPatchPlaceholder0) {
         // We'd like to make $0 a placeholder too, but vscode does not support
         // this (https://github.com/microsoft/vscode/issues/152837).
         *Snippet += "$0";
Index: clang-tools-extra/clangd/CodeComplete.cpp
===================================================================
--- clang-tools-extra/clangd/CodeComplete.cpp
+++ clang-tools-extra/clangd/CodeComplete.cpp
@@ -438,7 +438,7 @@
     if (C.SemaResult) {
       bool IsPattern = C.SemaResult->Kind == CodeCompletionResult::RK_Pattern;
       getSignature(*SemaCCS, &S.Signature, &S.SnippetSuffix,
-                   &Completion.RequiredQualifier, IsPattern);
+                   &Completion.RequiredQualifier, IsPattern, C.SemaResult);
       if (!C.SemaResult->FunctionCanBeCall)
         S.SnippetSuffix.clear();
       S.ReturnType = getReturnType(*SemaCCS);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to