#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/ADT/StringSwitch.h"
return Result;
}
-namespace {
- // Escape a string for XML-like formatting.
- struct EscapedString {
- EscapedString(llvm::StringRef Str) : Str(Str) { }
-
- llvm::StringRef Str;
- };
-
- llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) {
- llvm::StringRef Str = EStr.Str;
- while (!Str.empty()) {
- // Find the next escaped character.
- llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'");
-
- // Print everything before that escaped character.
- OS << Str.substr(0, Pos);
+static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
+ OS.write((const char *)&Value, sizeof(unsigned));
+}
- // If we didn't find any escaped characters, we're done.
- if (Pos == llvm::StringRef::npos)
- break;
-
- // Print the appropriate escape sequence.
- switch (Str[Pos]) {
- case '<': OS << "<"; break;
- case '>': OS << ">"; break;
- case '&': OS << "&"; break;
- case '"': OS << """; break;
- case '\'': OS << "'"; break;
- }
-
- // Remove everything up to and including that escaped character.
- Str = Str.substr(Pos + 1);
- }
-
- return OS;
- }
-
- /// \brief Remove XML-like escaping from a string.
- std::string UnescapeString(llvm::StringRef Str) {
- using llvm::StringRef;
-
- std::string Result;
- llvm::raw_string_ostream OS(Result);
-
- while (!Str.empty()) {
- StringRef::size_type Amp = Str.find('&');
- OS << Str.substr(0, Amp);
-
- if (Amp == StringRef::npos)
- break;
-
- StringRef::size_type Semi = Str.substr(Amp).find(';');
- if (Semi == StringRef::npos) {
- // Malformed input; do the best we can.
- OS << '&';
- Str = Str.substr(Amp + 1);
- continue;
- }
-
- char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1))
- .Case("lt", '<')
- .Case("gt", '>')
- .Case("amp", '&')
- .Case("quot", '"')
- .Case("apos", '\'')
- .Default('\0');
-
- if (Unescaped)
- OS << Unescaped;
- else
- OS << Str.substr(Amp, Semi + 1);
- Str = Str.substr(Amp + Semi + 1);
- }
-
- return OS.str();
- }
+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:
- OS << "<typed-text>" << EscapedString(C->Text) << "</>";
- break;
case CK_Text:
- OS << "<text>" << EscapedString(C->Text) << "</>";
- break;
- case CK_Optional:
- OS << "<optional>";
- C->Optional->Serialize(OS);
- OS << "</>";
- break;
case CK_Placeholder:
- OS << "<placeholder>" << EscapedString(C->Text) << "</>";
- break;
case CK_Informative:
- OS << "<informative>" << EscapedString(C->Text) << "</>";
+ case CK_CurrentParameter: {
+ const char *Text = C->Text;
+ unsigned StrLen = strlen(Text);
+ WriteUnsigned(OS, StrLen);
+ OS.write(Text, StrLen);
break;
- case CK_CurrentParameter:
- OS << "<current-parameter>" << EscapedString(C->Text) << "</>";
+ }
+
+ case CK_Optional:
+ C->Optional->Serialize(OS);
break;
+
case CK_LeftParen:
- OS << "<lparen/>";
- break;
case CK_RightParen:
- OS << "<rparen/>";
- break;
case CK_LeftBracket:
- OS << "<lbracket/>";
- break;
case CK_RightBracket:
- OS << "<rbracket/>";
- break;
case CK_LeftBrace:
- OS << "<lbrace/>";
- break;
case CK_RightBrace:
- OS << "<rbrace/>";
- break;
case CK_LeftAngle:
- OS << "<langle/>";
- break;
case CK_RightAngle:
- OS << "<rangle/>";
- break;
case CK_Comma:
- OS << "<comma/>";
break;
- }
+ }
}
}
-/// \brief Parse the next XML-ish tag of the form <blah>.
-///
-/// \param Str the string in which we're looking for the next tag.
-///
-/// \param TagPos if successful, will be set to the start of the tag we found.
-///
-/// \param Standalone will indicate whether this is a "standalone" tag that
-/// has no associated data, e.g., <comma/>.
-///
-/// \param Terminator will indicate whether this is a terminating tag (that is
-/// or starts with '/').
-///
-/// \returns the tag itself, without the angle brackets.
-static llvm::StringRef ParseNextTag(llvm::StringRef Str,
- llvm::StringRef::size_type &StartTag,
- llvm::StringRef::size_type &AfterTag,
- bool &Standalone, bool &Terminator) {
- using llvm::StringRef;
-
- Standalone = false;
- Terminator = false;
- AfterTag = StringRef::npos;
-
- // Find the starting '<'.
- StartTag = Str.find('<');
- if (StartTag == StringRef::npos)
- return llvm::StringRef();
-
- // Find the corresponding '>'.
- llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>');
- if (EndTag == StringRef::npos)
- return llvm::StringRef();
- AfterTag = StartTag + EndTag + 1;
-
- // Determine whether this is a terminating tag.
- if (Str[StartTag + 1] == '/') {
- Terminator = true;
- Str = Str.substr(1);
- --EndTag;
- }
-
- // Determine whether this is a standalone tag.
- if (!Terminator && Str[StartTag + EndTag - 1] == '/') {
- Standalone = true;
- if (EndTag > 1)
- --EndTag;
- }
-
- return Str.substr(StartTag + 1, EndTag - 1);
-}
+CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
+ const char *StrEnd) {
+ if (Str == StrEnd || *Str == 0)
+ return 0;
-CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) {
- using llvm::StringRef;
-
CodeCompletionString *Result = new CodeCompletionString;
-
- do {
- // Parse the next tag.
- StringRef::size_type StartTag, AfterTag;
- bool Standalone, Terminator;
- StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
- Terminator);
-
- if (StartTag == StringRef::npos)
+ unsigned NumBlocks;
+ if (ReadUnsigned(Str, StrEnd, NumBlocks))
+ return Result;
+
+ for (unsigned I = 0; I != NumBlocks; ++I) {
+ if (Str + 1 >= StrEnd)
break;
-
- // Figure out what kind of chunk we have.
- const unsigned UnknownKind = 10000;
- unsigned Kind = llvm::StringSwitch<unsigned>(Tag)
- .Case("typed-text", CK_TypedText)
- .Case("text", CK_Text)
- .Case("optional", CK_Optional)
- .Case("placeholder", CK_Placeholder)
- .Case("informative", CK_Informative)
- .Case("current-parameter", CK_CurrentParameter)
- .Case("lparen", CK_LeftParen)
- .Case("rparen", CK_RightParen)
- .Case("lbracket", CK_LeftBracket)
- .Case("rbracket", CK_RightBracket)
- .Case("lbrace", CK_LeftBrace)
- .Case("rbrace", CK_RightBrace)
- .Case("langle", CK_LeftAngle)
- .Case("rangle", CK_RightAngle)
- .Case("comma", CK_Comma)
- .Default(UnknownKind);
-
- // If we've hit a terminator tag, we're done.
- if (Terminator)
+
+ // Parse the next kind.
+ unsigned KindValue;
+ if (ReadUnsigned(Str, StrEnd, KindValue))
+ return Result;
+
+ switch (ChunkKind Kind = (ChunkKind)KindValue) {
+ case CK_TypedText:
+ case CK_Text:
+ case CK_Placeholder:
+ case CK_Informative:
+ case CK_CurrentParameter: {
+ unsigned StrLen;
+ if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd))
+ return Result;
+
+ Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen)));
+ Str += StrLen;
break;
-
- // Consume the tag.
- Str = Str.substr(AfterTag);
-
- // Handle standalone tags now, since they don't need to be matched to
- // anything.
- if (Standalone) {
- // Ignore anything we don't know about.
- if (Kind == UnknownKind)
- continue;
-
- switch ((ChunkKind)Kind) {
- case CK_TypedText:
- case CK_Text:
- case CK_Optional:
- case CK_Placeholder:
- case CK_Informative:
- case CK_CurrentParameter:
- // There is no point in creating empty chunks of these kinds.
- 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:
- Result->AddChunk(Chunk((ChunkKind)Kind));
- break;
- }
-
- continue;
}
-
- if (Kind == CK_Optional) {
- // Deserialize the optional code-completion string.
- std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str));
+
+ case CK_Optional: {
+ std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str, StrEnd));
Result->AddOptionalChunk(Optional);
+ break;
}
-
- StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone,
- Terminator);
- if (StartTag == StringRef::npos || !Terminator || Standalone)
- break; // Parsing failed; just give up.
-
- if (EndTag.empty() || Tag == EndTag) {
- // Found the matching end tag. Add this chunk based on the text
- // between the tags, then consume that input.
- StringRef Text = Str.substr(0, StartTag);
- switch ((ChunkKind)Kind) {
- case CK_TypedText:
- case CK_Text:
- case CK_Placeholder:
- case CK_Informative:
- 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:
- Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text)));
- break;
-
- case CK_Optional:
- // We've already added the optional chunk.
- 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:
+ Result->AddChunk(Chunk(Kind));
+ break;
}
-
- // Remove this tag.
- Str = Str.substr(AfterTag);
- } while (!Str.empty());
+ };
return Result;
}
unsigned NumResults) {
// Print the results.
for (unsigned I = 0; I != NumResults; ++I) {
- OS << "COMPLETION:" << Results[I].Rank << ":";
+ CXCursorKind Kind = CXCursor_NotImplemented;
+
switch (Results[I].Kind) {
- case Result::RK_Declaration:
- if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) {
- if (Record->isStruct())
- OS << "Struct:";
- else if (Record->isUnion())
- OS << "Union:";
- else
- OS << "Class:";
- } else if (ObjCMethodDecl *Method
- = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) {
- if (Method->isInstanceMethod())
- OS << "ObjCInstanceMethod:";
- else
- OS << "ObjCClassMethod:";
- } else {
- OS << Results[I].Declaration->getDeclKindName() << ":";
- }
- if (CodeCompletionString *CCS
- = Results[I].CreateCodeCompletionString(SemaRef)) {
- CCS->Serialize(OS);
- delete CCS;
- } else {
- OS << "<typed-text>"
- << Results[I].Declaration->getNameAsString()
- << "</>";
- }
+ 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;
+ }
- OS << '\n';
+ case Decl::Typedef:
+ Kind = CXCursor_TypedefDecl;
break;
- case Result::RK_Keyword:
- OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n";
+ case Decl::Enum:
+ Kind = CXCursor_EnumDecl;
break;
- case Result::RK_Macro: {
- OS << "Macro:";
- if (CodeCompletionString *CCS
- = Results[I].CreateCodeCompletionString(SemaRef)) {
- CCS->Serialize(OS);
- delete CCS;
- } else {
- OS << "<typed-text>" << Results[I].Macro->getName() << "</>";
- }
- OS << '\n';
+ 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 Result::RK_Pattern: {
- OS << "Pattern:";
- Results[I].Pattern->Serialize(OS);
- OS << '\n';
+ case Decl::ObjCProperty:
+ Kind = CXCursor_ObjCPropertyDecl;
+ break;
+
+ case Decl::ObjCIvar:
+ Kind = CXCursor_ObjCIvarDecl;
+ break;
+
+ case Decl::ObjCImplementation:
+ Kind = CXCursor_ObjCClassDefn;
+ break;
+
+ case Decl::ObjCCategoryImpl:
+ Kind = CXCursor_ObjCCategoryDefn;
+ break;
+
+ default:
break;
}
+ break;
+
+ case Result::RK_Keyword:
+ case Result::RK_Macro:
+ case Result::RK_Pattern:
+ Kind = CXCursor_NotImplemented;
+ break;
}
+
+ WriteUnsigned(OS, Kind);
+ CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef);
+ assert(CCS && "No code-completion string?");
+ CCS->Serialize(OS);
+ delete CCS;
}
// Once we've printed the code-completion results, suppress remaining
OverloadCandidate *Candidates,
unsigned NumCandidates) {
for (unsigned I = 0; I != NumCandidates; ++I) {
- if (CodeCompletionString *CCS
- = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
- OS << "OVERLOAD:";
- CCS->Serialize(OS);
- OS << '\n';
- delete CCS;
- }
+ WriteUnsigned(OS, CXCursor_NotImplemented);
+ CodeCompletionString *CCS
+ = Candidates[I].CreateSignatureString(CurrentArg, SemaRef);
+ assert(CCS && "No code-completion string?");
+ CCS->Serialize(OS);
+ delete CCS;
}
// Once we've printed the code-completion results, suppress remaining
CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
typedef CodeCompletionString::Chunk Chunk;
- if (Kind == RK_Keyword)
- return 0;
+ if (Kind == RK_Pattern)
+ return Pattern->Clone();
+
+ CodeCompletionString *Result = new CodeCompletionString;
+
+ if (Kind == RK_Keyword) {
+ Result->AddTypedTextChunk(Keyword);
+ return Result;
+ }
if (Kind == RK_Macro) {
MacroInfo *MI = S.PP.getMacroInfo(Macro);
- if (!MI || !MI->isFunctionLike())
- return 0;
+ assert(MI && "Not a macro?");
+
+ Result->AddTypedTextChunk(Macro->getName());
+
+ if (!MI->isFunctionLike())
+ return Result;
// Format a function-like macro with placeholders for the arguments.
- CodeCompletionString *Result = new CodeCompletionString;
- Result->AddTypedTextChunk(Macro->getName());
Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end();
A != AEnd; ++A) {
NamedDecl *ND = Declaration;
if (StartsNestedNameSpecifier) {
- CodeCompletionString *Result = new CodeCompletionString;
Result->AddTypedTextChunk(ND->getNameAsString());
Result->AddTextChunk("::");
return Result;
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
- CodeCompletionString *Result = new CodeCompletionString;
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
Result->AddTypedTextChunk(Function->getNameAsString());
}
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
- CodeCompletionString *Result = new CodeCompletionString;
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
FunctionDecl *Function = FunTmpl->getTemplatedDecl();
}
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
- CodeCompletionString *Result = new CodeCompletionString;
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
Result->AddTypedTextChunk(Template->getNameAsString());
}
if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
- CodeCompletionString *Result = new CodeCompletionString;
Selector Sel = Method->getSelector();
if (Sel.isUnarySelector()) {
Result->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName());
return Result;
}
- if (Qualifier) {
- CodeCompletionString *Result = new CodeCompletionString;
+ if (Qualifier)
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
S.Context);
- Result->AddTypedTextChunk(ND->getNameAsString());
- return Result;
- }
-
- return 0;
+
+ Result->AddTypedTextChunk(ND->getNameAsString());
+ return Result;
}
CodeCompletionString *
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/ASTUnit.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
return CCStr? CCStr->size() : 0;
}
-static CXCursorKind parseResultKind(llvm::StringRef Str) {
- return llvm::StringSwitch<CXCursorKind>(Str)
- .Case("Typedef", CXCursor_TypedefDecl)
- .Case("Struct", CXCursor_StructDecl)
- .Case("Union", CXCursor_UnionDecl)
- .Case("Class", CXCursor_ClassDecl)
- .Case("Enum", CXCursor_EnumDecl)
- .Case("Field", CXCursor_FieldDecl)
- .Case("EnumConstant", CXCursor_EnumConstantDecl)
- .Case("Function", CXCursor_FunctionDecl)
- // FIXME: Hacks here to make C++ member functions look like C functions
- .Case("CXXMethod", CXCursor_FunctionDecl)
- .Case("CXXConstructor", CXCursor_FunctionDecl)
- .Case("CXXDestructor", CXCursor_FunctionDecl)
- .Case("CXXConversion", CXCursor_FunctionDecl)
- .Case("Var", CXCursor_VarDecl)
- .Case("ParmVar", CXCursor_ParmDecl)
- .Case("ObjCInterface", CXCursor_ObjCInterfaceDecl)
- .Case("ObjCCategory", CXCursor_ObjCCategoryDecl)
- .Case("ObjCProtocol", CXCursor_ObjCProtocolDecl)
- .Case("ObjCProperty", CXCursor_ObjCPropertyDecl)
- .Case("ObjCIvar", CXCursor_ObjCIvarDecl)
- .Case("ObjCInstanceMethod", CXCursor_ObjCInstanceMethodDecl)
- .Case("ObjCClassMethod", CXCursor_ObjCClassMethodDecl)
- .Default(CXCursor_NotImplemented);
+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 clang_codeComplete(CXIndex CIdx,
using llvm::StringRef;
if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
StringRef Buffer = F->getBuffer();
- do {
- StringRef::size_type CompletionIdx = Buffer.find("COMPLETION:");
- StringRef::size_type OverloadIdx = Buffer.find("OVERLOAD:");
- if (CompletionIdx == StringRef::npos && OverloadIdx == StringRef::npos)
+ for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
+ Str < StrEnd;) {
+ unsigned KindValue;
+ if (ReadUnsigned(Str, StrEnd, KindValue))
break;
- if (OverloadIdx < CompletionIdx) {
- // Parse an overload result.
- Buffer = Buffer.substr(OverloadIdx);
-
- // Skip past the OVERLOAD:
- Buffer = Buffer.substr(Buffer.find(':') + 1);
-
- // Find the entire completion string.
- StringRef::size_type EOL = Buffer.find_first_of("\n\r");
- if (EOL == StringRef::npos)
- continue;
-
- StringRef Line = Buffer.substr(0, EOL);
- Buffer = Buffer.substr(EOL + 1);
- CodeCompletionString *CCStr = CodeCompletionString::Deserialize(Line);
- if (!CCStr || CCStr->empty())
- continue;
+ CodeCompletionString *CCStr
+ = CodeCompletionString::Deserialize(Str, StrEnd);
+ if (!CCStr)
+ continue;
+ if (!CCStr->empty()) {
// Vend the code-completion result to the caller.
CXCompletionResult Result;
- Result.CursorKind = CXCursor_NotImplemented;
+ Result.CursorKind = (CXCursorKind)KindValue;
Result.CompletionString = CCStr;
if (completion_iterator)
completion_iterator(&Result, client_data);
- delete CCStr;
-
- continue;
}
- // Parse a completion result.
- Buffer = Buffer.substr(CompletionIdx);
-
- // Skip past the COMPLETION:
- Buffer = Buffer.substr(Buffer.find(':') + 1);
-
- // Get the rank
- unsigned Rank = 0;
- StringRef::size_type AfterRank = Buffer.find(':');
- Buffer.substr(0, AfterRank).getAsInteger(10, Rank);
- Buffer = Buffer.substr(AfterRank + 1);
-
- // Get the kind of result.
- StringRef::size_type AfterKind = Buffer.find(':');
- StringRef Kind = Buffer.substr(0, AfterKind);
- Buffer = Buffer.substr(AfterKind + 1);
-
- // Skip over any whitespace.
- Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
-
- // Find the entire completion string.
- StringRef::size_type EOL = Buffer.find_first_of("\n\r");
- if (EOL == StringRef::npos)
- continue;
-
- StringRef Line = Buffer.substr(0, EOL);
- Buffer = Buffer.substr(EOL + 1);
- CodeCompletionString *CCStr = CodeCompletionString::Deserialize(Line);
- if (!CCStr || CCStr->empty())
- continue;
-
- // Vend the code-completion result to the caller.
- CXCompletionResult Result;
- Result.CursorKind = parseResultKind(Kind);
- Result.CompletionString = CCStr;
- if (completion_iterator)
- completion_iterator(&Result, client_data);
delete CCStr;
- } while (true);
+ };
delete F;
}