#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 {
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.
//@{
bool canHiddenResultBeFound(NamedDecl *Hidden, NamedDecl *Visible);
void AddTypeSpecifierResults(unsigned Rank, ResultSet &Results);
+ CodeCompletionString *CreateCodeCompletionString(Result R);
//@}
};
#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);
}
// 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"
}
}
+/// \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) {
<< Results[I].Rank;
if (Results[I].Hidden)
OS << " (Hidden)";
+ if (CodeCompletionString *CCS = CreateCodeCompletionString(Results[I])) {
+ OS << " : " << CCS->getAsString();
+ delete CCS;
+ }
+
OS << '\n';
break;