]> granicus.if.org Git - clang/commitdiff
Separate the code-completion results for call completion from the
authorDouglas Gregor <dgregor@apple.com>
Wed, 23 Sep 2009 00:16:58 +0000 (00:16 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 23 Sep 2009 00:16:58 +0000 (00:16 +0000)
results for other, textual completion. For call completion, we now
produce enough information to show the function call argument that we
are currently on.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82592 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/CodeCompleteConsumer.h
lib/Sema/CodeCompleteConsumer.cpp
lib/Sema/SemaCodeComplete.cpp
test/CodeCompletion/call.cpp

index d18b4a732f22bec69df3672144e760fdb61e9e90..058012cd1299342cabefdafcc225d0e4be473b48 100644 (file)
@@ -22,7 +22,10 @@ class raw_ostream;
 }
 
 namespace clang {
-  
+
+class FunctionDecl;
+class FunctionType;
+class FunctionTemplateDecl;
 class NamedDecl;
 class NestedNameSpecifier;
 class Sema;
@@ -213,6 +216,65 @@ public:
     CodeCompletionString *CreateCodeCompletionString(Sema &S);
   };
     
+  class OverloadCandidate {
+  public:
+    /// \brief Describes the type of overload candidate.
+    enum CandidateKind {
+      /// \brief The candidate is a function declaration.
+      CK_Function,
+      /// \brief The candidate is a function template.
+      CK_FunctionTemplate,
+      /// \brief The "candidate" is actually a variable, expression, or block
+      /// for which we only have a function prototype.
+      CK_FunctionType
+    };
+    
+  private:
+    /// \brief The kind of overload candidate.
+    CandidateKind Kind;
+    
+    union {
+      /// \brief The function overload candidate, available when 
+      /// Kind == CK_Function.
+      FunctionDecl *Function;
+      
+      /// \brief The function template overload candidate, available when
+      /// Kind == CK_FunctionTemplate.
+      FunctionTemplateDecl *FunctionTemplate;
+      
+      /// \brief The function type that describes the entity being called,
+      /// when Kind == CK_FunctionType.
+      const FunctionType *Type;
+    };
+    
+  public:
+    OverloadCandidate(FunctionDecl *Function)
+      : Kind(CK_Function), Function(Function) { }
+
+    OverloadCandidate(FunctionTemplateDecl *FunctionTemplateDecl)
+      : Kind(CK_FunctionTemplate), FunctionTemplate(FunctionTemplate) { }
+
+    OverloadCandidate(const FunctionType *Type)
+      : Kind(CK_FunctionType), Type(Type) { }
+
+    /// \brief Determine the kind of overload candidate.
+    CandidateKind getKind() const { return Kind; }
+    
+    /// \brief Retrieve the function overload candidate or the templated 
+    /// function declaration for a function template.
+    FunctionDecl *getFunction() const;
+    
+    /// \brief Retrieve the function template overload candidate.
+    FunctionTemplateDecl *getFunctionTemplate() const {
+      assert(getKind() == CK_FunctionTemplate && "Not a function template");
+      return FunctionTemplate;
+    }
+    
+    /// \brief Retrieve the function type of the entity, regardless of how the
+    /// function is stored.
+    const FunctionType *getFunctionType() const;
+  };
+  
   /// \brief Deregisters and destroys this code-completion consumer.
   virtual ~CodeCompleteConsumer();
     
@@ -221,6 +283,17 @@ public:
   /// \brief Process the finalized code-completion results.
   virtual void ProcessCodeCompleteResults(Result *Results, 
                                           unsigned NumResults) { }
+  
+  /// \brief Process the set of overload candidates.
+  ///
+  /// \param CurrentArg the index of the current argument.
+  ///
+  /// \param Candidates an array of overload candidates.
+  ///
+  /// \param NumCandidates the number of overload candidates
+  virtual void ProcessOverloadCandidates(unsigned CurrentArg,
+                                         OverloadCandidate *Candidates,
+                                         unsigned NumCandidates) { }
   //@}
 };
   
@@ -243,6 +316,10 @@ public:
   /// \brief Prints the finalized code-completion results.
   virtual void ProcessCodeCompleteResults(Result *Results, 
                                           unsigned NumResults);
+  
+  virtual void ProcessOverloadCandidates(unsigned CurrentArg,
+                                         OverloadCandidate *Candidates,
+                                         unsigned NumCandidates);  
 };
   
 } // end namespace clang
index f490a2b5235a8334b980aed9ed59b9a78953bcf0..f1b475a6df5c8858453722039c36c101ef25e465 100644 (file)
@@ -96,6 +96,36 @@ std::string CodeCompletionString::getAsString() const {
   return Result;
 }
 
+//===----------------------------------------------------------------------===//
+// Code completion overload candidate implementation
+//===----------------------------------------------------------------------===//
+FunctionDecl *
+CodeCompleteConsumer::OverloadCandidate::getFunction() const {
+  if (getKind() == CK_Function)
+    return Function;
+  else if (getKind() == CK_FunctionTemplate)
+    return FunctionTemplate->getTemplatedDecl();
+  else
+    return 0;
+}
+
+const FunctionType *
+CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {
+  switch (Kind) {
+  case CK_Function:
+    return Function->getType()->getAs<FunctionType>();
+      
+  case CK_FunctionTemplate:
+    return FunctionTemplate->getTemplatedDecl()->getType()
+             ->getAs<FunctionType>();
+      
+  case CK_FunctionType:
+    return Type;
+  }
+  
+  return 0;
+}
+
 //===----------------------------------------------------------------------===//
 // Code completion consumer implementation
 //===----------------------------------------------------------------------===//
@@ -133,3 +163,37 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
   // FIXME: Move this somewhere else!
   SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
 }
+
+void 
+PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg,
+                                              OverloadCandidate *Candidates,
+                                                     unsigned NumCandidates) {
+  for (unsigned I = 0; I != NumCandidates; ++I) {
+    std::string ArgString;
+    QualType ArgType;
+    
+    if (FunctionDecl *Function = Candidates[I].getFunction()) {
+      if (CurrentArg < Function->getNumParams()) {
+        ArgString = Function->getParamDecl(CurrentArg)->getNameAsString();
+        ArgType = Function->getParamDecl(CurrentArg)->getOriginalType();
+      }
+    } else if (const FunctionProtoType *Proto 
+                 = dyn_cast<FunctionProtoType>(
+                                            Candidates[I].getFunctionType())) {
+      if (CurrentArg < Proto->getNumArgs())
+        ArgType = Proto->getArgType(CurrentArg);
+    }
+    
+    if (ArgType.isNull())
+      OS << "...\n";  // We have no prototype or we're matching an ellipsis.
+    else {
+      ArgType.getAsStringInternal(ArgString, SemaRef.Context.PrintingPolicy);
+      OS << ArgString << "\n";
+    }
+  }
+
+  // Once we've printed the code-completion results, suppress remaining
+  // diagnostics.
+  // FIXME: Move this somewhere else!
+  SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
+}
index ec01941901ec98635669027ac144178ddd83beb1..754d505bc0212cf24a044bc71ebfc7273490d4b3 100644 (file)
@@ -1161,19 +1161,17 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
                    IsBetterOverloadCandidate(*this));
   
   // Add the remaining viable overload candidates as code-completion reslults.  
-  typedef CodeCompleteConsumer::Result Result;
-  ResultBuilder Results(*this);
-  Results.EnterNewScope();
+  typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;
+  llvm::SmallVector<ResultCandidate, 8> Results;
   
   for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
                                    CandEnd = CandidateSet.end();
        Cand != CandEnd; ++Cand) {
     if (Cand->Viable)
-      Results.MaybeAddResult(Result(Cand->Function, 0), 0);
+      Results.push_back(ResultCandidate(Cand->Function));
   }
-  
-  Results.ExitScope();
-  HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+  CodeCompleter->ProcessOverloadCandidates(NumArgs, Results.data(), 
+                                           Results.size());
 }
 
 void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
index dd90083874c9ff0d8d3b660222df8d43ed3a2a30..9a6f578abc91018b85c1ef66b0265370f8c28233 100644 (file)
@@ -10,7 +10,7 @@ namespace N {
     
     operator int() const;
   };
-  void f(Y y, int);
+  void f(Y y, int ZZ);
 }
 typedef N::Y Y;
 void f();
@@ -18,12 +18,11 @@ void f();
 void test() {
   f(Y(), 0, 0);
   // RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC1 %s &&
-  // CHECK-CC1: f : 0 : f(<#struct N::Y y#>, <#int#>)
-  // CHECK-NEXT-CC1: f : 0 : f(<#int i#>, <#int j#>, <#int k#>)
-  // CHECK-NEXT-CC1: f : 0 : f(<#float x#>, <#float y#>)
+  // CHECK-CC1: int ZZ
+  // CHECK-NEXT-CC1: int j
+  // CHECK-NEXT-CC1: float y
   // RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:13 %s -o - | FileCheck -check-prefix=CC2 %s &&
-  // CHECK-NOT-CC2: f : 0 : f(<#struct N::Y y#>, <#int#>)
-  // CHECK-CC2: f : 0 : f(<#int i#>, <#int j#>, <#int k#>)
-  // CHECK-NEXT-CC2: f : 0 : f(<#float x#>, <#float y#>)
+  // FIXME: two ellipses are showing up when they shouldn't
+  // CHECK-CC2: int k
   // RUN: true
 }