forked from OSchip/llvm-project
Introduce code completion strings, which describe how to *use* the
results of code completion, e.g., by providing function call syntax with placeholders for each of the parameters. llvm-svn: 82293
This commit is contained in:
parent
b90893dc41
commit
fedc328ae9
|
@ -16,8 +16,11 @@
|
|||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
@ -31,6 +34,103 @@ class DeclContext;
|
|||
class NamedDecl;
|
||||
class Scope;
|
||||
class Sema;
|
||||
|
||||
/// \brief A "string" used to describe how code completion can
|
||||
/// be performed for an entity.
|
||||
///
|
||||
/// A code completion string typically shows how a particular entity can be
|
||||
/// used. For example, the code completion string for a function would show
|
||||
/// the syntax to call it, including the parentheses, placeholders for the
|
||||
/// arguments, etc.
|
||||
class CodeCompletionString {
|
||||
public:
|
||||
/// \brief The different kinds of "chunks" that can occur within a code
|
||||
/// completion string.
|
||||
enum ChunkKind {
|
||||
/// \brief A piece of text that should be placed in the buffer, e.g.,
|
||||
/// parentheses or a comma in a function call.
|
||||
CK_Text,
|
||||
/// \brief A code completion string that is entirely optional. For example,
|
||||
/// an optional code completion string that describes the default arguments
|
||||
/// in a function call.
|
||||
CK_Optional,
|
||||
/// \brief A string that acts as a placeholder for, e.g., a function
|
||||
/// call argument.
|
||||
CK_Placeholder
|
||||
};
|
||||
|
||||
/// \brief One piece of the code completion string.
|
||||
struct Chunk {
|
||||
/// \brief The kind of data stored in this piece of the code completion
|
||||
/// string.
|
||||
ChunkKind Kind;
|
||||
|
||||
union {
|
||||
/// \brief The text string associated with a CK_Text chunk.
|
||||
/// The string is owned by the chunk and will be deallocated
|
||||
/// (with delete[]) when the chunk is destroyed.
|
||||
const char *Text;
|
||||
|
||||
/// \brief The code completion string associated with a CK_Optional chunk.
|
||||
/// The optional code completion string is owned by the chunk, and will
|
||||
/// be deallocated (with delete) when the chunk is destroyed.
|
||||
CodeCompletionString *Optional;
|
||||
|
||||
/// \brief Placeholder text associated with a CK_Placeholder chunk.
|
||||
/// The string is owned by the chunk and will be deallocated (with
|
||||
/// delete[]) when the chunk is destroyed.
|
||||
const char *Placeholder;
|
||||
};
|
||||
|
||||
/// \brief Create a new text chunk.
|
||||
static Chunk CreateText(const char *Text);
|
||||
|
||||
/// \brief Create a new optional chunk.
|
||||
static Chunk CreateOptional(std::auto_ptr<CodeCompletionString> Optional);
|
||||
|
||||
/// \brief Create a new placeholder chunk.
|
||||
static Chunk CreatePlaceholder(const char *Placeholder);
|
||||
|
||||
/// \brief Destroy this chunk.
|
||||
void Destroy();
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief The chunks stored in this string.
|
||||
llvm::SmallVector<Chunk, 4> Chunks;
|
||||
|
||||
CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT
|
||||
CodeCompletionString &operator=(const CodeCompletionString &); // DITTO
|
||||
|
||||
public:
|
||||
CodeCompletionString() { }
|
||||
~CodeCompletionString();
|
||||
|
||||
typedef llvm::SmallVector<Chunk, 4>::const_iterator iterator;
|
||||
iterator begin() const { return Chunks.begin(); }
|
||||
iterator end() const { return Chunks.end(); }
|
||||
|
||||
/// \brief Add a new text chunk.
|
||||
/// The text string will be copied.
|
||||
void AddTextChunk(const char *Text) {
|
||||
Chunks.push_back(Chunk::CreateText(Text));
|
||||
}
|
||||
|
||||
/// \brief Add a new optional chunk.
|
||||
void AddOptionalChunk(std::auto_ptr<CodeCompletionString> Optional) {
|
||||
Chunks.push_back(Chunk::CreateOptional(Optional));
|
||||
}
|
||||
|
||||
/// \brief Add a new placeholder chunk.
|
||||
/// The placeholder text will be copied.
|
||||
void AddPlaceholderChunk(const char *Placeholder) {
|
||||
Chunks.push_back(Chunk::CreatePlaceholder(Placeholder));
|
||||
}
|
||||
|
||||
/// \brief Retrieve a string representation of the code completion string,
|
||||
/// which is mainly useful for debugging.
|
||||
std::string getAsString() const;
|
||||
};
|
||||
|
||||
/// \brief Abstract interface for a consumer of code-completion
|
||||
/// information.
|
||||
|
@ -264,6 +364,7 @@ public:
|
|||
//@{
|
||||
bool canHiddenResultBeFound(NamedDecl *Hidden, NamedDecl *Visible);
|
||||
void AddTypeSpecifierResults(unsigned Rank, ResultSet &Results);
|
||||
CodeCompletionString *CreateCodeCompletionString(Result R);
|
||||
//@}
|
||||
};
|
||||
|
||||
|
|
|
@ -19,9 +19,75 @@
|
|||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Code completion string implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
CodeCompletionString::Chunk
|
||||
CodeCompletionString::Chunk::CreateText(const char *Text) {
|
||||
Chunk Result;
|
||||
Result.Kind = CK_Text;
|
||||
char *New = new char [std::strlen(Text) + 1];
|
||||
std::strcpy(New, Text);
|
||||
Result.Text = New;
|
||||
return Result;
|
||||
}
|
||||
|
||||
CodeCompletionString::Chunk
|
||||
CodeCompletionString::Chunk::CreateOptional(
|
||||
std::auto_ptr<CodeCompletionString> Optional) {
|
||||
Chunk Result;
|
||||
Result.Kind = CK_Optional;
|
||||
Result.Optional = Optional.release();
|
||||
return Result;
|
||||
}
|
||||
|
||||
CodeCompletionString::Chunk
|
||||
CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
|
||||
Chunk Result;
|
||||
Result.Kind = CK_Placeholder;
|
||||
char *New = new char [std::strlen(Placeholder) + 1];
|
||||
std::strcpy(New, Placeholder);
|
||||
Result.Placeholder = New;
|
||||
return Result;
|
||||
}
|
||||
|
||||
void
|
||||
CodeCompletionString::Chunk::Destroy() {
|
||||
switch (Kind) {
|
||||
case CK_Text: delete [] Text; break;
|
||||
case CK_Optional: delete Optional; break;
|
||||
case CK_Placeholder: delete [] Placeholder; break;
|
||||
}
|
||||
}
|
||||
|
||||
CodeCompletionString::~CodeCompletionString() {
|
||||
std::for_each(Chunks.begin(), Chunks.end(),
|
||||
std::mem_fun_ref(&Chunk::Destroy));
|
||||
}
|
||||
|
||||
std::string CodeCompletionString::getAsString() const {
|
||||
std::string Result;
|
||||
llvm::raw_string_ostream OS(Result);
|
||||
|
||||
for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
|
||||
switch (C->Kind) {
|
||||
case CK_Text: OS << C->Text; break;
|
||||
case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
|
||||
case CK_Placeholder: OS << "<#" << C->Placeholder << "#>"; break;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Code completion consumer implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CodeCompleteConsumer::CodeCompleteConsumer(Sema &S) : SemaRef(S) {
|
||||
SemaRef.setCodeCompleteConsumer(this);
|
||||
}
|
||||
|
@ -180,7 +246,7 @@ void CodeCompleteConsumer::CodeCompleteOperatorName(Scope *S) {
|
|||
|
||||
// Add the names of overloadable operators.
|
||||
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
|
||||
if (strcmp(Spelling, "?")) \
|
||||
if (std::strcmp(Spelling, "?")) \
|
||||
Results.MaybeAddResult(Result(Spelling, 0));
|
||||
#include "clang/Basic/OperatorKinds.def"
|
||||
|
||||
|
@ -663,6 +729,64 @@ void CodeCompleteConsumer::AddTypeSpecifierResults(unsigned Rank,
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Add function parameter chunks to the given code completion string.
|
||||
static void AddFunctionParameterChunks(ASTContext &Context,
|
||||
FunctionDecl *Function,
|
||||
CodeCompletionString *Result) {
|
||||
CodeCompletionString *CCStr = Result;
|
||||
|
||||
for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) {
|
||||
ParmVarDecl *Param = Function->getParamDecl(P);
|
||||
|
||||
if (Param->hasDefaultArg()) {
|
||||
// When we see an optional default argument, put that argument and
|
||||
// the remaining default arguments into a new, optional string.
|
||||
CodeCompletionString *Opt = new CodeCompletionString;
|
||||
CCStr->AddOptionalChunk(std::auto_ptr<CodeCompletionString>(Opt));
|
||||
CCStr = Opt;
|
||||
}
|
||||
|
||||
if (P != 0)
|
||||
CCStr->AddTextChunk(", ");
|
||||
|
||||
// Format the placeholder string.
|
||||
std::string PlaceholderStr;
|
||||
if (Param->getIdentifier())
|
||||
PlaceholderStr = Param->getIdentifier()->getName();
|
||||
|
||||
Param->getType().getAsStringInternal(PlaceholderStr,
|
||||
Context.PrintingPolicy);
|
||||
|
||||
// Add the placeholder string.
|
||||
CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief If possible, create a new code completion string for the given
|
||||
/// result.
|
||||
///
|
||||
/// \returns Either a new, heap-allocated code completion string describing
|
||||
/// how to use this result, or NULL to indicate that the string or name of the
|
||||
/// result is all that is needed.
|
||||
CodeCompletionString *
|
||||
CodeCompleteConsumer::CreateCodeCompletionString(Result R) {
|
||||
if (R.Kind != Result::RK_Declaration)
|
||||
return 0;
|
||||
|
||||
NamedDecl *ND = R.Declaration;
|
||||
|
||||
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
|
||||
CodeCompletionString *Result = new CodeCompletionString;
|
||||
Result->AddTextChunk(Function->getNameAsString().c_str());
|
||||
Result->AddTextChunk("(");
|
||||
AddFunctionParameterChunks(getSema().Context, Function, Result);
|
||||
Result->AddTextChunk(")");
|
||||
return Result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
|
||||
unsigned NumResults) {
|
||||
|
@ -677,6 +801,11 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results,
|
|||
<< Results[I].Rank;
|
||||
if (Results[I].Hidden)
|
||||
OS << " (Hidden)";
|
||||
if (CodeCompletionString *CCS = CreateCodeCompletionString(Results[I])) {
|
||||
OS << " : " << CCS->getAsString();
|
||||
delete CCS;
|
||||
}
|
||||
|
||||
OS << '\n';
|
||||
break;
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
void f(int i, int j = 2, int k = 5);
|
||||
void f(float x, float y);
|
||||
|
||||
void test() {
|
||||
// CHECK-CC1: f(<#int i#>{#, <#int j#>{#, <#int k#>#}#})
|
||||
// CHECK-CC1: f(<#float x#>, <#float y#>)
|
||||
::
|
Loading…
Reference in New Issue