From: Douglas Gregor Date: Wed, 23 Sep 2009 00:16:58 +0000 (+0000) Subject: Separate the code-completion results for call completion from the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0594438e06f58ab3798416324780ab39ca9c8f54;p=clang Separate the code-completion results for call completion from the 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 --- diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index d18b4a732f..058012cd12 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -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 diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index f490a2b523..f1b475a6df 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -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(); + + case CK_FunctionTemplate: + return FunctionTemplate->getTemplatedDecl()->getType() + ->getAs(); + + 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( + 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(); +} diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index ec01941901..754d505bc0 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -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 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, diff --git a/test/CodeCompletion/call.cpp b/test/CodeCompletion/call.cpp index dd90083874..9a6f578abc 100644 --- a/test/CodeCompletion/call.cpp +++ b/test/CodeCompletion/call.cpp @@ -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 }