diff options
-rw-r--r-- | include/clang/Sema/CodeCompleteConsumer.h | 79 | ||||
-rw-r--r-- | lib/Sema/CodeCompleteConsumer.cpp | 64 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 12 | ||||
-rw-r--r-- | test/CodeCompletion/call.cpp | 13 |
4 files changed, 153 insertions, 15 deletions
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 @@ -97,6 +97,36 @@ std::string CodeCompletionString::getAsString() const { } //===----------------------------------------------------------------------===// +// 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(); +} 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<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, 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 } |