https://github.com/etyloppihacilem updated 
https://github.com/llvm/llvm-project/pull/165916

>From 6e39a3193ce99043946d34c87cfdc0574097147d Mon Sep 17 00:00:00 2001
From: Hippolyte Melica <[email protected]>
Date: Fri, 31 Oct 2025 12:08:07 +0100
Subject: [PATCH] [clangd] Autocomplete fixes for methods and arguments

---
 clang-tools-extra/clangd/CodeComplete.cpp     |   1 +
 .../clangd/CodeCompletionStrings.cpp          |  84 +++++++++-----
 .../clangd/CodeCompletionStrings.h            |   1 +
 .../clangd/unittests/CodeCompleteTests.cpp    | 107 ++++++++++++++----
 .../unittests/CodeCompletionStringsTests.cpp  |  30 ++++-
 clang/include/clang/Parse/Parser.h            |  26 ++++-
 .../include/clang/Sema/CodeCompleteConsumer.h |  14 ++-
 clang/include/clang/Sema/SemaCodeCompletion.h |  10 +-
 clang/lib/Parse/ParseExpr.cpp                 |   5 +-
 clang/lib/Parse/ParseExprCXX.cpp              |   5 +-
 clang/lib/Parse/Parser.cpp                    |  10 +-
 clang/lib/Sema/CodeCompleteConsumer.cpp       |  13 +++
 clang/lib/Sema/SemaCodeComplete.cpp           |  84 ++++++++++----
 clang/tools/libclang/CIndexCodeCompletion.cpp |   4 +
 14 files changed, 306 insertions(+), 88 deletions(-)

diff --git a/clang-tools-extra/clangd/CodeComplete.cpp 
b/clang-tools-extra/clangd/CodeComplete.cpp
index f43b5e71a1dfa..907fac0c2c9bf 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -480,6 +480,7 @@ struct CodeCompletionBuilder {
       getSignature(*SemaCCS, &S.Signature, &S.SnippetSuffix, 
C.SemaResult->Kind,
                    C.SemaResult->CursorKind,
                    
/*IncludeFunctionArguments=*/C.SemaResult->FunctionCanBeCall,
+                   /*IsDefinition=*/C.SemaResult->DeclaringEntity,
                    /*RequiredQualifiers=*/&Completion.RequiredQualifier);
       S.ReturnType = getReturnType(*SemaCCS);
       if (C.SemaResult->Kind == CodeCompletionResult::RK_Declaration)
diff --git a/clang-tools-extra/clangd/CodeCompletionStrings.cpp 
b/clang-tools-extra/clangd/CodeCompletionStrings.cpp
index 9c4241b54057a..7f5680e804c41 100644
--- a/clang-tools-extra/clangd/CodeCompletionStrings.cpp
+++ b/clang-tools-extra/clangd/CodeCompletionStrings.cpp
@@ -39,16 +39,29 @@ void appendEscapeSnippet(const llvm::StringRef Text, 
std::string *Out) {
   }
 }
 
-void appendOptionalChunk(const CodeCompletionString &CCS, std::string *Out) {
+/// Removes the value for defaults arguments.
+static void addWithoutValue(std::string *Out, const std::string &ToAdd) {
+  size_t Val = ToAdd.find('=');
+  if (Val != ToAdd.npos)
+    *Out += ToAdd.substr(0, Val - 1); // removing value in definition
+  else
+    *Out += ToAdd;
+}
+
+void appendOptionalChunk(const CodeCompletionString &CCS, std::string *Out,
+                         bool RemoveValues = false) {
   for (const CodeCompletionString::Chunk &C : CCS) {
     switch (C.Kind) {
     case CodeCompletionString::CK_Optional:
       assert(C.Optional &&
              "Expected the optional code completion string to be non-null.");
-      appendOptionalChunk(*C.Optional, Out);
+      appendOptionalChunk(*C.Optional, Out, RemoveValues);
       break;
     default:
-      *Out += C.Text;
+      if (RemoveValues)
+        addWithoutValue(Out, C.Text);
+      else
+        *Out += C.Text;
       break;
     }
   }
@@ -164,7 +177,7 @@ void getSignature(const CodeCompletionString &CCS, 
std::string *Signature,
                   std::string *Snippet,
                   CodeCompletionResult::ResultKind ResultKind,
                   CXCursorKind CursorKind, bool IncludeFunctionArguments,
-                  std::string *RequiredQualifiers) {
+                  bool IsDefinition, std::string *RequiredQualifiers) {
   // 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();
@@ -184,8 +197,8 @@ void getSignature(const CodeCompletionString &CCS, 
std::string *Signature,
   unsigned SnippetArg = 0;
   bool HadObjCArguments = false;
   bool HadInformativeChunks = false;
+  int IsTemplateArgument = 0;
 
-  std::optional<unsigned> TruncateSnippetAt;
   for (const auto &Chunk : CCS) {
     // Informative qualifier chunks only clutter completion results, skip
     // them.
@@ -252,26 +265,38 @@ void getSignature(const CodeCompletionString &CCS, 
std::string *Signature,
         }
       }
       break;
-    case CodeCompletionString::CK_Text:
+    case CodeCompletionString::CK_FunctionQualifier:
+      if (IsDefinition) // Only for definition
+        *Snippet += Chunk.Text;
       *Signature += Chunk.Text;
+      break;
+    case CodeCompletionString::CK_Text:
       *Snippet += Chunk.Text;
+      *Signature += Chunk.Text;
       break;
     case CodeCompletionString::CK_Optional:
       assert(Chunk.Optional);
       // No need to create placeholders for default arguments in Snippet.
       appendOptionalChunk(*Chunk.Optional, Signature);
+      // complete args without default value in definition
+      if (IsDefinition)
+        appendOptionalChunk(*Chunk.Optional, Snippet, /*RemoveValues=*/true);
       break;
     case CodeCompletionString::CK_Placeholder:
       *Signature += Chunk.Text;
-      ++SnippetArg;
-      if (SnippetArg == CursorSnippetArg) {
-        // We'd like to make $0 a placeholder too, but vscode does not support
-        // this (https://github.com/microsoft/vscode/issues/152837).
-        *Snippet += "$0";
-      } else {
-        *Snippet += "${" + std::to_string(SnippetArg) + ':';
-        appendEscapeSnippet(Chunk.Text, Snippet);
-        *Snippet += '}';
+      if (IncludeFunctionArguments) {
+        ++SnippetArg;
+        if (SnippetArg == CursorSnippetArg) {
+          // We'd like to make $0 a placeholder too, but vscode does not 
support
+          // this (https://github.com/microsoft/vscode/issues/152837).
+          *Snippet += "$0";
+        } else {
+          *Snippet += "${" + std::to_string(SnippetArg) + ':';
+          appendEscapeSnippet(Chunk.Text, Snippet);
+          *Snippet += '}';
+        }
+      } else if (IsDefinition) { // completion without snippets
+        *Snippet += Chunk.Text;
       }
       break;
     case CodeCompletionString::CK_Informative:
@@ -290,28 +315,35 @@ void getSignature(const CodeCompletionString &CCS, 
std::string *Signature,
       llvm_unreachable("Unexpected CK_CurrentParameter while collecting "
                        "CompletionItems");
       break;
+    case CodeCompletionString::CK_LeftAngle:
+      // Do not add template arguments in address of a function
+      if (IsDefinition || IncludeFunctionArguments) {
+        IsTemplateArgument++;
+        *Snippet += Chunk.Text;
+      }
+      *Signature += Chunk.Text;
+      break;
+    case CodeCompletionString::CK_RightAngle:
+      if (IsDefinition || IncludeFunctionArguments || IsTemplateArgument) {
+        IsTemplateArgument--;
+        *Snippet += Chunk.Text;
+      }
+      *Signature += Chunk.Text;
+      break;
     case CodeCompletionString::CK_LeftParen:
-      // We're assuming that a LeftParen in a declaration starts a function
-      // call, and arguments following the parenthesis could be discarded if
-      // IncludeFunctionArguments is false.
-      if (!IncludeFunctionArguments &&
-          ResultKind == CodeCompletionResult::RK_Declaration)
-        TruncateSnippetAt.emplace(Snippet->size());
-      [[fallthrough]];
     case CodeCompletionString::CK_RightParen:
     case CodeCompletionString::CK_LeftBracket:
     case CodeCompletionString::CK_RightBracket:
     case CodeCompletionString::CK_LeftBrace:
     case CodeCompletionString::CK_RightBrace:
-    case CodeCompletionString::CK_LeftAngle:
-    case CodeCompletionString::CK_RightAngle:
     case CodeCompletionString::CK_Comma:
     case CodeCompletionString::CK_Colon:
     case CodeCompletionString::CK_SemiColon:
     case CodeCompletionString::CK_Equal:
     case CodeCompletionString::CK_HorizontalSpace:
       *Signature += Chunk.Text;
-      *Snippet += Chunk.Text;
+      if (IncludeFunctionArguments || IsDefinition || IsTemplateArgument)
+        *Snippet += Chunk.Text;
       break;
     case CodeCompletionString::CK_VerticalSpace:
       *Snippet += Chunk.Text;
@@ -319,8 +351,6 @@ void getSignature(const CodeCompletionString &CCS, 
std::string *Signature,
       break;
     }
   }
-  if (TruncateSnippetAt)
-    *Snippet = Snippet->substr(0, *TruncateSnippetAt);
 }
 
 std::string formatDocumentation(const CodeCompletionString &CCS,
diff --git a/clang-tools-extra/clangd/CodeCompletionStrings.h 
b/clang-tools-extra/clangd/CodeCompletionStrings.h
index fa81ad64d406c..baad1346c4c20 100644
--- a/clang-tools-extra/clangd/CodeCompletionStrings.h
+++ b/clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -53,6 +53,7 @@ void getSignature(const CodeCompletionString &CCS, 
std::string *Signature,
                   std::string *Snippet,
                   CodeCompletionResult::ResultKind ResultKind,
                   CXCursorKind CursorKind, bool IncludeFunctionArguments = 
true,
+                  bool IsDefinition = false,
                   std::string *RequiredQualifiers = nullptr);
 
 /// Assembles formatted documentation for a completion result. This includes
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp 
b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 267910b571279..946a9995261de 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -531,19 +531,23 @@ TEST(CompletionTest, 
HeuristicsForMemberFunctionCompletion) {
 
   Annotations Code(R"cpp(
       struct Foo {
-        static int staticMethod(int);
-        int method(int) const;
+        static int staticMethod(int name);
+        int method(int name) const;
         template <typename T, typename U, typename V = int>
-        T generic(U, V);
+        T generic(U nameU, V nameV);
         template <typename T, int U>
         static T staticGeneric();
         Foo() {
-          this->$canBeCall^
+          this->$canBeCallNoStatic^
           $canBeCall^
           Foo::$canBeCall^
         }
       };
 
+      int Foo::$isDefinition^ {
+      }
+      ;
+
       struct Derived : Foo {
         using Foo::method;
         using Foo::generic;
@@ -553,12 +557,13 @@ TEST(CompletionTest, 
HeuristicsForMemberFunctionCompletion) {
       };
 
       struct OtherClass {
-        OtherClass() {
+        OthrClass() {
           Foo f;
           Derived d;
-          f.$canBeCall^
+          f.$canBeCallNoStatic^
           ; // Prevent parsing as 'f.f'
           f.Foo::$canBeCall^
+          ; // Prevent parsing as 'f.f'
           &Foo::$canNotBeCall^
           ;
           d.Foo::$canBeCall^
@@ -573,6 +578,7 @@ TEST(CompletionTest, HeuristicsForMemberFunctionCompletion) 
{
         f.$canBeCall^
         ; // Prevent parsing as 'f.f'
         f.Foo::$canBeCall^
+        ; // Prevent parsing as 'f.f'
         &Foo::$canNotBeCall^
         ;
         d.Foo::$canBeCall^
@@ -585,39 +591,94 @@ TEST(CompletionTest, 
HeuristicsForMemberFunctionCompletion) {
   for (const auto &P : Code.points("canNotBeCall")) {
     auto Results = completions(TU, P, /*IndexSymbols*/ {}, Opts);
     EXPECT_THAT(Results.Completions,
-                Contains(AllOf(named("method"), signature("(int) const"),
+                Contains(AllOf(named("method"), signature("(int name) const"),
                                snippetSuffix(""))));
-    // We don't have any arguments to deduce against if this isn't a call.
-    // Thus, we should emit these deducible template arguments explicitly.
     EXPECT_THAT(
         Results.Completions,
         Contains(AllOf(named("generic"),
-                       signature("<typename T, typename U>(U, V)"),
-                       snippetSuffix("<${1:typename T}, ${2:typename U}>"))));
+                       signature("<typename T, typename U>(U nameU, V nameV)"),
+                       snippetSuffix(""))));
+    EXPECT_THAT(Results.Completions,
+                Contains(AllOf(named("staticMethod"), signature("(int name)"),
+                               snippetSuffix(""))));
+    EXPECT_THAT(
+        Results.Completions,
+        Contains(AllOf(named("staticGeneric"),
+                       signature("<typename T, int U>()"), 
snippetSuffix(""))));
   }
 
   for (const auto &P : Code.points("canBeCall")) {
     auto Results = completions(TU, P, /*IndexSymbols*/ {}, Opts);
     EXPECT_THAT(Results.Completions,
-                Contains(AllOf(named("method"), signature("(int) const"),
-                               snippetSuffix("(${1:int})"))));
+                Contains(AllOf(named("method"), signature("(int name) const"),
+                               snippetSuffix("(${1:int name})"))));
     EXPECT_THAT(
         Results.Completions,
-        Contains(AllOf(named("generic"), signature("<typename T>(U, V)"),
-                       snippetSuffix("<${1:typename T}>(${2:U}, ${3:V})"))));
-  }
-
-  // static method will always keep the snippet
-  for (const auto &P : Code.points()) {
-    auto Results = completions(TU, P, /*IndexSymbols*/ {}, Opts);
+        Contains(AllOf(
+            named("generic"), signature("<typename T>(U nameU, V nameV)"),
+            snippetSuffix("<${1:typename T}>(${2:U nameU}, ${3:V nameV})"))));
     EXPECT_THAT(Results.Completions,
-                Contains(AllOf(named("staticMethod"), signature("(int)"),
-                               snippetSuffix("(${1:int})"))));
+                Contains(AllOf(named("staticMethod"), signature("(int name)"),
+                               snippetSuffix("(${1:int name})"))));
     EXPECT_THAT(Results.Completions,
                 Contains(AllOf(
                     named("staticGeneric"), signature("<typename T, int U>()"),
                     snippetSuffix("<${1:typename T}, ${2:int U}>()"))));
   }
+
+  for (const auto &P : Code.points("canBeCallNoStatic")) {
+    auto Results = completions(TU, P, /*IndexSymbols*/ {}, Opts);
+    EXPECT_THAT(Results.Completions,
+                Contains(AllOf(named("method"), signature("(int name) const"),
+                               snippetSuffix("(${1:int name})"))));
+    EXPECT_THAT(
+        Results.Completions,
+        Contains(AllOf(
+            named("generic"), signature("<typename T>(U nameU, V nameV)"),
+            snippetSuffix("<${1:typename T}>(${2:U nameU}, ${3:V nameV})"))));
+  }
+
+  for (const auto &P : Code.points("isDefinition")) {
+    auto Results = completions(TU, P, /*IndexSymbols*/ {}, Opts);
+
+    EXPECT_THAT(Results.Completions,
+                Contains(AllOf(named("method"), signature("(int name) const"),
+                               snippetSuffix("(int name) const"))));
+    EXPECT_THAT(
+        Results.Completions,
+        Contains(AllOf(
+            named("generic"),
+            signature("<typename T, typename U>(U nameU, V nameV)"),
+            snippetSuffix("<typename T, typename U>(U nameU, V nameV)"))));
+    EXPECT_THAT(Results.Completions,
+                Contains(AllOf(named("staticMethod"), signature("(int name)"),
+                               snippetSuffix("(int name)"))));
+    EXPECT_THAT(Results.Completions,
+                Contains(AllOf(named("staticGeneric"),
+                               signature("<typename T, int U>()"),
+                               snippetSuffix("<typename T, int U>()"))));
+  }
+}
+
+TEST(CompletionTest, DefaultArgsWithValues) {
+  clangd::CodeCompleteOptions Opts;
+  Opts.EnableSnippets = true;
+  auto Results = completions(
+      R"cpp(
+    struct Arg {
+        Arg(int a, int b);
+    };
+    struct Foo {
+      void foo(int x = 42, int y = 0, Arg arg = Arg(42,  0));
+    };
+    void Foo::foo^
+  )cpp",
+      /*IndexSymbols=*/{}, Opts);
+  EXPECT_THAT(Results.Completions,
+              Contains(AllOf(
+                  named("foo"),
+                  signature("(int x = 42, int y = 0, Arg arg = Arg(42,  0))"),
+                  snippetSuffix("(int x, int y, Arg arg)"))));
 }
 
 TEST(CompletionTest, NoSnippetsInUsings) {
@@ -4490,7 +4551,7 @@ TEST(CompletionTest, SkipExplicitObjectParameter) {
     EXPECT_THAT(
         Result.Completions,
         ElementsAre(AllOf(named("foo"), signature("<class self:auto>(int 
arg)"),
-                          snippetSuffix("<${1:class self:auto}>"))));
+                          snippetSuffix(""))));
   }
   {
     auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"),
diff --git a/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp 
b/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
index de5f533d31645..019768f969992 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
@@ -26,12 +26,14 @@ class CompletionStringTest : public ::testing::Test {
   void computeSignature(const CodeCompletionString &CCS,
                         CodeCompletionResult::ResultKind ResultKind =
                             CodeCompletionResult::ResultKind::RK_Declaration,
-                        bool IncludeFunctionArguments = true) {
+                        bool IncludeFunctionArguments = true,
+                        bool IsDeclaration = false) {
     Signature.clear();
     Snippet.clear();
     getSignature(CCS, &Signature, &Snippet, ResultKind,
                  /*CursorKind=*/CXCursorKind::CXCursor_NotImplemented,
                  /*IncludeFunctionArguments=*/IncludeFunctionArguments,
+                 /*IsDeclaration=*/IsDeclaration,
                  /*RequiredQualifiers=*/nullptr);
   }
 
@@ -158,6 +160,28 @@ TEST_F(CompletionStringTest, SnippetsInPatterns) {
   EXPECT_EQ(Snippet, " ${1:name} = $0;");
 }
 
+TEST_F(CompletionStringTest, DropFunctionPlaceholders) {
+  Builder.AddTypedTextChunk("foo");
+  Builder.AddChunk(CodeCompletionString::CK_LeftAngle);
+  Builder.AddPlaceholderChunk("typename T");
+  Builder.AddChunk(CodeCompletionString::CK_Comma);
+  Builder.AddPlaceholderChunk("int U");
+  Builder.AddChunk(CodeCompletionString::CK_RightAngle);
+  Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+  Builder.AddPlaceholderChunk("arg1");
+  Builder.AddChunk(CodeCompletionString::CK_Comma);
+  Builder.AddPlaceholderChunk("arg2");
+  Builder.AddChunk(CodeCompletionString::CK_RightParen);
+
+  computeSignature(
+      *Builder.TakeString(),
+      /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Declaration,
+      /*IncludeFunctionArguments=*/false, /*IsDeclaration=*/true);
+  // Arguments placeholders dropped from snippet, kept in signature.
+  EXPECT_EQ(Signature, "<typename T, int U>(arg1, arg2)");
+  EXPECT_EQ(Snippet, "<typename T, int U>(arg1, arg2)");
+}
+
 TEST_F(CompletionStringTest, DropFunctionArguments) {
   Builder.AddTypedTextChunk("foo");
   Builder.AddChunk(CodeCompletionString::CK_LeftAngle);
@@ -174,10 +198,10 @@ TEST_F(CompletionStringTest, DropFunctionArguments) {
   computeSignature(
       *Builder.TakeString(),
       /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Declaration,
-      /*IncludeFunctionArguments=*/false);
+      /*IncludeFunctionArguments=*/false, /*IsDeclaration=*/false);
   // Arguments dropped from snippet, kept in signature.
   EXPECT_EQ(Signature, "<typename T, int U>(arg1, arg2)");
-  EXPECT_EQ(Snippet, "<${1:typename T}, ${2:int U}>");
+  EXPECT_EQ(Snippet, "");
 }
 
 TEST_F(CompletionStringTest, IgnoreInformativeQualifier) {
diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index f7e7b0ec51d80..3a4f4ef13c809 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -355,7 +355,14 @@ class Parser : public CodeCompletionHandler {
   /// are invalid.
   bool
   TryAnnotateTypeOrScopeToken(ImplicitTypenameContext AllowImplicitTypename =
-                                  ImplicitTypenameContext::No);
+                                  ImplicitTypenameContext::No,
+                              bool isAddressOfOperand = false);
+
+  bool TryAnnotateTypeOrScopeToken(bool isAddressOfOperand) {
+    return TryAnnotateTypeOrScopeToken(
+        /*AllowImplicitTypename=*/ImplicitTypenameContext::No,
+        /*isAddressOfOperand=*/isAddressOfOperand);
+  }
 
   /// Try to annotate a type or scope token, having already parsed an
   /// optional scope specifier. \p IsNewScope should be \c true unless the 
scope
@@ -4566,7 +4573,22 @@ class Parser : public CodeCompletionHandler {
       bool EnteringContext, bool *MayBePseudoDestructor = nullptr,
       bool IsTypename = false, const IdentifierInfo **LastII = nullptr,
       bool OnlyNamespace = false, bool InUsingDeclaration = false,
-      bool Disambiguation = false);
+      bool Disambiguation = false, bool isAddressOfOperand = false);
+
+  bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType,
+                                      bool ObjectHasErrors,
+                                      bool EnteringContext,
+                                      bool isAddressOfOperand) {
+    return ParseOptionalCXXScopeSpecifier(
+        SS, ObjectType, ObjectHasErrors, EnteringContext,
+        /*MayBePseudoDestructor=*/nullptr,
+        /*IsTypename=*/false,
+        /*LastII=*/nullptr,
+        /*OnlyNamespace=*/false,
+        /*InUsingDeclaration=*/false,
+        /*Disambiguation=*/false,
+        /*isAddressOfOperand=*/isAddressOfOperand);
+  }
 
   
//===--------------------------------------------------------------------===//
   // C++11 5.1.2: Lambda expressions
diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h 
b/clang/include/clang/Sema/CodeCompleteConsumer.h
index c26f4e33d289c..37821bfb51cda 100644
--- a/clang/include/clang/Sema/CodeCompleteConsumer.h
+++ b/clang/include/clang/Sema/CodeCompleteConsumer.h
@@ -473,6 +473,12 @@ class CodeCompletionString {
     /// A piece of text that describes something about the result but
     /// should not be inserted into the buffer.
     CK_Informative,
+
+    /// A piece of text that holds function qualifiers. Should be inserted
+    /// into the buffer only in definition, not on call.
+    /// e.g. const for a function or a method.
+    CK_FunctionQualifier,
+
     /// A piece of text that describes the type of an entity or, for
     /// functions and methods, the return type.
     CK_ResultType,
@@ -534,7 +540,7 @@ class CodeCompletionString {
 
     union {
       /// The text string associated with a CK_Text, CK_Placeholder,
-      /// CK_Informative, or CK_Comma chunk.
+      /// CK_Informative, CK_FunctionQualifier, or CK_Comma chunk.
       /// The string is owned by the chunk and will be deallocated
       /// (with delete[]) when the chunk is destroyed.
       const char *Text;
@@ -561,6 +567,9 @@ class CodeCompletionString {
     /// Create a new informative chunk.
     static Chunk CreateInformative(const char *Informative);
 
+    /// Create a new declaration informative chunk.
+    static Chunk CreateFunctionQualifier(const char *FunctionQualifier);
+
     /// Create a new result type chunk.
     static Chunk CreateResultType(const char *ResultType);
 
@@ -737,6 +746,9 @@ class CodeCompletionBuilder {
   /// Add a new informative chunk.
   void AddInformativeChunk(const char *Text);
 
+  /// Add a new function qualifier chunk.
+  void AddFunctionQualifierChunk(const char *Text);
+
   /// Add a new result-type chunk.
   void AddResultTypeChunk(const char *ResultType);
 
diff --git a/clang/include/clang/Sema/SemaCodeCompletion.h 
b/clang/include/clang/Sema/SemaCodeCompletion.h
index 3029e56e5cfe2..99888caad2d0c 100644
--- a/clang/include/clang/Sema/SemaCodeCompletion.h
+++ b/clang/include/clang/Sema/SemaCodeCompletion.h
@@ -101,9 +101,11 @@ class SemaCodeCompletion : public SemaBase {
                             bool AllowNestedNameSpecifiers);
 
   struct CodeCompleteExpressionData;
-  void CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData 
&Data);
+  void CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data,
+                              bool IsAddressOfOperand = false);
   void CodeCompleteExpression(Scope *S, QualType PreferredType,
-                              bool IsParenthesized = false);
+                              bool IsParenthesized = false,
+                              bool IsAddressOfOperand = false);
   void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase,
                                        SourceLocation OpLoc, bool IsArrow,
                                        bool IsBaseExprStatement,
@@ -156,8 +158,8 @@ class SemaCodeCompletion : public SemaBase {
   void CodeCompleteAfterIf(Scope *S, bool IsBracedThen);
 
   void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool 
EnteringContext,
-                               bool IsUsingDeclaration, QualType BaseType,
-                               QualType PreferredType);
+                               bool IsUsingDeclaration, bool 
IsAddressOfOperand,
+                               QualType BaseType, QualType PreferredType);
   void CodeCompleteUsing(Scope *S);
   void CodeCompleteUsingDirective(Scope *S);
   void CodeCompleteNamespaceDecl(Scope *S);
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 3515343202de1..ad597b5c47b68 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -902,7 +902,7 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool 
isAddressOfOperand,
                Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren,
                             tok::l_brace)) {
         // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
-        if (TryAnnotateTypeOrScopeToken())
+        if (TryAnnotateTypeOrScopeToken(isAddressOfOperand))
           return ExprError();
         if (!Tok.is(tok::identifier))
           return ParseCastExpression(ParseKind, isAddressOfOperand, 
NotCastExpr,
@@ -1527,7 +1527,8 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool 
isAddressOfOperand,
   case tok::code_completion: {
     cutOffParsing();
     Actions.CodeCompletion().CodeCompleteExpression(
-        getCurScope(), PreferredType.get(Tok.getLocation()));
+        getCurScope(), PreferredType.get(Tok.getLocation()),
+        /*IsParenthesized=*/false, /*IsAddressOfOperand=*/isAddressOfOperand);
     return ExprError();
   }
 #define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 7a5d28caf8521..c5bd375a5df3c 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -108,7 +108,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
     CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors,
     bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename,
     const IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration,
-    bool Disambiguation) {
+    bool Disambiguation, bool isAddressOfOperand) {
   assert(getLangOpts().CPlusPlus &&
          "Call sites of this function should be guarded by checking for C++");
 
@@ -237,7 +237,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
         // completion token follows the '::'.
         Actions.CodeCompletion().CodeCompleteQualifiedId(
             getCurScope(), SS, EnteringContext, InUsingDeclaration,
-            ObjectType.get(), SavedType.get(SS.getBeginLoc()));
+            isAddressOfOperand, ObjectType.get(),
+            SavedType.get(SS.getBeginLoc()));
         // Include code completion token into the range of the scope otherwise
         // when we try to annotate the scope tokens the dangling code 
completion
         // token will cause assertion in
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 8f6f023dd79d0..7f02d9c0bc296 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1884,7 +1884,7 @@ bool Parser::TryKeywordIdentFallback(bool DisableKeyword) 
{
 }
 
 bool Parser::TryAnnotateTypeOrScopeToken(
-    ImplicitTypenameContext AllowImplicitTypename) {
+    ImplicitTypenameContext AllowImplicitTypename, bool isAddressOfOperand) {
   assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
           Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) ||
           Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) ||
@@ -2000,9 +2000,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(
 
   CXXScopeSpec SS;
   if (getLangOpts().CPlusPlus)
-    if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
-                                       /*ObjectHasErrors=*/false,
-                                       /*EnteringContext*/ false))
+    if (ParseOptionalCXXScopeSpecifier(
+            SS, /*ObjectType=*/nullptr,
+            /*ObjectHasErrors=*/false,
+            /*EnteringContext*/ false,
+            /*isAddressOfOperand=*/isAddressOfOperand))
       return true;
 
   return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp 
b/clang/lib/Sema/CodeCompleteConsumer.cpp
index 50a552272f421..0a445b8f6f590 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -183,6 +183,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const 
char *Text)
   case CK_Text:
   case CK_Placeholder:
   case CK_Informative:
+  case CK_FunctionQualifier:
   case CK_ResultType:
   case CK_CurrentParameter:
     this->Text = Text;
@@ -272,6 +273,12 @@ CodeCompletionString::Chunk::CreateInformative(const char 
*Informative) {
   return Chunk(CK_Informative, Informative);
 }
 
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateFunctionQualifier(
+    const char *FunctionQualifier) {
+  return Chunk(CK_FunctionQualifier, FunctionQualifier);
+}
+
 CodeCompletionString::Chunk
 CodeCompletionString::Chunk::CreateResultType(const char *ResultType) {
   return Chunk(CK_ResultType, ResultType);
@@ -326,6 +333,7 @@ std::string CodeCompletionString::getAsString() const {
       OS << "<#" << C.Text << "#>";
       break;
     case CK_Informative:
+    case CK_FunctionQualifier:
     case CK_ResultType:
       OS << "[#" << C.Text << "#]";
       break;
@@ -461,6 +469,10 @@ void CodeCompletionBuilder::AddInformativeChunk(const char 
*Text) {
   Chunks.push_back(Chunk::CreateInformative(Text));
 }
 
+void CodeCompletionBuilder::AddFunctionQualifierChunk(const char *Text) {
+  Chunks.push_back(Chunk::CreateFunctionQualifier(Text));
+}
+
 void CodeCompletionBuilder::AddResultTypeChunk(const char *ResultType) {
   Chunks.push_back(Chunk::CreateResultType(ResultType));
 }
@@ -727,6 +739,7 @@ static std::string getOverloadAsString(const 
CodeCompletionString &CCS) {
   for (auto &C : CCS) {
     switch (C.Kind) {
     case CodeCompletionString::CK_Informative:
+    case CodeCompletionString::CK_FunctionQualifier:
     case CodeCompletionString::CK_ResultType:
       OS << "[#" << C.Text << "#]";
       break;
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp 
b/clang/lib/Sema/SemaCodeComplete.cpp
index aa93507ab5c30..48b39eeb1d632 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -325,7 +325,9 @@ class ResultBuilder {
   ///
   /// \param BaseExprType the object type in a member access expression,
   /// if any.
-  bool canFunctionBeCalled(const NamedDecl *ND, QualType BaseExprType) const;
+  bool canFunctionBeCalled(const NamedDecl *ND, QualType BaseExprType,
+                           bool IsBorrowedContext,
+                           bool IsAddressOfOperand) const;
 
   /// Decide whether or not a use of member function Decl can be a call.
   ///
@@ -369,7 +371,8 @@ class ResultBuilder {
   /// \param BaseExprType the type of expression that precedes the "." or "->"
   /// in a member access expression.
   void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
-                 bool InBaseClass, QualType BaseExprType);
+                 bool InBaseClass, QualType BaseExprType,
+                 bool IsBorrowedContext, bool IsAddressOfOperand);
 
   /// Add a new non-declaration result to this result set.
   void AddResult(Result R);
@@ -1342,7 +1345,13 @@ bool ResultBuilder::canCxxMethodBeCalled(const 
CXXMethodDecl *Method,
 }
 
 bool ResultBuilder::canFunctionBeCalled(const NamedDecl *ND,
-                                        QualType BaseExprType) const {
+                                        QualType BaseExprType,
+                                        bool IsBorrowedContext = false,
+                                        bool IsAddressOfOperand = false) const 
{
+  // If context is borrowed, it is always a declaration so function cannot be
+  // called. If we are waiting for the address of operand, it is not a call.
+  if (IsBorrowedContext || IsAddressOfOperand)
+    return false;
   // We apply heuristics only to CCC_Symbol:
   // * CCC_{Arrow,Dot}MemberAccess reflect member access expressions:
   //   f.method() and f->method(). These are always calls.
@@ -1365,7 +1374,9 @@ bool ResultBuilder::canFunctionBeCalled(const NamedDecl 
*ND,
 
 void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
                               NamedDecl *Hiding, bool InBaseClass = false,
-                              QualType BaseExprType = QualType()) {
+                              QualType BaseExprType = QualType(),
+                              bool IsBorrowedContext = false,
+                              bool IsAddressOfOperand = false) {
   if (R.Kind != Result::RK_Declaration) {
     // For non-declaration results, just add the result.
     Results.push_back(R);
@@ -1504,7 +1515,10 @@ void ResultBuilder::AddResult(Result R, DeclContext 
*CurContext,
         OverloadSet.Add(Method, Results.size());
       }
 
-  R.FunctionCanBeCall = canFunctionBeCalled(R.getDeclaration(), BaseExprType);
+  // if Context is borrowed, we are in a defintion, meaning not a call
+  R.FunctionCanBeCall = canFunctionBeCalled(
+      R.getDeclaration(), BaseExprType, IsBorrowedContext, IsAddressOfOperand);
+  R.DeclaringEntity = IsBorrowedContext;
 
   // Insert this result into the set of results.
   Results.push_back(R);
@@ -1762,7 +1776,8 @@ class CodeCompletionDeclConsumer : public 
VisibleDeclConsumer {
       QualType BaseType = QualType(),
       std::vector<FixItHint> FixIts = std::vector<FixItHint>())
       : Results(Results), InitialLookupCtx(InitialLookupCtx),
-        FixIts(std::move(FixIts)) {
+        FixIts(std::move(FixIts)), IsBorrowedContext(false),
+        IsAddressOfOperand(false) {
     NamingClass = llvm::dyn_cast<CXXRecordDecl>(InitialLookupCtx);
     // If BaseType was not provided explicitly, emulate implicit 'this->'.
     if (BaseType.isNull()) {
@@ -1777,13 +1792,22 @@ class CodeCompletionDeclConsumer : public 
VisibleDeclConsumer {
     this->BaseType = BaseType;
   }
 
+  void setIsBorrowedContext(bool isBorrowedContext) {
+    IsBorrowedContext = isBorrowedContext;
+  }
+
+  void setIsAddressOfOperand(bool isAddressOfOperand) {
+    IsAddressOfOperand = isAddressOfOperand;
+  }
+
   void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
                  bool InBaseClass) override {
     ResultBuilder::Result Result(ND, Results.getBasePriority(ND),
                                  /*Qualifier=*/std::nullopt,
                                  /*QualifierIsInformative=*/false,
                                  IsAccessible(ND, Ctx), FixIts);
-    Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass, BaseType);
+    Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass, BaseType,
+                      IsBorrowedContext, IsAddressOfOperand);
   }
 
   void EnteredContext(DeclContext *Ctx) override {
@@ -1791,6 +1815,8 @@ class CodeCompletionDeclConsumer : public 
VisibleDeclConsumer {
   }
 
 private:
+  bool IsBorrowedContext;
+  bool IsAddressOfOperand;
   bool IsAccessible(NamedDecl *ND, DeclContext *Ctx) {
     // Naming class to use for access check. In most cases it was provided
     // explicitly (e.g. member access (lhs.foo) or qualified lookup (X::)),
@@ -3440,17 +3466,17 @@ static void AddFunctionTypeQuals(CodeCompletionBuilder 
&Result,
 
   // Handle single qualifiers without copying
   if (Quals.hasOnlyConst()) {
-    Result.AddInformativeChunk(" const");
+    Result.AddFunctionQualifierChunk(" const");
     return;
   }
 
   if (Quals.hasOnlyVolatile()) {
-    Result.AddInformativeChunk(" volatile");
+    Result.AddFunctionQualifierChunk(" volatile");
     return;
   }
 
   if (Quals.hasOnlyRestrict()) {
-    Result.AddInformativeChunk(" restrict");
+    Result.AddFunctionQualifierChunk(" restrict");
     return;
   }
 
@@ -3462,7 +3488,7 @@ static void AddFunctionTypeQuals(CodeCompletionBuilder 
&Result,
     QualsStr += " volatile";
   if (Quals.hasRestrict())
     QualsStr += " restrict";
-  Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr));
+  Result.AddFunctionQualifierChunk(Result.getAllocator().CopyString(QualsStr));
 }
 
 static void
@@ -5072,7 +5098,7 @@ static void AddLambdaCompletion(ResultBuilder &Results,
 /// Perform code-completion in an expression context when we know what
 /// type we're looking for.
 void SemaCodeCompletion::CodeCompleteExpression(
-    Scope *S, const CodeCompleteExpressionData &Data) {
+    Scope *S, const CodeCompleteExpressionData &Data, bool IsAddressOfOperand) 
{
   ResultBuilder Results(
       SemaRef, CodeCompleter->getAllocator(),
       CodeCompleter->getCodeCompletionTUInfo(),
@@ -5100,6 +5126,7 @@ void SemaCodeCompletion::CodeCompleteExpression(
     Results.Ignore(Data.IgnoreDecls[I]);
 
   CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);
+  Consumer.setIsAddressOfOperand(IsAddressOfOperand);
   SemaRef.LookupVisibleDecls(S, Sema::LookupOrdinaryName, Consumer,
                              CodeCompleter->includeGlobals(),
                              CodeCompleter->loadExternal());
@@ -5143,9 +5170,11 @@ void SemaCodeCompletion::CodeCompleteExpression(
 
 void SemaCodeCompletion::CodeCompleteExpression(Scope *S,
                                                 QualType PreferredType,
-                                                bool IsParenthesized) {
+                                                bool IsParenthesized,
+                                                bool IsAddressOfOperand) {
   return CodeCompleteExpression(
-      S, CodeCompleteExpressionData(PreferredType, IsParenthesized));
+      S, CodeCompleteExpressionData(PreferredType, IsParenthesized),
+      IsAddressOfOperand);
 }
 
 void SemaCodeCompletion::CodeCompletePostfixExpression(Scope *S, ExprResult E,
@@ -6820,11 +6849,9 @@ void SemaCodeCompletion::CodeCompleteAfterIf(Scope *S, 
bool IsBracedThen) {
                             Results.size());
 }
 
-void SemaCodeCompletion::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
-                                                 bool EnteringContext,
-                                                 bool IsUsingDeclaration,
-                                                 QualType BaseType,
-                                                 QualType PreferredType) {
+void SemaCodeCompletion::CodeCompleteQualifiedId(
+    Scope *S, CXXScopeSpec &SS, bool EnteringContext, bool IsUsingDeclaration,
+    bool IsAddressOfOperand, QualType BaseType, QualType PreferredType) {
   if (SS.isEmpty() || !CodeCompleter)
     return;
 
@@ -6859,12 +6886,25 @@ void SemaCodeCompletion::CodeCompleteQualifiedId(Scope 
*S, CXXScopeSpec &SS,
   // resolves to a dependent record.
   DeclContext *Ctx = SemaRef.computeDeclContext(SS, /*EnteringContext=*/true);
 
+  // This is used to borrow context to access private methods for completion
+  DeclContext *SavedContext = nullptr;
+  if (!SemaRef.CurContext->isFunctionOrMethod() &&
+      !SemaRef.CurContext->isRecord()) {
+    // We are in global scope or namespace
+    SavedContext = SemaRef.CurContext;
+    SemaRef.CurContext = Ctx; // Simulate that we are in class scope
+                              // to access private methods
+  }
+
   // Try to instantiate any non-dependent declaration contexts before
   // we look in them. Bail out if we fail.
   NestedNameSpecifier NNS = SS.getScopeRep();
   if (NNS && !NNS.isDependent()) {
-    if (Ctx == nullptr || SemaRef.RequireCompleteDeclContext(SS, Ctx))
+    if (Ctx == nullptr || SemaRef.RequireCompleteDeclContext(SS, Ctx)) {
+      if (SavedContext)
+        SemaRef.CurContext = SavedContext;
       return;
+    }
   }
 
   ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),
@@ -6905,11 +6945,15 @@ void SemaCodeCompletion::CodeCompleteQualifiedId(Scope 
*S, CXXScopeSpec &SS,
   if (Ctx &&
       (CodeCompleter->includeNamespaceLevelDecls() || !Ctx->isFileContext())) {
     CodeCompletionDeclConsumer Consumer(Results, Ctx, BaseType);
+    Consumer.setIsBorrowedContext(SavedContext != nullptr);
+    Consumer.setIsAddressOfOperand(IsAddressOfOperand);
     SemaRef.LookupVisibleDecls(Ctx, Sema::LookupOrdinaryName, Consumer,
                                /*IncludeGlobalScope=*/true,
                                /*IncludeDependentBases=*/true,
                                CodeCompleter->loadExternal());
   }
+  if (SavedContext)
+    SemaRef.CurContext = SavedContext;
 
   HandleCodeCompleteResults(&SemaRef, CodeCompleter,
                             Results.getCompletionContext(), Results.data(),
diff --git a/clang/tools/libclang/CIndexCodeCompletion.cpp 
b/clang/tools/libclang/CIndexCodeCompletion.cpp
index 81448b4d11342..816afd28e6568 100644
--- a/clang/tools/libclang/CIndexCodeCompletion.cpp
+++ b/clang/tools/libclang/CIndexCodeCompletion.cpp
@@ -70,6 +70,8 @@ clang_getCompletionChunkKind(CXCompletionString 
completion_string,
   case CodeCompletionString::CK_Placeholder:
     return CXCompletionChunk_Placeholder;
   case CodeCompletionString::CK_Informative:
+  case CodeCompletionString::CK_FunctionQualifier:
+    // as FunctionQualifier are informative, except for completion.
     return CXCompletionChunk_Informative;
   case CodeCompletionString::CK_ResultType:
     return CXCompletionChunk_ResultType;
@@ -120,6 +122,7 @@ CXString clang_getCompletionChunkText(CXCompletionString 
completion_string,
   case CodeCompletionString::CK_Placeholder:
   case CodeCompletionString::CK_CurrentParameter:
   case CodeCompletionString::CK_Informative:
+  case CodeCompletionString::CK_FunctionQualifier:
   case CodeCompletionString::CK_LeftParen:
   case CodeCompletionString::CK_RightParen:
   case CodeCompletionString::CK_LeftBracket:
@@ -159,6 +162,7 @@ clang_getCompletionChunkCompletionString(CXCompletionString 
completion_string,
   case CodeCompletionString::CK_Placeholder:
   case CodeCompletionString::CK_CurrentParameter:
   case CodeCompletionString::CK_Informative:
+  case CodeCompletionString::CK_FunctionQualifier:
   case CodeCompletionString::CK_LeftParen:
   case CodeCompletionString::CK_RightParen:
   case CodeCompletionString::CK_LeftBracket:

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to