forked from OSchip/llvm-project
[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:
parent
6403c34c2a
commit
24c55228a9
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue