[cfe-commits] r82549 - in /cfe/trunk: include/clang/Parse/Action.h include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp lib/Sema/Sema.h lib/Sema/SemaCodeComplete.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/CodeCompletion/call.cpp

Douglas Gregor dgregor at apple.com
Tue Sep 22 08:41:20 PDT 2009


Author: dgregor
Date: Tue Sep 22 10:41:20 2009
New Revision: 82549

URL: http://llvm.org/viewvc/llvm-project?rev=82549&view=rev
Log:
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.

Added:
    cfe/trunk/test/CodeCompletion/call.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=82549&r1=82548&r2=82549&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Sep 22 10:41:20 2009
@@ -2239,6 +2239,18 @@
   /// \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.
   ///

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=82549&r1=82548&r2=82549&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Sep 22 10:41:20 2009
@@ -745,7 +745,11 @@
   typedef llvm::SmallVector<SourceLocation, ExprListSize> 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 {

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=82549&r1=82548&r2=82549&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Tue Sep 22 10:41:20 2009
@@ -899,8 +899,14 @@
 
       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 @@
 /// [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;

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=82549&r1=82548&r2=82549&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Sep 22 10:41:20 2009
@@ -835,7 +835,8 @@
                             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 @@
                                     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 @@
                                                    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 @@
                                  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 @@
                                                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);

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=82549&r1=82548&r2=82549&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Tue Sep 22 10:41:20 2009
@@ -1070,6 +1070,78 @@
   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)

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=82549&r1=82548&r2=82549&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Sep 22 10:41:20 2009
@@ -2734,6 +2734,96 @@
   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<ImplicitCastExpr>(FnExpr))
+      FnExpr = IcExpr->getSubExpr();
+    else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
+      // Parentheses around a function disable ADL
+      // (C++0x [basic.lookup.argdep]p1).
+      ArgumentDependentLookup = false;
+      FnExpr = PExpr->getSubExpr();
+    } else if (isa<UnaryOperator>(FnExpr) &&
+               cast<UnaryOperator>(FnExpr)->getOpcode()
+               == UnaryOperator::AddrOf) {
+      FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
+    } else if (QualifiedDeclRefExpr *QDRExpr 
+                 = dyn_cast<QualifiedDeclRefExpr>(FnExpr)) {
+      // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
+      ArgumentDependentLookup = false;
+      Qualifier = QDRExpr->getQualifier();
+      QualifierRange = QDRExpr->getQualifierRange();
+      Function = dyn_cast<NamedDecl>(QDRExpr->getDecl());
+      break;
+    } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
+      Function = dyn_cast<NamedDecl>(DRExpr->getDecl());
+      break;
+    } else if (UnresolvedFunctionNameExpr *DepName
+               = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
+      Name = DepName->getName();
+      break;
+    } else if (TemplateIdRefExpr *TemplateIdRef
+               = dyn_cast<TemplateIdRefExpr>(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 @@
   // 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<ImplicitCastExpr>(FnExpr))
-      FnExpr = IcExpr->getSubExpr();
-    else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
-      // Parentheses around a function disable ADL
-      // (C++0x [basic.lookup.argdep]p1).
-      ADL = false;
-      FnExpr = PExpr->getSubExpr();
-    } else if (isa<UnaryOperator>(FnExpr) &&
-               cast<UnaryOperator>(FnExpr)->getOpcode()
-                 == UnaryOperator::AddrOf) {
-      FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
-    } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
-      // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
-      ADL &= !isa<QualifiedDeclRefExpr>(DRExpr);
-      NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
-      break;
-    } else if (UnresolvedFunctionNameExpr *DepName
-                 = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
-      UnqualifiedName = DepName->getName();
-      break;
-    } else if (TemplateIdRefExpr *TemplateIdRef
-                 = dyn_cast<TemplateIdRefExpr>(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 @@
 
       // Update Fn to refer to the actual function selected.
       Expr *NewFn = 0;
-      if (QualifiedDeclRefExpr *QDRExpr
-            = dyn_cast<QualifiedDeclRefExpr>(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;
     }

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=82549&r1=82548&r2=82549&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Sep 22 10:41:20 2009
@@ -2122,12 +2122,17 @@
 /// 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 @@
   // 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 @@
 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 @@
         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 @@
   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 @@
   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 @@
   //     -- 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 @@
   //   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>();

Added: cfe/trunk/test/CodeCompletion/call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/call.cpp?rev=82549&view=auto

==============================================================================
--- cfe/trunk/test/CodeCompletion/call.cpp (added)
+++ cfe/trunk/test/CodeCompletion/call.cpp Tue Sep 22 10:41:20 2009
@@ -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(),

Propchange: cfe/trunk/test/CodeCompletion/call.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeCompletion/call.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeCompletion/call.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list