]> granicus.if.org Git - clang/commitdiff
Sema: code completion for pointer and reference to functions.
authorFrancisco Lopes da Silva <oblita@gmail.com>
Thu, 22 Jan 2015 21:14:08 +0000 (21:14 +0000)
committerFrancisco Lopes da Silva <oblita@gmail.com>
Thu, 22 Jan 2015 21:14:08 +0000 (21:14 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@226865 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaCodeComplete.cpp
test/Index/complete-pointer-and-reference-to-functions.cpp [new file with mode: 0644]

index 3fad2b6b784d742ac64918b0b2e44fcf0a0d986d..add469b97af9bb9db7f9c05ba4f999047d3e8c87 100644 (file)
@@ -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 (file)
index 0000000..5d5904c
--- /dev/null
@@ -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