Sema: code completion for pointer and reference to functions.

llvm-svn: 226865
This commit is contained in:
Francisco Lopes da Silva 2015-01-22 21:14:08 +00:00
parent 799ef37d02
commit c6ccc4fe91
2 changed files with 63 additions and 19 deletions

View 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 highlighting optional parameters.
// FIXME: Provide support for variadic template functions. // FIXME: Provide support for variadic template functions.
// FIXME: Provide support for pointers and references to functions.
// Ignore type-dependent call expressions entirely. // Ignore type-dependent call expressions entirely.
if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args) || 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, AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs,
/*SuppressUsedConversions=*/false, /*SuppressUsedConversions=*/false,
/*PartialOverloading=*/true); /*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 { } else {
// Lastly we check, as a possibly resolved expression, whether it can be
// converted to a function.
FunctionDecl *FD = nullptr; FunctionDecl *FD = nullptr;
if (auto MCE = dyn_cast<MemberExpr>(NakedFn)) if (auto MCE = dyn_cast<MemberExpr>(NakedFn))
FD = dyn_cast<FunctionDecl>(MCE->getMemberDecl()); FD = dyn_cast<FunctionDecl>(MCE->getMemberDecl());
else if (auto DRE = dyn_cast<DeclRefExpr>(NakedFn)) else if (auto DRE = dyn_cast<DeclRefExpr>(NakedFn))
FD = dyn_cast<FunctionDecl>(DRE->getDecl()); FD = dyn_cast<FunctionDecl>(DRE->getDecl());
if (FD) { if (FD) { // We check whether it's a resolved function declaration.
if (!getLangOpts().CPlusPlus || if (!getLangOpts().CPlusPlus ||
!FD->getType()->getAs<FunctionProtoType>()) !FD->getType()->getAs<FunctionProtoType>())
Results.push_back(ResultCandidate(FD)); Results.push_back(ResultCandidate(FD));
@ -3960,6 +3942,34 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args) {
Args, CandidateSet, Args, CandidateSet,
/*SuppressUsedConversions=*/false, /*SuppressUsedConversions=*/false,
/*PartialOverloading=*/true); /*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));
} }
} }

View File

@ -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