From 8f3dd24e4ff099b618beeb1dbc88fda68c1098b4 Mon Sep 17 00:00:00 2001
From: Francisco Lopes da Silva <oblita@gmail.com>
Date: Thu, 22 Jan 2015 21:14:08 +0000
Subject: [PATCH] Sema: code completion for pointer and reference to functions.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@226865 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaCodeComplete.cpp                 | 48 +++++++++++--------
 ...ete-pointer-and-reference-to-functions.cpp | 34 +++++++++++++
 2 files changed, 63 insertions(+), 19 deletions(-)
 create mode 100644 test/Index/complete-pointer-and-reference-to-functions.cpp

diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 3fad2b6b784..add469b97af 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -3896,7 +3896,6 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args) {
 
   // FIXME: Provide support for highlighting optional parameters.
   // FIXME: Provide support for variadic template functions.
-  // FIXME: Provide support for pointers and references to functions.
 
   // Ignore type-dependent call expressions entirely.
   if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args) ||
@@ -3928,30 +3927,13 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args) {
     AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs,
                           /*SuppressUsedConversions=*/false,
                           /*PartialOverloading=*/true);
-  } else if (auto DC = NakedFn->getType()->getCanonicalTypeInternal()
-                       ->getAsCXXRecordDecl()) {
-    // If it's a CXXRecordDecl, it may overload the function call operator,
-    // so we check if it does and add them as candidates.
-    DeclarationName OpName = Context.DeclarationNames
-                             .getCXXOperatorName(OO_Call);
-    LookupResult R(*this, OpName, Loc, LookupOrdinaryName);
-    LookupQualifiedName(R, DC);
-    R.suppressDiagnostics();
-    SmallVector<Expr *, 12> ArgExprs(1, NakedFn);
-    ArgExprs.append(Args.begin(), Args.end());
-    AddFunctionCandidates(R.asUnresolvedSet(), ArgExprs, CandidateSet,
-                          /*ExplicitArgs=*/nullptr,
-                          /*SuppressUsedConversions=*/false,
-                          /*PartialOverloading=*/true);
   } else {
-    // Lastly we check, as a possibly resolved expression, whether it can be
-    // converted to a function.
     FunctionDecl *FD = nullptr;
     if (auto MCE = dyn_cast<MemberExpr>(NakedFn))
       FD = dyn_cast<FunctionDecl>(MCE->getMemberDecl());
     else if (auto DRE = dyn_cast<DeclRefExpr>(NakedFn))
       FD = dyn_cast<FunctionDecl>(DRE->getDecl());
-    if (FD) {
+    if (FD) { // We check whether it's a resolved function declaration.
       if (!getLangOpts().CPlusPlus || 
           !FD->getType()->getAs<FunctionProtoType>())
         Results.push_back(ResultCandidate(FD));
@@ -3960,6 +3942,34 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args) {
                              Args, CandidateSet,
                              /*SuppressUsedConversions=*/false,
                              /*PartialOverloading=*/true);
+
+    } else if (auto DC = NakedFn->getType()->getAsCXXRecordDecl()) {
+      // If expression's type is CXXRecordDecl, it may overload the function
+      // call operator, so we check if it does and add them as candidates.
+      DeclarationName OpName = Context.DeclarationNames
+                               .getCXXOperatorName(OO_Call);
+      LookupResult R(*this, OpName, Loc, LookupOrdinaryName);
+      LookupQualifiedName(R, DC);
+      R.suppressDiagnostics();
+      SmallVector<Expr *, 12> ArgExprs(1, NakedFn);
+      ArgExprs.append(Args.begin(), Args.end());
+      AddFunctionCandidates(R.asUnresolvedSet(), ArgExprs, CandidateSet,
+                            /*ExplicitArgs=*/nullptr,
+                            /*SuppressUsedConversions=*/false,
+                            /*PartialOverloading=*/true);
+    } else {
+      // Lastly we check whether expression's type is function pointer or
+      // function.
+      QualType T = NakedFn->getType();
+      if (!T->getPointeeType().isNull())
+        T = T->getPointeeType();
+
+      if (auto FP = T->getAs<FunctionProtoType>()) {
+        if (!TooManyArguments(FP->getNumParams(), Args.size(),
+                             /*PartialOverloading=*/true))
+          Results.push_back(ResultCandidate(FP));
+      } else if (auto FT = T->getAs<FunctionType>())
+        Results.push_back(ResultCandidate(FT));
     }
   }
 
diff --git a/test/Index/complete-pointer-and-reference-to-functions.cpp b/test/Index/complete-pointer-and-reference-to-functions.cpp
new file mode 100644
index 00000000000..5d5904ca415
--- /dev/null
+++ b/test/Index/complete-pointer-and-reference-to-functions.cpp
@@ -0,0 +1,34 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+template<class T> void (&foo(T))(T);
+template<class T> void (*bar(T))(T);
+
+int main() {
+  foo(42)(42);
+  bar(42)(42);
+}
+
+// RUN: c-index-test -code-completion-at=%s:8:11 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: OverloadCandidate:{Text void}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
+// CHECK-CC1: Completion contexts:
+// CHECK-CC1-NEXT: Any type
+// CHECK-CC1-NEXT: Any value
+// CHECK-CC1-NEXT: Enum tag
+// CHECK-CC1-NEXT: Union tag
+// CHECK-CC1-NEXT: Struct tag
+// CHECK-CC1-NEXT: Class name
+// CHECK-CC1-NEXT: Nested name specifier
+// CHECK-CC1-NEXT: Objective-C interface
+
+// RUN: c-index-test -code-completion-at=%s:9:11 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: OverloadCandidate:{Text void}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
+// CHECK-CC2: Completion contexts:
+// CHECK-CC2-NEXT: Any type
+// CHECK-CC2-NEXT: Any value
+// CHECK-CC2-NEXT: Enum tag
+// CHECK-CC2-NEXT: Union tag
+// CHECK-CC2-NEXT: Struct tag
+// CHECK-CC2-NEXT: Class name
+// CHECK-CC2-NEXT: Nested name specifier
+// CHECK-CC2-NEXT: Objective-C interface
-- 
GitLab