[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.

llvm-svn: 202471
This commit is contained in:
Argyrios Kyrtzidis 2014-02-28 07:11:01 +00:00
parent 6403c34c2a
commit 24c55228a9
2 changed files with 114 additions and 54 deletions

View File

@ -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<unsigned, unsigned> RemoveRange;
std::pair<unsigned, unsigned> InsertFromRange;
std::string CodeToInsert;
bool BeforePreviousInsertions;
};
struct StandaloneDiagnostic {
unsigned ID;
DiagnosticsEngine::Level Level;
std::string Message;
std::string Filename;
unsigned LocOffset;
std::vector<std::pair<unsigned, unsigned> > Ranges;
std::vector<StandaloneFixIt> FixIts;
};
private:
IntrusiveRefCntPtr<LangOptions> LangOpts;
IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
@ -136,7 +154,7 @@ private:
std::string OriginalSourceFile;
/// \brief The set of diagnostics produced when creating the preamble.
SmallVector<StoredDiagnostic, 4> PreambleDiagnostics;
SmallVector<StandaloneDiagnostic, 4> 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<StoredDiagnostic> &Diags,
const SmallVectorImpl<StandaloneDiagnostic> &Diags,
SmallVectorImpl<StoredDiagnostic> &Out);
void clearFileLevelDecls();

View File

@ -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<unsigned, unsigned>
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<unsigned, int, 2> 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<StoredDiagnostic> &Diags,
const SmallVectorImpl<StandaloneDiagnostic> &Diags,
SmallVectorImpl<StoredDiagnostic> &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<StoredDiagnostic, 4> 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<CharSourceRange, 4> 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<std::pair<unsigned, unsigned> >::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<FixItHint, 2> 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<StandaloneFixIt>::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);
}