From: Douglas Gregor Date: Fri, 20 Aug 2010 00:59:43 +0000 (+0000) Subject: When performing code-completion in the presence of a preamble, make X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2283d79155a3e82442fce124ce5fd704ca138801;p=clang When performing code-completion in the presence of a preamble, make sure to (1) actually use the remapped files we were given rather than old data, and (2) keep the remapped files alive until the code-completion results are destroyed. Big thanks to Daniel for the test case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111597 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 8f3b4d40f1..e323170b08 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -311,6 +311,7 @@ private: unsigned MaxLines, bool &CreatedBuffer); llvm::MemoryBuffer *getMainBufferWithPrecompiledPreamble( + CompilerInvocation PreambleInvocation, bool AllowRebuild = true, unsigned MaxLines = 0); void RealizeTopLevelDeclsFromPreamble(); @@ -546,16 +547,16 @@ public: /// \param IncludeCodePatterns Whether to include code patterns (such as a /// for loop) in the code-completion results. /// - /// FIXME: The Diag, LangOpts, SourceMgr, FileMgr, and - /// StoredDiagnostics parameters are all disgusting hacks. They will - /// go away. + /// FIXME: The Diag, LangOpts, SourceMgr, FileMgr, StoredDiagnostics, and + /// OwnedBuffers parameters are all disgusting hacks. They will go away. void CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, bool IncludeMacros, bool IncludeCodePatterns, CodeCompleteConsumer &Consumer, Diagnostic &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, FileManager &FileMgr, - llvm::SmallVectorImpl &StoredDiagnostics); + llvm::SmallVectorImpl &StoredDiagnostics, + llvm::SmallVectorImpl &OwnedBuffers); /// \brief Save this translation unit to a file with the given name. /// diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 9c5fea4717..1377e739ed 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -940,9 +940,9 @@ static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old, /// buffer that should be used in place of the main file when doing so. /// Otherwise, returns a NULL pointer. llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( + CompilerInvocation PreambleInvocation, bool AllowRebuild, unsigned MaxLines) { - CompilerInvocation PreambleInvocation(*Invocation); FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts(); PreprocessorOptions &PreprocessorOpts = PreambleInvocation.getPreprocessorOpts(); @@ -1312,7 +1312,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble. if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus) { AST->PreambleRebuildCounter = 1; - OverrideMainBuffer = AST->getMainBufferWithPrecompiledPreamble(); + OverrideMainBuffer + = AST->getMainBufferWithPrecompiledPreamble(*AST->Invocation); } llvm::Timer *ParsingTimer = 0; @@ -1437,7 +1438,7 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { // build a precompiled preamble, do so now. llvm::MemoryBuffer *OverrideMainBuffer = 0; if (!PreambleFile.empty() || PreambleRebuildCounter > 0) - OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(); + OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation); // Clear out the diagnostics state. if (!OverrideMainBuffer) @@ -1663,7 +1664,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, CodeCompleteConsumer &Consumer, Diagnostic &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, FileManager &FileMgr, - llvm::SmallVectorImpl &StoredDiagnostics) { + llvm::SmallVectorImpl &StoredDiagnostics, + llvm::SmallVectorImpl &OwnedBuffers) { if (!Invocation.get()) return; @@ -1739,9 +1741,11 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, // Remap files. PreprocessorOpts.clearRemappedFiles(); PreprocessorOpts.RetainRemappedFileBuffers = true; - for (unsigned I = 0; I != NumRemappedFiles; ++I) + for (unsigned I = 0; I != NumRemappedFiles; ++I) { PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, RemappedFiles[I].second); + OwnedBuffers.push_back(RemappedFiles[I].second); + } // Use the code completion consumer we were given, but adding any cached // code-completion results. @@ -1763,8 +1767,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, if (const FileStatus *CompleteFileStatus = CompleteFilePath.getFileStatus()) if (const FileStatus *MainStatus = MainPath.getFileStatus()) if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID()) - OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(false, - Line); + OverrideMainBuffer + = getMainBufferWithPrecompiledPreamble(CCInvocation, false, Line); } // If the main file has been overridden due to the use of a preamble, @@ -1785,6 +1789,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr); StoredDiagnostics[I].setLocation(Loc); } + + OwnedBuffers.push_back(OverrideMainBuffer); } else { PreprocessorOpts.PrecompiledPreambleBytes.first = 0; PreprocessorOpts.PrecompiledPreambleBytes.second = false; @@ -1802,7 +1808,6 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, CompletionTimer->stopTimer(); // Steal back our resources. - delete OverrideMainBuffer; Clang.takeFileManager(); Clang.takeSourceManager(); Clang.takeInvocation(); diff --git a/test/Index/crash-recovery-code-complete.c b/test/Index/crash-recovery-code-complete.c index be834fb813..71b98b639b 100644 --- a/test/Index/crash-recovery-code-complete.c +++ b/test/Index/crash-recovery-code-complete.c @@ -1,11 +1,10 @@ -// RUN: echo env CINDEXTEST_EDITING=1 \ +// RUN: env CINDEXTEST_EDITING=1 \ // RUN: not c-index-test -code-completion-at=%s:20:1 \ -// RUN: -remap-file="%s;%S/Inputs/crash-recovery-code-complete-remap.c" \ +// RUN: "-remap-file=%s;%S/Inputs/crash-recovery-code-complete-remap.c" \ // RUN: %s 2> %t.err // RUN: FileCheck < %t.err -check-prefix=CHECK-CODE-COMPLETE-CRASH %s -// CHECK-CODE-COMPLETE-CRASH: Unable to reparse translation unit +// CHECK-CODE-COMPLETE-CRASH: Unable to perform code completion! // // XFAIL: win32 -// XFAIL: * #warning parsing original file diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 53767c4467..c2febf9b72 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -624,11 +624,6 @@ void clang_codeCompleteAt_Impl(void *UserData) { // Create a code-completion consumer to capture the results. CaptureCompletionResults Capture(*Results); - // Make sure that we free the temporary buffers when the - // code-completion constructor is freed. - for (unsigned I = 0, N = RemappedFiles.size(); I != N; ++I) - Results->TemporaryBuffers.push_back(RemappedFiles[I].second); - // Perform completion. AST->CodeComplete(complete_filename, complete_line, complete_column, RemappedFiles.data(), RemappedFiles.size(), @@ -636,7 +631,8 @@ void clang_codeCompleteAt_Impl(void *UserData) { (options & CXCodeComplete_IncludeCodePatterns), Capture, *Results->Diag, Results->LangOpts, Results->SourceMgr, - Results->FileMgr, Results->Diagnostics); + Results->FileMgr, Results->Diagnostics, + Results->TemporaryBuffers);