From 9c6a0e92dbf89897eae6106b24bfd017f269bfd0 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 22 Sep 2009 15:41:20 +0000 Subject: [PATCH] Implement code completion within a function call, triggered after the opening parentheses and after each comma. We gather the set of visible overloaded functions, perform "partial" overloading based on the set of arguments that we have thus far, and return the still-viable results sorted by the likelihood that they will be the best candidate. Most of the changes in this patch are a refactoring of the overloading routines for a function call, since we needed to separate out the notion of building an overload set (common to code-completion and normal semantic analysis) and then what to do with that overload set. As part of this change, I've pushed explicit template arguments into a few more subroutines. There is still much more work to do in this area. Function templates won't be handled well (unless we happen to deduce all of the template arguments before we hit the completion point), nor will overloaded function-call operators or calls to member functions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82549 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Action.h | 12 +++ include/clang/Parse/Parser.h | 6 +- lib/Parse/ParseExpr.cpp | 21 +++- lib/Sema/Sema.h | 31 +++++- lib/Sema/SemaCodeComplete.cpp | 72 +++++++++++++ lib/Sema/SemaExpr.cpp | 163 ++++++++++++++++++----------- lib/Sema/SemaOverload.cpp | 191 +++++++++++++++++++++------------- test/CodeCompletion/call.cpp | 22 ++++ 8 files changed, 379 insertions(+), 139 deletions(-) create mode 100644 test/CodeCompletion/call.cpp diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 06213ddf47..df85dfe8eb 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -2239,6 +2239,18 @@ public: /// \brief S the scope in which the case statement occurs. virtual void CodeCompleteCase(Scope *S) { } + /// \brief Code completion for a call. + /// + /// \brief S the scope in which the call occurs. + /// + /// \param Fn the expression describing the function being called. + /// + /// \param Args the arguments to the function call (so far). + /// + /// \param NumArgs the number of arguments in \p Args. + virtual void CodeCompleteCall(Scope *S, ExprTy *Fn, + ExprTy **Args, unsigned NumArgs) { } + /// \brief Code completion for a C++ nested-name-specifier that precedes a /// qualified-id of some form. /// diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e1a6e7ad39..b9b17d24d1 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -745,7 +745,11 @@ private: typedef llvm::SmallVector CommaLocsTy; /// ParseExpressionList - Used for C/C++ (argument-)expression-list. - bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs); + bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs, + void (Action::*Completer)(Scope *S, void *Data, + ExprTy **Args, + unsigned NumArgs) = 0, + void *Data = 0); /// ParenParseOption - Control what ParseParenExpression will parse. enum ParenParseOption { diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 156c84804f..d10e38cf68 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -899,8 +899,14 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { Loc = ConsumeParen(); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteCall(CurScope, LHS.get(), 0, 0); + ConsumeToken(); + } + if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs)) { + if (ParseExpressionList(ArgExprs, CommaLocs, &Action::CodeCompleteCall, + LHS.get())) { SkipUntil(tok::r_paren); return ExprError(); } @@ -1508,8 +1514,19 @@ Parser::OwningExprResult Parser::ParseStringLiteralExpression() { /// [C++] assignment-expression /// [C++] expression-list , assignment-expression /// -bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs) { +bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs, + void (Action::*Completer)(Scope *S, + void *Data, + ExprTy **Args, + unsigned NumArgs), + void *Data) { while (1) { + if (Tok.is(tok::code_completion)) { + if (Completer) + (Actions.*Completer)(CurScope, Data, Exprs.data(), Exprs.size()); + ConsumeToken(); + } + OwningExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) return true; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 7fa546258e..4d8fd8d095 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -835,7 +835,8 @@ public: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, - bool ForceRValue = false); + bool ForceRValue = false, + bool PartialOverloading = false); void AddFunctionCandidates(const FunctionSet &Functions, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -891,7 +892,11 @@ public: OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet); + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + OverloadCandidateSet& CandidateSet, + bool PartialOverloading = false); bool isBetterOverloadCandidate(const OverloadCandidate& Cand1, const OverloadCandidate& Cand2); OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet, @@ -904,6 +909,16 @@ public: bool Complain); void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + void AddOverloadedCallCandidates(NamedDecl *Callee, + DeclarationName &UnqualifiedName, + bool &ArgumentDependentLookup, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet &CandidateSet, + bool PartialOverloading = false); + FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, DeclarationName UnqualifiedName, bool HasExplicitTemplateArgs, @@ -1670,6 +1685,16 @@ public: unsigned NumInitializers ); + void DeconstructCallFunction(Expr *FnExpr, + NamedDecl *&Function, + DeclarationName &Name, + NestedNameSpecifier *&Qualifier, + SourceRange &QualifierRange, + bool &ArgumentDependentLookup, + bool &HasExplicitTemplateArguments, + const TemplateArgument *&ExplicitTemplateArgs, + unsigned &NumExplicitTemplateArgs); + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -3635,6 +3660,8 @@ public: bool IsArrow); virtual void CodeCompleteTag(Scope *S, unsigned TagSpec); virtual void CodeCompleteCase(Scope *S); + virtual void CodeCompleteCall(Scope *S, ExprTy *Fn, + ExprTy **Args, unsigned NumArgs); virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, bool EnteringContext); virtual void CodeCompleteUsing(Scope *S); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 52e7d0e005..757bb62711 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1070,6 +1070,78 @@ void Sema::CodeCompleteCase(Scope *S) { HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } +namespace { + struct IsBetterOverloadCandidate { + Sema &S; + + public: + explicit IsBetterOverloadCandidate(Sema &S) : S(S) { } + + bool + operator()(const OverloadCandidate &X, const OverloadCandidate &Y) const { + return S.isBetterOverloadCandidate(X, Y); + } + }; +} + +void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, + ExprTy **ArgsIn, unsigned NumArgs) { + if (!CodeCompleter) + return; + + Expr *Fn = (Expr *)FnIn; + Expr **Args = (Expr **)ArgsIn; + + // Ignore type-dependent call expressions entirely. + if (Fn->isTypeDependent() || + Expr::hasAnyTypeDependentArguments(Args, NumArgs)) + return; + + NamedDecl *Function; + DeclarationName UnqualifiedName; + NestedNameSpecifier *Qualifier; + SourceRange QualifierRange; + bool ArgumentDependentLookup; + bool HasExplicitTemplateArgs; + const TemplateArgument *ExplicitTemplateArgs; + unsigned NumExplicitTemplateArgs; + + DeconstructCallFunction(Fn, + Function, UnqualifiedName, Qualifier, QualifierRange, + ArgumentDependentLookup, HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs); + + + // FIXME: What if we're calling something that isn't a function declaration? + // FIXME: What if we're calling a pseudo-destructor? + // FIXME: What if we're calling a member function? + + // Build an overload candidate set based on the functions we find. + OverloadCandidateSet CandidateSet; + AddOverloadedCallCandidates(Function, UnqualifiedName, + ArgumentDependentLookup, HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs, + Args, NumArgs, + CandidateSet, + /*PartialOverloading=*/true); + + // Sort the overload candidate set by placing the best overloads first. + std::stable_sort(CandidateSet.begin(), CandidateSet.end(), + IsBetterOverloadCandidate(*this)); + + // Add the remaining viable overload candidates as code-completion reslults. + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + CandEnd = CandidateSet.end(); + Cand != CandEnd; ++Cand) { + if (Cand->Viable) + Results.MaybeAddResult(Result(Cand->Function, 0), 0); + } + + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, bool EnteringContext) { if (!SS.getScopeRep() || !CodeCompleter) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 333cd35f89..3eed4fcde3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2734,6 +2734,96 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, return Invalid; } +/// \brief "Deconstruct" the function argument of a call expression to find +/// the underlying declaration (if any), the name of the called function, +/// whether argument-dependent lookup is available, whether it has explicit +/// template arguments, etc. +void Sema::DeconstructCallFunction(Expr *FnExpr, + NamedDecl *&Function, + DeclarationName &Name, + NestedNameSpecifier *&Qualifier, + SourceRange &QualifierRange, + bool &ArgumentDependentLookup, + bool &HasExplicitTemplateArguments, + const TemplateArgument *&ExplicitTemplateArgs, + unsigned &NumExplicitTemplateArgs) { + // Set defaults for all of the output parameters. + Function = 0; + Name = DeclarationName(); + Qualifier = 0; + QualifierRange = SourceRange(); + ArgumentDependentLookup = getLangOptions().CPlusPlus; + HasExplicitTemplateArguments = false; + + // If we're directly calling a function, get the appropriate declaration. + // Also, in C++, keep track of whether we should perform argument-dependent + // lookup and whether there were any explicitly-specified template arguments. + while (true) { + if (ImplicitCastExpr *IcExpr = dyn_cast(FnExpr)) + FnExpr = IcExpr->getSubExpr(); + else if (ParenExpr *PExpr = dyn_cast(FnExpr)) { + // Parentheses around a function disable ADL + // (C++0x [basic.lookup.argdep]p1). + ArgumentDependentLookup = false; + FnExpr = PExpr->getSubExpr(); + } else if (isa(FnExpr) && + cast(FnExpr)->getOpcode() + == UnaryOperator::AddrOf) { + FnExpr = cast(FnExpr)->getSubExpr(); + } else if (QualifiedDeclRefExpr *QDRExpr + = dyn_cast(FnExpr)) { + // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1). + ArgumentDependentLookup = false; + Qualifier = QDRExpr->getQualifier(); + QualifierRange = QDRExpr->getQualifierRange(); + Function = dyn_cast(QDRExpr->getDecl()); + break; + } else if (DeclRefExpr *DRExpr = dyn_cast(FnExpr)) { + Function = dyn_cast(DRExpr->getDecl()); + break; + } else if (UnresolvedFunctionNameExpr *DepName + = dyn_cast(FnExpr)) { + Name = DepName->getName(); + break; + } else if (TemplateIdRefExpr *TemplateIdRef + = dyn_cast(FnExpr)) { + Function = TemplateIdRef->getTemplateName().getAsTemplateDecl(); + if (!Function) + Function = TemplateIdRef->getTemplateName().getAsOverloadedFunctionDecl(); + HasExplicitTemplateArguments = true; + ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs(); + NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs(); + + // C++ [temp.arg.explicit]p6: + // [Note: For simple function names, argument dependent lookup (3.4.2) + // applies even when the function name is not visible within the + // scope of the call. This is because the call still has the syntactic + // form of a function call (3.4.1). But when a function template with + // explicit template arguments is used, the call does not have the + // correct syntactic form unless there is a function template with + // that name visible at the point of the call. If no such name is + // visible, the call is not syntactically well-formed and + // argument-dependent lookup does not apply. If some such name is + // visible, argument dependent lookup applies and additional function + // templates may be found in other namespaces. + // + // The summary of this paragraph is that, if we get to this point and the + // template-id was not a qualified name, then argument-dependent lookup + // is still possible. + if ((Qualifier = TemplateIdRef->getQualifier())) { + ArgumentDependentLookup = false; + QualifierRange = TemplateIdRef->getQualifierRange(); + } + break; + } else { + // Any kind of name that does not refer to a declaration (or + // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3). + ArgumentDependentLookup = false; + break; + } + } +} + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -2808,67 +2898,15 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // If we're directly calling a function, get the appropriate declaration. // Also, in C++, keep track of whether we should perform argument-dependent // lookup and whether there were any explicitly-specified template arguments. - Expr *FnExpr = Fn; bool ADL = true; bool HasExplicitTemplateArgs = 0; const TemplateArgument *ExplicitTemplateArgs = 0; unsigned NumExplicitTemplateArgs = 0; - while (true) { - if (ImplicitCastExpr *IcExpr = dyn_cast(FnExpr)) - FnExpr = IcExpr->getSubExpr(); - else if (ParenExpr *PExpr = dyn_cast(FnExpr)) { - // Parentheses around a function disable ADL - // (C++0x [basic.lookup.argdep]p1). - ADL = false; - FnExpr = PExpr->getSubExpr(); - } else if (isa(FnExpr) && - cast(FnExpr)->getOpcode() - == UnaryOperator::AddrOf) { - FnExpr = cast(FnExpr)->getSubExpr(); - } else if (DeclRefExpr *DRExpr = dyn_cast(FnExpr)) { - // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1). - ADL &= !isa(DRExpr); - NDecl = dyn_cast(DRExpr->getDecl()); - break; - } else if (UnresolvedFunctionNameExpr *DepName - = dyn_cast(FnExpr)) { - UnqualifiedName = DepName->getName(); - break; - } else if (TemplateIdRefExpr *TemplateIdRef - = dyn_cast(FnExpr)) { - NDecl = TemplateIdRef->getTemplateName().getAsTemplateDecl(); - if (!NDecl) - NDecl = TemplateIdRef->getTemplateName().getAsOverloadedFunctionDecl(); - HasExplicitTemplateArgs = true; - ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs(); - NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs(); - - // C++ [temp.arg.explicit]p6: - // [Note: For simple function names, argument dependent lookup (3.4.2) - // applies even when the function name is not visible within the - // scope of the call. This is because the call still has the syntactic - // form of a function call (3.4.1). But when a function template with - // explicit template arguments is used, the call does not have the - // correct syntactic form unless there is a function template with - // that name visible at the point of the call. If no such name is - // visible, the call is not syntactically well-formed and - // argument-dependent lookup does not apply. If some such name is - // visible, argument dependent lookup applies and additional function - // templates may be found in other namespaces. - // - // The summary of this paragraph is that, if we get to this point and the - // template-id was not a qualified name, then argument-dependent lookup - // is still possible. - if (TemplateIdRef->getQualifier()) - ADL = false; - break; - } else { - // Any kind of name that does not refer to a declaration (or - // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3). - ADL = false; - break; - } - } + NestedNameSpecifier *Qualifier = 0; + SourceRange QualifierRange; + DeconstructCallFunction(Fn, NDecl, UnqualifiedName, Qualifier, QualifierRange, + ADL,HasExplicitTemplateArgs, ExplicitTemplateArgs, + NumExplicitTemplateArgs); OverloadedFunctionDecl *Ovl = 0; FunctionTemplateDecl *FunctionTemplate = 0; @@ -2903,16 +2941,15 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // Update Fn to refer to the actual function selected. Expr *NewFn = 0; - if (QualifiedDeclRefExpr *QDRExpr - = dyn_cast(FnExpr)) + if (Qualifier) NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(), - QDRExpr->getLocation(), + Fn->getLocStart(), false, false, - QDRExpr->getQualifierRange(), - QDRExpr->getQualifier()); + QualifierRange, + Qualifier); else NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(), - Fn->getSourceRange().getBegin()); + Fn->getLocStart()); Fn->Destroy(Context); Fn = NewFn; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 2ff0c0544a..063b387fba 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2122,12 +2122,17 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { /// If @p ForceRValue, treat all arguments as rvalues. This is a slightly /// hacky way to implement the overloading rules for elidable copy /// initialization in C++0x (C++0x 12.8p15). +/// +/// \para PartialOverloading true if we are performing "partial" overloading +/// based on an incomplete set of function arguments. This feature is used by +/// code completion. void Sema::AddOverloadCandidate(FunctionDecl *Function, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, - bool ForceRValue) { + bool ForceRValue, + bool PartialOverloading) { const FunctionProtoType* Proto = dyn_cast(Function->getType()->getAs()); assert(Proto && "Functions without a prototype cannot be overloaded"); @@ -2177,7 +2182,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // parameter list is truncated on the right, so that there are // exactly m parameters. unsigned MinRequiredArgs = Function->getMinRequiredArguments(); - if (NumArgs < MinRequiredArgs) { + if (NumArgs < MinRequiredArgs && !PartialOverloading) { // Not enough arguments. Candidate.Viable = false; return; @@ -3615,9 +3620,15 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, void Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet) { + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + OverloadCandidateSet& CandidateSet, + bool PartialOverloading) { FunctionSet Functions; + // FIXME: Should we be trafficking in canonical function decls throughout? + // Record all of the function candidates that we've already // added to the overload set, so that we don't add those same // candidates a second time. @@ -3630,6 +3641,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, Functions.insert(FunTmpl); } + // FIXME: Pass in the explicit template arguments? ArgumentDependentLookup(Name, Args, NumArgs, Functions); // Erase all of the candidates we already knew about. @@ -3648,11 +3660,17 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, for (FunctionSet::iterator Func = Functions.begin(), FuncEnd = Functions.end(); Func != FuncEnd; ++Func) { - if (FunctionDecl *FD = dyn_cast(*Func)) - AddOverloadCandidate(FD, Args, NumArgs, CandidateSet); - else + if (FunctionDecl *FD = dyn_cast(*Func)) { + if (HasExplicitTemplateArgs) + continue; + + AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, + false, false, PartialOverloading); + } else AddTemplateOverloadCandidate(cast(*Func), - /*FIXME: explicit args */false, 0, 0, + HasExplicitTemplateArgs, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, Args, NumArgs, CandidateSet); } } @@ -4100,25 +4118,48 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; } -/// ResolveOverloadedCallFn - Given the call expression that calls Fn -/// (which eventually refers to the declaration Func) and the call -/// arguments Args/NumArgs, attempt to resolve the function call down -/// to a specific function. If overload resolution succeeds, returns -/// the function declaration produced by overload -/// resolution. Otherwise, emits diagnostics, deletes all of the -/// arguments and Fn, and returns NULL. -FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, - DeclarationName UnqualifiedName, - bool HasExplicitTemplateArgs, +/// \brief Add a single candidate to the overload set. +static void AddOverloadedCallCandidate(Sema &S, + AnyFunctionDecl Callee, + bool &ArgumentDependentLookup, + bool HasExplicitTemplateArgs, const TemplateArgument *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation LParenLoc, - Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc, - bool &ArgumentDependentLookup) { - OverloadCandidateSet CandidateSet; - + unsigned NumExplicitTemplateArgs, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet &CandidateSet, + bool PartialOverloading) { + if (FunctionDecl *Func = dyn_cast(Callee)) { + assert(!HasExplicitTemplateArgs && "Explicit template arguments?"); + S.AddOverloadCandidate(Func, Args, NumArgs, CandidateSet, false, false, + PartialOverloading); + + if (Func->getDeclContext()->isRecord() || + Func->getDeclContext()->isFunctionOrMethod()) + ArgumentDependentLookup = false; + return; + } + + FunctionTemplateDecl *FuncTemplate = cast(Callee); + S.AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + Args, NumArgs, CandidateSet); + + if (FuncTemplate->getDeclContext()->isRecord()) + ArgumentDependentLookup = false; +} + +/// \brief Add the overload candidates named by callee and/or found by argument +/// dependent lookup to the given overload set. +void Sema::AddOverloadedCallCandidates(NamedDecl *Callee, + DeclarationName &UnqualifiedName, + bool &ArgumentDependentLookup, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet &CandidateSet, + bool PartialOverloading) { // Add the functions denoted by Callee to the set of candidate // functions. While we're doing so, track whether argument-dependent // lookup still applies, per: @@ -4131,63 +4172,72 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, // -- a declaration of a class member, or // // -- a block-scope function declaration that is not a - // using-declaration, or + // using-declaration (FIXME: check for using declaration), or // // -- a declaration that is neither a function or a function // template // // then Y is empty. - if (OverloadedFunctionDecl *Ovl - = dyn_cast_or_null(Callee)) { + if (!Callee) { + // Nothing to do. + } else if (OverloadedFunctionDecl *Ovl + = dyn_cast(Callee)) { for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), FuncEnd = Ovl->function_end(); - Func != FuncEnd; ++Func) { - DeclContext *Ctx = 0; - if (FunctionDecl *FunDecl = dyn_cast(*Func)) { - if (HasExplicitTemplateArgs) - continue; - - AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet); - Ctx = FunDecl->getDeclContext(); - } else { - FunctionTemplateDecl *FunTmpl = cast(*Func); - AddTemplateOverloadCandidate(FunTmpl, HasExplicitTemplateArgs, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - Args, NumArgs, CandidateSet); - Ctx = FunTmpl->getDeclContext(); - } - - - if (Ctx->isRecord() || Ctx->isFunctionOrMethod()) - ArgumentDependentLookup = false; - } - } else if (FunctionDecl *Func = dyn_cast_or_null(Callee)) { - assert(!HasExplicitTemplateArgs && "Explicit template arguments?"); - AddOverloadCandidate(Func, Args, NumArgs, CandidateSet); - - if (Func->getDeclContext()->isRecord() || - Func->getDeclContext()->isFunctionOrMethod()) - ArgumentDependentLookup = false; - } else if (FunctionTemplateDecl *FuncTemplate - = dyn_cast_or_null(Callee)) { - AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - Args, NumArgs, CandidateSet); - - if (FuncTemplate->getDeclContext()->isRecord()) - ArgumentDependentLookup = false; - } - + Func != FuncEnd; ++Func) + AddOverloadedCallCandidate(*this, *Func, ArgumentDependentLookup, + HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs, + Args, NumArgs, CandidateSet, + PartialOverloading); + } else if (isa(Callee) || isa(Callee)) + AddOverloadedCallCandidate(*this, + AnyFunctionDecl::getFromNamedDecl(Callee), + ArgumentDependentLookup, + HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs, + Args, NumArgs, CandidateSet, + PartialOverloading); + // FIXME: assert isa || isa rather than + // checking dynamically. + if (Callee) UnqualifiedName = Callee->getDeclName(); - - // FIXME: Pass explicit template arguments through for ADL + if (ArgumentDependentLookup) AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs, - CandidateSet); + HasExplicitTemplateArgs, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + CandidateSet, + PartialOverloading); +} + +/// ResolveOverloadedCallFn - Given the call expression that calls Fn +/// (which eventually refers to the declaration Func) and the call +/// arguments Args/NumArgs, attempt to resolve the function call down +/// to a specific function. If overload resolution succeeds, returns +/// the function declaration produced by overload +/// resolution. Otherwise, emits diagnostics, deletes all of the +/// arguments and Fn, and returns NULL. +FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, + DeclarationName UnqualifiedName, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc, + bool &ArgumentDependentLookup) { + OverloadCandidateSet CandidateSet; + // Add the functions denoted by Callee to the set of candidate + // functions. + AddOverloadedCallCandidates(Callee, UnqualifiedName, ArgumentDependentLookup, + HasExplicitTemplateArgs, ExplicitTemplateArgs, + NumExplicitTemplateArgs, Args, NumArgs, + CandidateSet); OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) { case OR_Success: @@ -4877,7 +4927,6 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { // for a class object x of type T if T::operator->() exists and if // the operator is selected as the best match function by the // overload resolution mechanism (13.3). - // FIXME: look in base classes. DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow); OverloadCandidateSet CandidateSet; const RecordType *BaseRecord = Base->getType()->getAs(); diff --git a/test/CodeCompletion/call.cpp b/test/CodeCompletion/call.cpp new file mode 100644 index 0000000000..4faff15c05 --- /dev/null +++ b/test/CodeCompletion/call.cpp @@ -0,0 +1,22 @@ +// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s && +// RUN: true +void f(float x, float y); +void f(int i, int j, int k); +struct X { }; +void f(X); +namespace N { + struct Y { + Y(int = 0); + + operator int() const; + }; + void f(Y y); +} +typedef N::Y Y; +void f(); + +void test() { + // CHECK-CC1: f : 0 : f(<#struct N::Y y#>) + // CHECK-NEXT-CC1: f : 0 : f(<#int i#>, <#int j#>, <#int k#>) + // CHECK-NEXT-CC1: f : 0 : f(<#float x#>, <#float y#>) + f(Y(), -- 2.40.0