aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h79
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp64
-rw-r--r--lib/Sema/SemaCodeComplete.cpp12
-rw-r--r--test/CodeCompletion/call.cpp13
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
}