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.
|
/// \brief Utility class for loading a ASTContext from an AST file.
|
||||||
///
|
///
|
||||||
class ASTUnit : public ModuleLoader {
|
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:
|
private:
|
||||||
IntrusiveRefCntPtr<LangOptions> LangOpts;
|
IntrusiveRefCntPtr<LangOptions> LangOpts;
|
||||||
IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
|
||||||
|
@ -136,7 +154,7 @@ private:
|
||||||
std::string OriginalSourceFile;
|
std::string OriginalSourceFile;
|
||||||
|
|
||||||
/// \brief The set of diagnostics produced when creating the preamble.
|
/// \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
|
/// \brief The set of diagnostics produced when creating this
|
||||||
/// translation unit.
|
/// translation unit.
|
||||||
|
@ -295,9 +313,9 @@ private:
|
||||||
const char **ArgBegin, const char **ArgEnd,
|
const char **ArgBegin, const char **ArgEnd,
|
||||||
ASTUnit &AST, bool CaptureDiagnostics);
|
ASTUnit &AST, bool CaptureDiagnostics);
|
||||||
|
|
||||||
void TranslateStoredDiagnostics(ASTReader *MMan, StringRef ModName,
|
void TranslateStoredDiagnostics(FileManager &FileMgr,
|
||||||
SourceManager &SrcMan,
|
SourceManager &SrcMan,
|
||||||
const SmallVectorImpl<StoredDiagnostic> &Diags,
|
const SmallVectorImpl<StandaloneDiagnostic> &Diags,
|
||||||
SmallVectorImpl<StoredDiagnostic> &Out);
|
SmallVectorImpl<StoredDiagnostic> &Out);
|
||||||
|
|
||||||
void clearFileLevelDecls();
|
void clearFileLevelDecls();
|
||||||
|
|
|
@ -1159,9 +1159,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
|
||||||
|
|
||||||
if (OverrideMainBuffer) {
|
if (OverrideMainBuffer) {
|
||||||
std::string ModName = getPreambleFile(this);
|
std::string ModName = getPreambleFile(this);
|
||||||
TranslateStoredDiagnostics(Clang->getModuleManager().getPtr(), ModName,
|
TranslateStoredDiagnostics(getFileManager(), getSourceManager(),
|
||||||
getSourceManager(), PreambleDiagnostics,
|
PreambleDiagnostics, StoredDiagnostics);
|
||||||
StoredDiagnostics);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Act->Execute())
|
if (!Act->Execute())
|
||||||
|
@ -1329,6 +1328,53 @@ bool operator==(const ASTUnit::PreambleFileHash &LHS,
|
||||||
}
|
}
|
||||||
} // namespace clang
|
} // 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
|
/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
|
||||||
/// the source file.
|
/// the source file.
|
||||||
///
|
///
|
||||||
|
@ -1589,6 +1635,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||||
checkAndRemoveNonDriverDiags(StoredDiagnostics);
|
checkAndRemoveNonDriverDiags(StoredDiagnostics);
|
||||||
TopLevelDecls.clear();
|
TopLevelDecls.clear();
|
||||||
TopLevelDeclsInPreamble.clear();
|
TopLevelDeclsInPreamble.clear();
|
||||||
|
PreambleDiagnostics.clear();
|
||||||
|
|
||||||
// Create a file manager object to provide access to and cache the filesystem.
|
// Create a file manager object to provide access to and cache the filesystem.
|
||||||
Clang->setFileManager(new FileManager(Clang->getFileSystemOpts()));
|
Clang->setFileManager(new FileManager(Clang->getFileSystemOpts()));
|
||||||
|
@ -1609,8 +1656,21 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||||
}
|
}
|
||||||
|
|
||||||
Act->Execute();
|
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();
|
Act->EndSourceFile();
|
||||||
|
|
||||||
|
checkAndRemoveNonDriverDiags(StoredDiagnostics);
|
||||||
|
|
||||||
if (!Act->hasEmittedPreamblePCH()) {
|
if (!Act->hasEmittedPreamblePCH()) {
|
||||||
// The preamble PCH failed (e.g. there was a module loading fatal error),
|
// The preamble PCH failed (e.g. there was a module loading fatal error),
|
||||||
// so no precompiled header was generated. Forget that we even tried.
|
// so no precompiled header was generated. Forget that we even tried.
|
||||||
|
@ -1624,13 +1684,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||||
return 0;
|
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.
|
// Keep track of the preamble we precompiled.
|
||||||
setPreambleFile(this, FrontendOpts.OutputFile);
|
setPreambleFile(this, FrontendOpts.OutputFile);
|
||||||
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
|
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
|
||||||
|
@ -2545,68 +2598,57 @@ bool ASTUnit::serialize(raw_ostream &OS) {
|
||||||
|
|
||||||
typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap;
|
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(
|
void ASTUnit::TranslateStoredDiagnostics(
|
||||||
ASTReader *MMan,
|
FileManager &FileMgr,
|
||||||
StringRef ModName,
|
|
||||||
SourceManager &SrcMgr,
|
SourceManager &SrcMgr,
|
||||||
const SmallVectorImpl<StoredDiagnostic> &Diags,
|
const SmallVectorImpl<StandaloneDiagnostic> &Diags,
|
||||||
SmallVectorImpl<StoredDiagnostic> &Out) {
|
SmallVectorImpl<StoredDiagnostic> &Out) {
|
||||||
// The stored diagnostic has the old source manager in it; update
|
// Map the standalone diagnostic into the new source manager. We also need to
|
||||||
// the locations to refer into the new source manager. We also need to remap
|
// remap all the locations to the new view. This includes the diag location,
|
||||||
// all the locations to the new view. This includes the diag location, any
|
// any associated source ranges, and the source ranges of associated fix-its.
|
||||||
// associated source ranges, and the source ranges of associated fix-its.
|
|
||||||
// FIXME: There should be a cleaner way to do this.
|
// FIXME: There should be a cleaner way to do this.
|
||||||
|
|
||||||
SmallVector<StoredDiagnostic, 4> Result;
|
SmallVector<StoredDiagnostic, 4> Result;
|
||||||
Result.reserve(Diags.size());
|
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) {
|
for (unsigned I = 0, N = Diags.size(); I != N; ++I) {
|
||||||
// Rebuild the StoredDiagnostic.
|
// Rebuild the StoredDiagnostic.
|
||||||
const StoredDiagnostic &SD = Diags[I];
|
const StandaloneDiagnostic &SD = Diags[I];
|
||||||
SourceLocation L = SD.getLocation();
|
if (SD.Filename.empty())
|
||||||
TranslateSLoc(L, Remap);
|
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);
|
FullSourceLoc Loc(L, SrcMgr);
|
||||||
|
|
||||||
SmallVector<CharSourceRange, 4> Ranges;
|
SmallVector<CharSourceRange, 4> Ranges;
|
||||||
Ranges.reserve(SD.range_size());
|
Ranges.reserve(SD.Ranges.size());
|
||||||
for (StoredDiagnostic::range_iterator I = SD.range_begin(),
|
for (std::vector<std::pair<unsigned, unsigned> >::const_iterator
|
||||||
E = SD.range_end();
|
I = SD.Ranges.begin(), E = SD.Ranges.end(); I != E; ++I) {
|
||||||
I != E; ++I) {
|
SourceLocation BL = FileLoc.getLocWithOffset((*I).first);
|
||||||
SourceLocation BL = I->getBegin();
|
SourceLocation EL = FileLoc.getLocWithOffset((*I).second);
|
||||||
TranslateSLoc(BL, Remap);
|
Ranges.push_back(CharSourceRange::getCharRange(BL, EL));
|
||||||
SourceLocation EL = I->getEnd();
|
|
||||||
TranslateSLoc(EL, Remap);
|
|
||||||
Ranges.push_back(CharSourceRange(SourceRange(BL, EL), I->isTokenRange()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVector<FixItHint, 2> FixIts;
|
SmallVector<FixItHint, 2> FixIts;
|
||||||
FixIts.reserve(SD.fixit_size());
|
FixIts.reserve(SD.FixIts.size());
|
||||||
for (StoredDiagnostic::fixit_iterator I = SD.fixit_begin(),
|
for (std::vector<StandaloneFixIt>::const_iterator
|
||||||
E = SD.fixit_end();
|
I = SD.FixIts.begin(), E = SD.FixIts.end();
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
FixIts.push_back(FixItHint());
|
FixIts.push_back(FixItHint());
|
||||||
FixItHint &FH = FixIts.back();
|
FixItHint &FH = FixIts.back();
|
||||||
FH.CodeToInsert = I->CodeToInsert;
|
FH.CodeToInsert = I->CodeToInsert;
|
||||||
SourceLocation BL = I->RemoveRange.getBegin();
|
SourceLocation BL = FileLoc.getLocWithOffset(I->RemoveRange.first);
|
||||||
TranslateSLoc(BL, Remap);
|
SourceLocation EL = FileLoc.getLocWithOffset(I->RemoveRange.second);
|
||||||
SourceLocation EL = I->RemoveRange.getEnd();
|
FH.RemoveRange = CharSourceRange::getCharRange(BL, EL);
|
||||||
TranslateSLoc(EL, Remap);
|
|
||||||
FH.RemoveRange = CharSourceRange(SourceRange(BL, EL),
|
|
||||||
I->RemoveRange.isTokenRange());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result.push_back(StoredDiagnostic(SD.getLevel(), SD.getID(),
|
Result.push_back(StoredDiagnostic(SD.Level, SD.ID,
|
||||||
SD.getMessage(), Loc, Ranges, FixIts));
|
SD.Message, Loc, Ranges, FixIts));
|
||||||
}
|
}
|
||||||
Result.swap(Out);
|
Result.swap(Out);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue