From 3e1970f112d12e61b46f1dd6ac997e1d0ea55c1e Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Fri, 28 Feb 2014 07:11:01 +0000 Subject: [PATCH] [ASTUnit] Don't let the preamble diagnostics out-live the CompilerInstance that created them, this is inherently unsafe. Instead get the diagnostic info into a SourceManager-independent form. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202471 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Frontend/ASTUnit.h | 24 +++++- lib/Frontend/ASTUnit.cpp | 144 ++++++++++++++++++++----------- 2 files changed, 114 insertions(+), 54 deletions(-) diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index adc920a8c7..6ff6250e42 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -64,6 +64,24 @@ class ASTDeserializationListener; /// \brief Utility class for loading a ASTContext from an AST file. /// class ASTUnit : public ModuleLoader { +public: + struct StandaloneFixIt { + std::pair RemoveRange; + std::pair InsertFromRange; + std::string CodeToInsert; + bool BeforePreviousInsertions; + }; + + struct StandaloneDiagnostic { + unsigned ID; + DiagnosticsEngine::Level Level; + std::string Message; + std::string Filename; + unsigned LocOffset; + std::vector > Ranges; + std::vector FixIts; + }; + private: IntrusiveRefCntPtr LangOpts; IntrusiveRefCntPtr Diagnostics; @@ -136,7 +154,7 @@ private: std::string OriginalSourceFile; /// \brief The set of diagnostics produced when creating the preamble. - SmallVector PreambleDiagnostics; + SmallVector PreambleDiagnostics; /// \brief The set of diagnostics produced when creating this /// translation unit. @@ -295,9 +313,9 @@ private: const char **ArgBegin, const char **ArgEnd, ASTUnit &AST, bool CaptureDiagnostics); - void TranslateStoredDiagnostics(ASTReader *MMan, StringRef ModName, + void TranslateStoredDiagnostics(FileManager &FileMgr, SourceManager &SrcMan, - const SmallVectorImpl &Diags, + const SmallVectorImpl &Diags, SmallVectorImpl &Out); void clearFileLevelDecls(); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 93429cba88..a78ea769d2 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1159,9 +1159,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { if (OverrideMainBuffer) { std::string ModName = getPreambleFile(this); - TranslateStoredDiagnostics(Clang->getModuleManager().getPtr(), ModName, - getSourceManager(), PreambleDiagnostics, - StoredDiagnostics); + TranslateStoredDiagnostics(getFileManager(), getSourceManager(), + PreambleDiagnostics, StoredDiagnostics); } if (!Act->Execute()) @@ -1329,6 +1328,53 @@ bool operator==(const ASTUnit::PreambleFileHash &LHS, } } // namespace clang +static std::pair +makeStandaloneRange(CharSourceRange Range, const SourceManager &SM, + const LangOptions &LangOpts) { + CharSourceRange FileRange = Lexer::makeFileCharRange(Range, SM, LangOpts); + unsigned Offset = SM.getFileOffset(FileRange.getBegin()); + unsigned EndOffset = SM.getFileOffset(FileRange.getEnd()); + return std::make_pair(Offset, EndOffset); +} + +static void makeStandaloneFixIt(const SourceManager &SM, + const LangOptions &LangOpts, + const FixItHint &InFix, + ASTUnit::StandaloneFixIt &OutFix) { + OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts); + OutFix.InsertFromRange = makeStandaloneRange(InFix.InsertFromRange, SM, + LangOpts); + OutFix.CodeToInsert = InFix.CodeToInsert; + OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions; +} + +static void makeStandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag, + ASTUnit::StandaloneDiagnostic &OutDiag) { + OutDiag.ID = InDiag.getID(); + OutDiag.Level = InDiag.getLevel(); + OutDiag.Message = InDiag.getMessage(); + OutDiag.LocOffset = 0; + if (InDiag.getLocation().isInvalid()) + return; + const SourceManager &SM = InDiag.getLocation().getManager(); + SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation()); + OutDiag.Filename = SM.getFilename(FileLoc); + if (OutDiag.Filename.empty()) + return; + OutDiag.LocOffset = SM.getFileOffset(FileLoc); + for (StoredDiagnostic::range_iterator + I = InDiag.range_begin(), E = InDiag.range_end(); I != E; ++I) { + OutDiag.Ranges.push_back(makeStandaloneRange(*I, SM, LangOpts)); + } + for (StoredDiagnostic::fixit_iterator + I = InDiag.fixit_begin(), E = InDiag.fixit_end(); I != E; ++I) { + ASTUnit::StandaloneFixIt Fix; + makeStandaloneFixIt(SM, LangOpts, *I, Fix); + OutDiag.FixIts.push_back(Fix); + } +} + /// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing /// the source file. /// @@ -1589,6 +1635,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( checkAndRemoveNonDriverDiags(StoredDiagnostics); TopLevelDecls.clear(); TopLevelDeclsInPreamble.clear(); + PreambleDiagnostics.clear(); // Create a file manager object to provide access to and cache the filesystem. Clang->setFileManager(new FileManager(Clang->getFileSystemOpts())); @@ -1609,8 +1656,21 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( } Act->Execute(); + + // Transfer any diagnostics generated when parsing the preamble into the set + // of preamble diagnostics. + for (stored_diag_iterator + I = stored_diag_afterDriver_begin(), + E = stored_diag_end(); I != E; ++I) { + StandaloneDiagnostic Diag; + makeStandaloneDiagnostic(Clang->getLangOpts(), *I, Diag); + PreambleDiagnostics.push_back(Diag); + } + Act->EndSourceFile(); + checkAndRemoveNonDriverDiags(StoredDiagnostics); + if (!Act->hasEmittedPreamblePCH()) { // The preamble PCH failed (e.g. there was a module loading fatal error), // so no precompiled header was generated. Forget that we even tried. @@ -1624,13 +1684,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( return 0; } - // Transfer any diagnostics generated when parsing the preamble into the set - // of preamble diagnostics. - PreambleDiagnostics.clear(); - PreambleDiagnostics.insert(PreambleDiagnostics.end(), - stored_diag_afterDriver_begin(), stored_diag_end()); - checkAndRemoveNonDriverDiags(StoredDiagnostics); - // Keep track of the preamble we precompiled. setPreambleFile(this, FrontendOpts.OutputFile); NumWarningsInPreamble = getDiagnostics().getNumWarnings(); @@ -2545,68 +2598,57 @@ bool ASTUnit::serialize(raw_ostream &OS) { typedef ContinuousRangeMap SLocRemap; -static void TranslateSLoc(SourceLocation &L, SLocRemap &Remap) { - unsigned Raw = L.getRawEncoding(); - const unsigned MacroBit = 1U << 31; - L = SourceLocation::getFromRawEncoding((Raw & MacroBit) | - ((Raw & ~MacroBit) + Remap.find(Raw & ~MacroBit)->second)); -} - void ASTUnit::TranslateStoredDiagnostics( - ASTReader *MMan, - StringRef ModName, + FileManager &FileMgr, SourceManager &SrcMgr, - const SmallVectorImpl &Diags, + const SmallVectorImpl &Diags, SmallVectorImpl &Out) { - // The stored diagnostic has the old source manager in it; update - // the locations to refer into the new source manager. We also need to remap - // all the locations to the new view. This includes the diag location, any - // associated source ranges, and the source ranges of associated fix-its. + // Map the standalone diagnostic into the new source manager. We also need to + // remap all the locations to the new view. This includes the diag location, + // any associated source ranges, and the source ranges of associated fix-its. // FIXME: There should be a cleaner way to do this. SmallVector Result; Result.reserve(Diags.size()); - assert(MMan && "Don't have a module manager"); - serialization::ModuleFile *Mod = MMan->ModuleMgr.lookup(ModName); - assert(Mod && "Don't have preamble module"); - SLocRemap &Remap = Mod->SLocRemap; for (unsigned I = 0, N = Diags.size(); I != N; ++I) { // Rebuild the StoredDiagnostic. - const StoredDiagnostic &SD = Diags[I]; - SourceLocation L = SD.getLocation(); - TranslateSLoc(L, Remap); + const StandaloneDiagnostic &SD = Diags[I]; + if (SD.Filename.empty()) + continue; + const FileEntry *FE = FileMgr.getFile(SD.Filename); + if (!FE) + continue; + FileID FID = SrcMgr.translateFile(FE); + SourceLocation FileLoc = SrcMgr.getLocForStartOfFile(FID); + if (FileLoc.isInvalid()) + continue; + SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset); FullSourceLoc Loc(L, SrcMgr); SmallVector Ranges; - Ranges.reserve(SD.range_size()); - for (StoredDiagnostic::range_iterator I = SD.range_begin(), - E = SD.range_end(); - I != E; ++I) { - SourceLocation BL = I->getBegin(); - TranslateSLoc(BL, Remap); - SourceLocation EL = I->getEnd(); - TranslateSLoc(EL, Remap); - Ranges.push_back(CharSourceRange(SourceRange(BL, EL), I->isTokenRange())); + Ranges.reserve(SD.Ranges.size()); + for (std::vector >::const_iterator + I = SD.Ranges.begin(), E = SD.Ranges.end(); I != E; ++I) { + SourceLocation BL = FileLoc.getLocWithOffset((*I).first); + SourceLocation EL = FileLoc.getLocWithOffset((*I).second); + Ranges.push_back(CharSourceRange::getCharRange(BL, EL)); } SmallVector FixIts; - FixIts.reserve(SD.fixit_size()); - for (StoredDiagnostic::fixit_iterator I = SD.fixit_begin(), - E = SD.fixit_end(); + FixIts.reserve(SD.FixIts.size()); + for (std::vector::const_iterator + I = SD.FixIts.begin(), E = SD.FixIts.end(); I != E; ++I) { FixIts.push_back(FixItHint()); FixItHint &FH = FixIts.back(); FH.CodeToInsert = I->CodeToInsert; - SourceLocation BL = I->RemoveRange.getBegin(); - TranslateSLoc(BL, Remap); - SourceLocation EL = I->RemoveRange.getEnd(); - TranslateSLoc(EL, Remap); - FH.RemoveRange = CharSourceRange(SourceRange(BL, EL), - I->RemoveRange.isTokenRange()); + SourceLocation BL = FileLoc.getLocWithOffset(I->RemoveRange.first); + SourceLocation EL = FileLoc.getLocWithOffset(I->RemoveRange.second); + FH.RemoveRange = CharSourceRange::getCharRange(BL, EL); } - Result.push_back(StoredDiagnostic(SD.getLevel(), SD.getID(), - SD.getMessage(), Loc, Ranges, FixIts)); + Result.push_back(StoredDiagnostic(SD.Level, SD.ID, + SD.Message, Loc, Ranges, FixIts)); } Result.swap(Out); } -- 2.40.0