aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-09-22 15:41:20 +0000
committerDouglas Gregor <dgregor@apple.com>2009-09-22 15:41:20 +0000
commit9c6a0e92dbf89897eae6106b24bfd017f269bfd0 (patch)
tree0cf2ed937ce5e34365078d5fdadcfedbd3afdf74 /lib/Sema/SemaOverload.cpp
parente119e84ea5ea66eb2090aec05310c23e9d6f63fc (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.cpp191
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>();