diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp | 628 |
1 files changed, 628 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp new file mode 100644 index 0000000..6cefc61 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -0,0 +1,628 @@ +//===--- CodeCompleteConsumer.cpp - Code Completion Interface ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the CodeCompleteConsumer class. +// +//===----------------------------------------------------------------------===// +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/AST/DeclCXX.h" +#include "clang/Parse/Scope.h" +#include "clang/Lex/Preprocessor.h" +#include "clang-c/Index.h" +#include "Sema.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstring> +#include <functional> + +using namespace clang; +using llvm::StringRef; + +//===----------------------------------------------------------------------===// +// Code completion string implementation +//===----------------------------------------------------------------------===// +CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) + : Kind(Kind), Text("") +{ + switch (Kind) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_ResultType: + case CK_CurrentParameter: { + char *New = new char [Text.size() + 1]; + std::memcpy(New, Text.data(), Text.size()); + New[Text.size()] = '\0'; + this->Text = New; + break; + } + + case CK_Optional: + llvm_unreachable("Optional strings cannot be created from text"); + break; + + case CK_LeftParen: + this->Text = "("; + break; + + case CK_RightParen: + this->Text = ")"; + break; + + case CK_LeftBracket: + this->Text = "["; + break; + + case CK_RightBracket: + this->Text = "]"; + break; + + case CK_LeftBrace: + this->Text = "{"; + break; + + case CK_RightBrace: + this->Text = "}"; + break; + + case CK_LeftAngle: + this->Text = "<"; + break; + + case CK_RightAngle: + this->Text = ">"; + break; + + case CK_Comma: + this->Text = ", "; + break; + + case CK_Colon: + this->Text = ":"; + break; + + case CK_SemiColon: + this->Text = ";"; + break; + + case CK_Equal: + this->Text = " = "; + break; + + case CK_HorizontalSpace: + this->Text = " "; + break; + + case CK_VerticalSpace: + this->Text = "\n"; + break; + } +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateText(StringRef Text) { + return Chunk(CK_Text, Text); +} + +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(StringRef Placeholder) { + return Chunk(CK_Placeholder, Placeholder); +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateInformative(StringRef Informative) { + return Chunk(CK_Informative, Informative); +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateResultType(StringRef ResultType) { + return Chunk(CK_ResultType, ResultType); +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateCurrentParameter( + StringRef CurrentParameter) { + return Chunk(CK_CurrentParameter, CurrentParameter); +} + +CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const { + switch (Kind) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_ResultType: + case CK_CurrentParameter: + case CK_LeftParen: + case CK_RightParen: + case CK_LeftBracket: + case CK_RightBracket: + case CK_LeftBrace: + case CK_RightBrace: + case CK_LeftAngle: + case CK_RightAngle: + case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: + return Chunk(Kind, Text); + + case CK_Optional: { + std::auto_ptr<CodeCompletionString> Opt(Optional->Clone()); + return CreateOptional(Opt); + } + } + + // Silence GCC warning. + return Chunk(); +} + +void +CodeCompletionString::Chunk::Destroy() { + switch (Kind) { + case CK_Optional: + delete Optional; + break; + + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_ResultType: + case CK_CurrentParameter: + delete [] Text; + break; + + case CK_LeftParen: + case CK_RightParen: + case CK_LeftBracket: + case CK_RightBracket: + case CK_LeftBrace: + case CK_RightBrace: + case CK_LeftAngle: + case CK_RightAngle: + case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: + break; + } +} + +void CodeCompletionString::clear() { + std::for_each(Chunks.begin(), Chunks.end(), + std::mem_fun_ref(&Chunk::Destroy)); + Chunks.clear(); +} + +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_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break; + case CK_Placeholder: OS << "<#" << C->Text << "#>"; break; + + case CK_Informative: + case CK_ResultType: + OS << "[#" << C->Text << "#]"; + break; + + case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break; + default: OS << C->Text; break; + } + } + OS.flush(); + return Result; +} + +const char *CodeCompletionString::getTypedText() const { + for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) + if (C->Kind == CK_TypedText) + return C->Text; + + return 0; +} + +CodeCompletionString *CodeCompletionString::Clone() const { + CodeCompletionString *Result = new CodeCompletionString; + for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) + Result->AddChunk(C->Clone()); + return Result; +} + +static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) { + OS.write((const char *)&Value, sizeof(unsigned)); +} + +static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, + unsigned &Value) { + if (Memory + sizeof(unsigned) > MemoryEnd) + return true; + + memmove(&Value, Memory, sizeof(unsigned)); + Memory += sizeof(unsigned); + return false; +} + +void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { + // Write the number of chunks. + WriteUnsigned(OS, size()); + + for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { + WriteUnsigned(OS, C->Kind); + + switch (C->Kind) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_ResultType: + case CK_CurrentParameter: { + const char *Text = C->Text; + unsigned StrLen = strlen(Text); + WriteUnsigned(OS, StrLen); + OS.write(Text, StrLen); + break; + } + + case CK_Optional: + C->Optional->Serialize(OS); + break; + + case CK_LeftParen: + case CK_RightParen: + case CK_LeftBracket: + case CK_RightBracket: + case CK_LeftBrace: + case CK_RightBrace: + case CK_LeftAngle: + case CK_RightAngle: + case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: + break; + } + } +} + +bool CodeCompletionString::Deserialize(const char *&Str, const char *StrEnd) { + if (Str == StrEnd || *Str == 0) + return false; + + unsigned NumBlocks; + if (ReadUnsigned(Str, StrEnd, NumBlocks)) + return false; + + for (unsigned I = 0; I != NumBlocks; ++I) { + if (Str + 1 >= StrEnd) + break; + + // Parse the next kind. + unsigned KindValue; + if (ReadUnsigned(Str, StrEnd, KindValue)) + return false; + + switch (ChunkKind Kind = (ChunkKind)KindValue) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_ResultType: + case CK_CurrentParameter: { + unsigned StrLen; + if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd)) + return false; + + AddChunk(Chunk(Kind, StringRef(Str, StrLen))); + Str += StrLen; + break; + } + + case CK_Optional: { + std::auto_ptr<CodeCompletionString> Optional(new CodeCompletionString()); + if (Optional->Deserialize(Str, StrEnd)) + AddOptionalChunk(Optional); + break; + } + + case CK_LeftParen: + case CK_RightParen: + case CK_LeftBracket: + case CK_RightBracket: + case CK_LeftBrace: + case CK_RightBrace: + case CK_LeftAngle: + case CK_RightAngle: + case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: + AddChunk(Chunk(Kind)); + break; + } + }; + + return true; +} + +void CodeCompleteConsumer::Result::Destroy() { + if (Kind == RK_Pattern) { + delete Pattern; + Pattern = 0; + } +} + +unsigned CodeCompleteConsumer::Result::getPriorityFromDecl(NamedDecl *ND) { + if (!ND) + return CCP_Unlikely; + + // Context-based decisions. + DeclContext *DC = ND->getDeclContext()->getLookupContext(); + if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) + return CCP_LocalDeclaration; + if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) + return CCP_MemberDeclaration; + + // Content-based decisions. + if (isa<EnumConstantDecl>(ND)) + return CCP_Constant; + if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) + return CCP_Type; + return CCP_Declaration; +} + +//===----------------------------------------------------------------------===// +// 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 +//===----------------------------------------------------------------------===// + +CodeCompleteConsumer::~CodeCompleteConsumer() { } + +void +PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, + Result *Results, + unsigned NumResults) { + // Print the results. + for (unsigned I = 0; I != NumResults; ++I) { + OS << "COMPLETION: "; + switch (Results[I].Kind) { + case Result::RK_Declaration: + OS << Results[I].Declaration; + if (Results[I].Hidden) + OS << " (Hidden)"; + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + OS << " : " << CCS->getAsString(); + delete CCS; + } + + OS << '\n'; + break; + + case Result::RK_Keyword: + OS << Results[I].Keyword << '\n'; + break; + + case Result::RK_Macro: { + OS << Results[I].Macro->getName(); + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + OS << " : " << CCS->getAsString(); + delete CCS; + } + OS << '\n'; + break; + } + + case Result::RK_Pattern: { + OS << "Pattern : " + << Results[I].Pattern->getAsString() << '\n'; + break; + } + } + } +} + +void +PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, + unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + for (unsigned I = 0; I != NumCandidates; ++I) { + if (CodeCompletionString *CCS + = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { + OS << "OVERLOAD: " << CCS->getAsString() << "\n"; + delete CCS; + } + } +} + +void +CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, + Result *Results, + unsigned NumResults) { + // Print the results. + for (unsigned I = 0; I != NumResults; ++I) { + CXCursorKind Kind = CXCursor_NotImplemented; + + switch (Results[I].Kind) { + case Result::RK_Declaration: + switch (Results[I].Declaration->getKind()) { + case Decl::Record: + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: { + RecordDecl *Record = cast<RecordDecl>(Results[I].Declaration); + if (Record->isStruct()) + Kind = CXCursor_StructDecl; + else if (Record->isUnion()) + Kind = CXCursor_UnionDecl; + else + Kind = CXCursor_ClassDecl; + break; + } + + case Decl::ObjCMethod: { + ObjCMethodDecl *Method = cast<ObjCMethodDecl>(Results[I].Declaration); + if (Method->isInstanceMethod()) + Kind = CXCursor_ObjCInstanceMethodDecl; + else + Kind = CXCursor_ObjCClassMethodDecl; + break; + } + + case Decl::Typedef: + Kind = CXCursor_TypedefDecl; + break; + + case Decl::Enum: + Kind = CXCursor_EnumDecl; + break; + + case Decl::Field: + Kind = CXCursor_FieldDecl; + break; + + case Decl::EnumConstant: + Kind = CXCursor_EnumConstantDecl; + break; + + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + Kind = CXCursor_FunctionDecl; + break; + + case Decl::Var: + Kind = CXCursor_VarDecl; + break; + + case Decl::ParmVar: + Kind = CXCursor_ParmDecl; + break; + + case Decl::ObjCInterface: + Kind = CXCursor_ObjCInterfaceDecl; + break; + + case Decl::ObjCCategory: + Kind = CXCursor_ObjCCategoryDecl; + break; + + case Decl::ObjCProtocol: + Kind = CXCursor_ObjCProtocolDecl; + break; + + case Decl::ObjCProperty: + Kind = CXCursor_ObjCPropertyDecl; + break; + + case Decl::ObjCIvar: + Kind = CXCursor_ObjCIvarDecl; + break; + + case Decl::ObjCImplementation: + Kind = CXCursor_ObjCImplementationDecl; + break; + + case Decl::ObjCCategoryImpl: + Kind = CXCursor_ObjCCategoryImplDecl; + break; + + default: + break; + } + break; + + case Result::RK_Macro: + Kind = CXCursor_MacroDefinition; + break; + + case Result::RK_Keyword: + case Result::RK_Pattern: + Kind = CXCursor_NotImplemented; + break; + } + + WriteUnsigned(OS, Kind); + WriteUnsigned(OS, Results[I].Priority); + CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef); + assert(CCS && "No code-completion string?"); + CCS->Serialize(OS); + delete CCS; + } +} + +void +CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, + unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + for (unsigned I = 0; I != NumCandidates; ++I) { + WriteUnsigned(OS, CXCursor_NotImplemented); + WriteUnsigned(OS, /*Priority=*/0); + CodeCompletionString *CCS + = Candidates[I].CreateSignatureString(CurrentArg, SemaRef); + assert(CCS && "No code-completion string?"); + CCS->Serialize(OS); + delete CCS; + } +} |