diff options
author | dim <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
commit | 39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df (patch) | |
tree | a9243275843fbeaa590afc07ee888e006b8d54ea /tools/libclang/CIndexCodeCompletion.cpp | |
parent | 69b4eca4a4255ba43baa5c1d9bbdec3ec17f479e (diff) | |
download | FreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.zip FreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.tar.gz |
Vendor import of clang trunk r126079:
http://llvm.org/svn/llvm-project/cfe/trunk@126079
Diffstat (limited to 'tools/libclang/CIndexCodeCompletion.cpp')
-rw-r--r-- | tools/libclang/CIndexCodeCompletion.cpp | 525 |
1 files changed, 160 insertions, 365 deletions
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index d591c5d..292719b 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -13,6 +13,8 @@ //===----------------------------------------------------------------------===// #include "CIndexer.h" +#include "CXTranslationUnit.h" +#include "CXString.h" #include "CIndexDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" @@ -22,11 +24,12 @@ #include "clang/Sema/CodeCompleteConsumer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Atomic.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Program.h" #include <cstdlib> #include <cstdio> @@ -42,31 +45,12 @@ using namespace clang; using namespace clang::cxstring; -namespace { - /// \brief Stored representation of a completion string. - /// - /// This is the representation behind a CXCompletionString. - class CXStoredCodeCompletionString : public CodeCompletionString { - unsigned Priority; - CXAvailabilityKind Availability; - - public: - CXStoredCodeCompletionString(unsigned Priority, - CXAvailabilityKind Availability) - : Priority(Priority), Availability(Availability) { } - - unsigned getPriority() const { return Priority; } - CXAvailabilityKind getAvailability() const { return Availability; } - }; -} - extern "C" { enum CXCompletionChunkKind clang_getCompletionChunkKind(CXCompletionString completion_string, unsigned chunk_number) { - CXStoredCodeCompletionString *CCStr - = (CXStoredCodeCompletionString *)completion_string; + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return CXCompletionChunk_Text; @@ -121,10 +105,9 @@ clang_getCompletionChunkKind(CXCompletionString completion_string, CXString clang_getCompletionChunkText(CXCompletionString completion_string, unsigned chunk_number) { - CXStoredCodeCompletionString *CCStr - = (CXStoredCodeCompletionString *)completion_string; + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) - return createCXString(0); + return createCXString((const char*)0); switch ((*CCStr)[chunk_number].Kind) { case CodeCompletionString::CK_TypedText: @@ -146,11 +129,8 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string, case CodeCompletionString::CK_SemiColon: case CodeCompletionString::CK_Equal: case CodeCompletionString::CK_HorizontalSpace: - return createCXString((*CCStr)[chunk_number].Text, false); - case CodeCompletionString::CK_VerticalSpace: - // FIXME: Temporary hack until we figure out how to handle vertical space. - return createCXString(" "); + return createCXString((*CCStr)[chunk_number].Text, false); case CodeCompletionString::CK_Optional: // Note: treated as an empty text block. @@ -158,15 +138,14 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string, } // Should be unreachable, but let's be careful. - return createCXString(0); + return createCXString((const char*)0); } CXCompletionString clang_getCompletionChunkCompletionString(CXCompletionString completion_string, unsigned chunk_number) { - CXStoredCodeCompletionString *CCStr - = (CXStoredCodeCompletionString *)completion_string; + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return 0; @@ -203,32 +182,20 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string, } unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { - CXStoredCodeCompletionString *CCStr - = (CXStoredCodeCompletionString *)completion_string; + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; return CCStr? CCStr->size() : 0; } unsigned clang_getCompletionPriority(CXCompletionString completion_string) { - CXStoredCodeCompletionString *CCStr - = (CXStoredCodeCompletionString *)completion_string; + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); } enum CXAvailabilityKind clang_getCompletionAvailability(CXCompletionString completion_string) { - CXStoredCodeCompletionString *CCStr - = (CXStoredCodeCompletionString *)completion_string; - return CCStr? CCStr->getAvailability() : CXAvailability_Available; -} - -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; + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr? static_cast<CXAvailabilityKind>(CCStr->getAvailability()) + : CXAvailability_Available; } /// \brief The CXCodeCompleteResults structure we allocate internally; @@ -246,345 +213,119 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// \brief Language options used to adjust source locations. LangOptions LangOpts; - /// \brief Source manager, used for diagnostics. - SourceManager SourceMgr; - + FileSystemOptions FileSystemOpts; + /// \brief File manager, used for diagnostics. FileManager FileMgr; + + /// \brief Source manager, used for diagnostics. + SourceManager SourceMgr; /// \brief Temporary files that should be removed once we have finished /// with the code-completion results. std::vector<llvm::sys::Path> TemporaryFiles; - /// \brief Temporary buffers that will be deleted once we have finished with the code-completion results. + /// \brief Temporary buffers that will be deleted once we have finished with + /// the code-completion results. llvm::SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers; + + /// \brief Allocator used to store globally cached code-completion results. + llvm::IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator> + CachedCompletionAllocator; + + /// \brief Allocator used to store code completion results. + clang::CodeCompletionAllocator CodeCompletionAllocator; }; +/// \brief Tracks the number of code-completion result objects that are +/// currently active. +/// +/// Used for debugging purposes only. +static llvm::sys::cas_flag CodeCompletionResultObjects; + AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() - : CXCodeCompleteResults(), Diag(new Diagnostic), SourceMgr(*Diag) { } + : CXCodeCompleteResults(), + Diag(new Diagnostic( + llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))), + FileMgr(FileSystemOpts), + SourceMgr(*Diag, FileMgr) { + if (getenv("LIBCLANG_OBJTRACKING")) { + llvm::sys::AtomicIncrement(&CodeCompletionResultObjects); + fprintf(stderr, "+++ %d completion results\n", CodeCompletionResultObjects); + } +} AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { - for (unsigned I = 0, N = NumResults; I != N; ++I) - delete (CXStoredCodeCompletionString *)Results[I].CompletionString; delete [] Results; for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) TemporaryFiles[I].eraseFromDisk(); for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I) delete TemporaryBuffers[I]; -} - -CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, - const char *source_filename, - int num_command_line_args, - const char * const *command_line_args, - unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files, - const char *complete_filename, - unsigned complete_line, - unsigned complete_column) { -#ifdef UDP_CODE_COMPLETION_LOGGER -#ifdef UDP_CODE_COMPLETION_LOGGER_PORT - const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); -#endif -#endif - - bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; - - llvm::OwningPtr<llvm::NamedRegionTimer> CCTimer; - if (getenv("LIBCLANG_TIMING")) { - llvm::SmallString<128> TimerName; - llvm::raw_svector_ostream TimerNameOut(TimerName); - TimerNameOut << "Code completion (out-of-process) @ " << complete_filename - << ":" << complete_line << ":" << complete_column; - CCTimer.reset(new llvm::NamedRegionTimer(TimerNameOut.str())); - } - - // The indexer, which is mainly used to determine where diagnostics go. - CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); - - // Configure the diagnostics. - DiagnosticOptions DiagOpts; - llvm::IntrusiveRefCntPtr<Diagnostic> Diags; - Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); - - // The set of temporary files that we've built. - std::vector<llvm::sys::Path> TemporaryFiles; - - // Build up the arguments for invoking 'clang'. - std::vector<const char *> argv; - - // First add the complete path to the 'clang' executable. - llvm::sys::Path ClangPath = CXXIdx->getClangPath(); - argv.push_back(ClangPath.c_str()); - - // Always use Clang C++ support. - argv.push_back("-ccc-clang-cxx"); - - // Add the '-fsyntax-only' argument so that we only perform a basic - // syntax check of the code. - argv.push_back("-fsyntax-only"); - - // Add the appropriate '-code-completion-at=file:line:column' argument - // to perform code completion, with an "-Xclang" preceding it. - std::string code_complete_at; - code_complete_at += complete_filename; - code_complete_at += ":"; - code_complete_at += llvm::utostr(complete_line); - code_complete_at += ":"; - code_complete_at += llvm::utostr(complete_column); - argv.push_back("-Xclang"); - argv.push_back("-code-completion-at"); - argv.push_back("-Xclang"); - argv.push_back(code_complete_at.c_str()); - argv.push_back("-Xclang"); - argv.push_back("-no-code-completion-debug-printer"); - argv.push_back("-Xclang"); - argv.push_back("-code-completion-macros"); - argv.push_back("-fdiagnostics-binary"); - - // Remap any unsaved files to temporary files. - std::vector<std::string> RemapArgs; - if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) - return 0; - - // The pointers into the elements of RemapArgs are stable because we - // won't be adding anything to RemapArgs after this point. - for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i) - argv.push_back(RemapArgs[i].c_str()); - - // Add the source file name (FIXME: later, we'll want to build temporary - // file from the buffer, or just feed the source text via standard input). - if (source_filename) - argv.push_back(source_filename); - - // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'. - for (int i = 0; i < num_command_line_args; ++i) - if (const char *arg = command_line_args[i]) { - if (strcmp(arg, "-o") == 0) { - ++i; // Also skip the matching argument. - continue; - } - if (strcmp(arg, "-emit-ast") == 0 || - strcmp(arg, "-c") == 0 || - strcmp(arg, "-fsyntax-only") == 0) { - continue; - } - - // Keep the argument. - argv.push_back(arg); - } - - if (EnableLogging) { - std::string Log = ClangPath.str(); - for (unsigned I = 0, N = argv.size(); I != N; ++I) { - Log += ' '; - Log += argv[I]; - } - fprintf(stderr, "libclang (Code Completion): %s\n", Log.c_str()); - } - - // Add the null terminator. - argv.push_back(NULL); - - // Generate a temporary name for the code-completion results file. - char tmpFile[L_tmpnam]; - char *tmpFileName = tmpnam(tmpFile); - llvm::sys::Path ResultsFile(tmpFileName); - TemporaryFiles.push_back(ResultsFile); - - // Generate a temporary name for the diagnostics file. - char tmpFileResults[L_tmpnam]; - char *tmpResultsFileName = tmpnam(tmpFileResults); - llvm::sys::Path DiagnosticsFile(tmpResultsFileName); - TemporaryFiles.push_back(DiagnosticsFile); - - - - // Invoke 'clang'. - llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null - // on Unix or NUL (Windows). - std::string ErrMsg; - const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, - &DiagnosticsFile, 0 }; - llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL, - /* redirects */ &Redirects[0], - /* secondsToWait */ 0, - /* memoryLimits */ 0, &ErrMsg); - - if (!ErrMsg.empty()) { - std::string AllArgs; - for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); - I != E; ++I) { - AllArgs += ' '; - if (*I) - AllArgs += *I; - } - - Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; - } - - // Parse the resulting source file to find code-completion results. - using llvm::MemoryBuffer; - using llvm::StringRef; - AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; - Results->Results = 0; - Results->NumResults = 0; - // FIXME: Set Results->LangOpts! - if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) { - llvm::SmallVector<CXCompletionResult, 4> CompletionResults; - StringRef Buffer = F->getBuffer(); - for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size(); - Str < StrEnd;) { - unsigned KindValue; - if (ReadUnsigned(Str, StrEnd, KindValue)) - break; - - unsigned Priority; - if (ReadUnsigned(Str, StrEnd, Priority)) - break; - - unsigned Availability; - if (ReadUnsigned(Str, StrEnd, Availability)) - break; - - CXStoredCodeCompletionString *CCStr - = new CXStoredCodeCompletionString(Priority, - (CXAvailabilityKind)Availability); - if (!CCStr->Deserialize(Str, StrEnd)) { - delete CCStr; - continue; - } - - if (!CCStr->empty()) { - // Vend the code-completion result to the caller. - CXCompletionResult Result; - Result.CursorKind = (CXCursorKind)KindValue; - Result.CompletionString = CCStr; - CompletionResults.push_back(Result); - } - }; - - // Allocate the results. - Results->Results = new CXCompletionResult [CompletionResults.size()]; - Results->NumResults = CompletionResults.size(); - memcpy(Results->Results, CompletionResults.data(), - CompletionResults.size() * sizeof(CXCompletionResult)); - Results->TemporaryBuffers.push_back(F); - } - - LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files, - Results->FileMgr, Results->SourceMgr, - Results->Diagnostics); - - // Make sure we delete temporary files when the code-completion results are - // destroyed. - Results->TemporaryFiles.swap(TemporaryFiles); - -#ifdef UDP_CODE_COMPLETION_LOGGER -#ifdef UDP_CODE_COMPLETION_LOGGER_PORT - const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); - llvm::SmallString<256> LogResult; - llvm::raw_svector_ostream os(LogResult); - - // Figure out the language and whether or not it uses PCH. - const char *lang = 0; - bool usesPCH = false; - for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); - I != E; ++I) { - if (*I == 0) - continue; - if (strcmp(*I, "-x") == 0) { - if (I + 1 != E) { - lang = *(++I); - continue; - } - } - else if (strcmp(*I, "-include") == 0) { - if (I+1 != E) { - const char *arg = *(++I); - llvm::SmallString<512> pchName; - { - llvm::raw_svector_ostream os(pchName); - os << arg << ".pth"; - } - pchName.push_back('\0'); - struct stat stat_results; - if (stat(pchName.data(), &stat_results) == 0) - usesPCH = true; - continue; - } - } - } - - os << "{ "; - os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); - os << ", \"numRes\": " << Results->NumResults; - os << ", \"diags\": " << Results->Diagnostics.size(); - os << ", \"pch\": " << (usesPCH ? "true" : "false"); - os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; - const char *name = getlogin(); - os << ", \"user\": \"" << (name ? name : "unknown") << '"'; - os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; - os << " }"; - - llvm::StringRef res = os.str(); - if (res.size() > 0) { - do { - // Setup the UDP socket. - struct sockaddr_in servaddr; - bzero(&servaddr, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); - if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, - &servaddr.sin_addr) <= 0) - break; - - int sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) - break; - - sendto(sockfd, res.data(), res.size(), 0, - (struct sockaddr *)&servaddr, sizeof(servaddr)); - close(sockfd); - } - while (false); - } -#endif -#endif - clang_sortCodeCompletionResults(Results->Results, Results->NumResults); - return Results; + if (getenv("LIBCLANG_OBJTRACKING")) { + llvm::sys::AtomicDecrement(&CodeCompletionResultObjects); + fprintf(stderr, "--- %d completion results\n", CodeCompletionResultObjects); + } } - + } // end extern "C" namespace { class CaptureCompletionResults : public CodeCompleteConsumer { AllocatedCXCodeCompleteResults &AllocatedResults; - + llvm::SmallVector<CXCompletionResult, 16> StoredResults; public: - explicit CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results) + CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results) : CodeCompleteConsumer(true, false, true, false), AllocatedResults(Results) { } - + ~CaptureCompletionResults() { Finish(); } + virtual void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, CodeCompletionResult *Results, unsigned NumResults) { - AllocatedResults.Results = new CXCompletionResult [NumResults]; - AllocatedResults.NumResults = NumResults; + StoredResults.reserve(StoredResults.size() + NumResults); for (unsigned I = 0; I != NumResults; ++I) { - CXStoredCodeCompletionString *StoredCompletion - = new CXStoredCodeCompletionString(Results[I].Priority, - Results[I].Availability); - (void)Results[I].CreateCodeCompletionString(S, StoredCompletion); - AllocatedResults.Results[I].CursorKind = Results[I].CursorKind; - AllocatedResults.Results[I].CompletionString = StoredCompletion; + CodeCompletionString *StoredCompletion + = Results[I].CreateCodeCompletionString(S, + AllocatedResults.CodeCompletionAllocator); + + CXCompletionResult R; + R.CursorKind = Results[I].CursorKind; + R.CompletionString = StoredCompletion; + StoredResults.push_back(R); + } + } + + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + StoredResults.reserve(StoredResults.size() + NumCandidates); + for (unsigned I = 0; I != NumCandidates; ++I) { + CodeCompletionString *StoredCompletion + = Candidates[I].CreateSignatureString(CurrentArg, S, + AllocatedResults.CodeCompletionAllocator); + + CXCompletionResult R; + R.CursorKind = CXCursor_NotImplemented; + R.CompletionString = StoredCompletion; + StoredResults.push_back(R); } } - // FIXME: Add ProcessOverloadCandidates? + virtual CodeCompletionAllocator &getAllocator() { + return AllocatedResults.CodeCompletionAllocator; + } + + private: + void Finish() { + AllocatedResults.Results = new CXCompletionResult [StoredResults.size()]; + AllocatedResults.NumResults = StoredResults.size(); + std::memcpy(AllocatedResults.Results, StoredResults.data(), + StoredResults.size() * sizeof(CXCompletionResult)); + StoredResults.clear(); + } }; } @@ -618,10 +359,12 @@ void clang_codeCompleteAt_Impl(void *UserData) { bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; - ASTUnit *AST = static_cast<ASTUnit *>(TU); + ASTUnit *AST = static_cast<ASTUnit *>(TU->TUData); if (!AST) return; + ASTUnit::ConcurrencyCheck Check(*AST); + // Perform the remapping of source files. llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; for (unsigned I = 0; I != num_unsaved_files; ++I) { @@ -640,7 +383,7 @@ void clang_codeCompleteAt_Impl(void *UserData) { AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; Results->Results = 0; Results->NumResults = 0; - + // Create a code-completion consumer to capture the results. CaptureCompletionResults Capture(*Results); @@ -653,6 +396,12 @@ void clang_codeCompleteAt_Impl(void *UserData) { *Results->Diag, Results->LangOpts, Results->SourceMgr, Results->FileMgr, Results->Diagnostics, Results->TemporaryBuffers); + + // Keep a reference to the allocator used for cached global completions, so + // that we can be sure that the memory used by our code completion strings + // doesn't get freed due to subsequent reparses (while the code completion + // results are still active). + Results->CachedCompletionAllocator = AST->getCachedCompletionAllocator(); @@ -742,9 +491,9 @@ CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, options, 0 }; llvm::CrashRecoveryContext CRC; - if (!CRC.RunSafely(clang_codeCompleteAt_Impl, &CCAI)) { + if (!RunSafely(CRC, clang_codeCompleteAt_Impl, &CCAI)) { fprintf(stderr, "libclang: crash detected in code completion\n"); - static_cast<ASTUnit *>(TU)->setUnsafeToFree(true); + static_cast<ASTUnit *>(TU->TUData)->setUnsafeToFree(true); return 0; } @@ -788,28 +537,74 @@ clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, } // end extern "C" +/// \brief Simple utility function that appends a \p New string to the given +/// \p Old string, using the \p Buffer for storage. +/// +/// \param Old The string to which we are appending. This parameter will be +/// updated to reflect the complete string. +/// +/// +/// \param New The string to append to \p Old. +/// +/// \param Buffer A buffer that stores the actual, concatenated string. It will +/// be used if the old string is already-non-empty. +static void AppendToString(llvm::StringRef &Old, llvm::StringRef New, + llvm::SmallString<256> &Buffer) { + if (Old.empty()) { + Old = New; + return; + } + + if (Buffer.empty()) + Buffer.append(Old.begin(), Old.end()); + Buffer.append(New.begin(), New.end()); + Old = Buffer.str(); +} + +/// \brief Get the typed-text blocks from the given code-completion string +/// and return them as a single string. +/// +/// \param String The code-completion string whose typed-text blocks will be +/// concatenated. +/// +/// \param Buffer A buffer used for storage of the completed name. +static llvm::StringRef GetTypedName(CodeCompletionString *String, + llvm::SmallString<256> &Buffer) { + llvm::StringRef Result; + for (CodeCompletionString::iterator C = String->begin(), CEnd = String->end(); + C != CEnd; ++C) { + if (C->Kind == CodeCompletionString::CK_TypedText) + AppendToString(Result, C->Text, Buffer); + } + + return Result; +} + namespace { struct OrderCompletionResults { bool operator()(const CXCompletionResult &XR, const CXCompletionResult &YR) const { - CXStoredCodeCompletionString *X - = (CXStoredCodeCompletionString *)XR.CompletionString; - CXStoredCodeCompletionString *Y - = (CXStoredCodeCompletionString *)YR.CompletionString; + CodeCompletionString *X + = (CodeCompletionString *)XR.CompletionString; + CodeCompletionString *Y + = (CodeCompletionString *)YR.CompletionString; - const char *XText = X->getTypedText(); - const char *YText = Y->getTypedText(); - if (!XText || !YText) - return XText != 0; + llvm::SmallString<256> XBuffer; + llvm::StringRef XText = GetTypedName(X, XBuffer); + llvm::SmallString<256> YBuffer; + llvm::StringRef YText = GetTypedName(Y, YBuffer); - int result = llvm::StringRef(XText).compare_lower(YText); + if (XText.empty() || YText.empty()) + return !XText.empty(); + + int result = XText.compare_lower(YText); if (result < 0) return true; if (result > 0) return false; - result = llvm::StringRef(XText).compare(YText); - return result; + result = XText.compare(YText); + return result < 0; } }; } |