diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-09-22 15:41:20 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-09-22 15:41:20 +0000 |
commit | 9c6a0e92dbf89897eae6106b24bfd017f269bfd0 (patch) | |
tree | 0cf2ed937ce5e34365078d5fdadcfedbd3afdf74 /lib/Sema/SemaOverload.cpp | |
parent | e119e84ea5ea66eb2090aec05310c23e9d6f63fc (diff) |
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
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 191 |
1 files changed, 120 insertions, 71 deletions
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<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); 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<FunctionDecl>(*Func)) - AddOverloadCandidate(FD, Args, NumArgs, CandidateSet); - else + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) { + if (HasExplicitTemplateArgs) + continue; + + AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, + false, false, PartialOverloading); + } else AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*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<FunctionDecl>(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<FunctionTemplateDecl>(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<OverloadedFunctionDecl>(Callee)) { + if (!Callee) { + // Nothing to do. + } else if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(Callee)) { for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), FuncEnd = Ovl->function_end(); - Func != FuncEnd; ++Func) { - DeclContext *Ctx = 0; - if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Func)) { - if (HasExplicitTemplateArgs) - continue; - - AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet); - Ctx = FunDecl->getDeclContext(); - } else { - FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*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<FunctionDecl>(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<FunctionTemplateDecl>(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<FunctionDecl>(Callee) || isa<FunctionTemplateDecl>(Callee)) + AddOverloadedCallCandidate(*this, + AnyFunctionDecl::getFromNamedDecl(Callee), + ArgumentDependentLookup, + HasExplicitTemplateArgs, + ExplicitTemplateArgs, NumExplicitTemplateArgs, + Args, NumArgs, CandidateSet, + PartialOverloading); + // FIXME: assert isa<FunctionDecl> || isa<FunctionTemplateDecl> 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<RecordType>(); |