summaryrefslogtreecommitdiffstats
path: root/tools/libclang/CIndexCodeCompletion.cpp
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2011-02-20 13:06:31 +0000
committerdim <dim@FreeBSD.org>2011-02-20 13:06:31 +0000
commit39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df (patch)
treea9243275843fbeaa590afc07ee888e006b8d54ea /tools/libclang/CIndexCodeCompletion.cpp
parent69b4eca4a4255ba43baa5c1d9bbdec3ec17f479e (diff)
downloadFreeBSD-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.cpp525
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;
}
};
}
OpenPOWER on IntegriCloud