зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
8e0a0e4e45
Коммит
0594438e06
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче