summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp317
1 files changed, 235 insertions, 82 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp b/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
index c63e98d..caf1f0d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
@@ -169,9 +169,7 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
// If this location is within a macro, walk from UnexpandedLoc up to Loc
// and produce a macro backtrace.
if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
- unsigned MacroDepth = 0;
- emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM,
- MacroDepth);
+ emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM);
}
}
@@ -247,7 +245,7 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
// import stack rather than the
// FIXME: We want submodule granularity here.
std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc);
- if (Imported.first.isValid()) {
+ if (!Imported.second.empty()) {
// This location was imported by a module. Emit the module import stack.
emitImportStackRecursively(Imported.first, Imported.second, SM);
return;
@@ -278,13 +276,11 @@ void DiagnosticRenderer::emitImportStack(SourceLocation Loc,
void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
StringRef ModuleName,
const SourceManager &SM) {
- if (Loc.isInvalid()) {
+ if (ModuleName.empty()) {
return;
}
PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
- if (PLoc.isInvalid())
- return;
// Emit the other import frames first.
std::pair<SourceLocation, StringRef> NextImportLoc
@@ -310,6 +306,81 @@ void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
}
}
+/// A recursive function to trace all possible backtrace locations
+/// to match the \p CaretLocFileID.
+static SourceLocation
+retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID,
+ FileID CaretFileID,
+ const SmallVectorImpl<FileID> &CommonArgExpansions,
+ bool IsBegin, const SourceManager *SM) {
+ assert(SM->getFileID(Loc) == MacroFileID);
+ if (MacroFileID == CaretFileID)
+ return Loc;
+ if (!Loc.isMacroID())
+ return SourceLocation();
+
+ SourceLocation MacroLocation, MacroArgLocation;
+
+ if (SM->isMacroArgExpansion(Loc)) {
+ // Only look at the immediate spelling location of this macro argument if
+ // the other location in the source range is also present in that expansion.
+ if (std::binary_search(CommonArgExpansions.begin(),
+ CommonArgExpansions.end(), MacroFileID))
+ MacroLocation = SM->getImmediateSpellingLoc(Loc);
+ MacroArgLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first
+ : SM->getImmediateExpansionRange(Loc).second;
+ } else {
+ MacroLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first
+ : SM->getImmediateExpansionRange(Loc).second;
+ MacroArgLocation = SM->getImmediateSpellingLoc(Loc);
+ }
+
+ if (MacroLocation.isValid()) {
+ MacroFileID = SM->getFileID(MacroLocation);
+ MacroLocation =
+ retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID,
+ CommonArgExpansions, IsBegin, SM);
+ if (MacroLocation.isValid())
+ return MacroLocation;
+ }
+
+ MacroFileID = SM->getFileID(MacroArgLocation);
+ return retrieveMacroLocation(MacroArgLocation, MacroFileID, CaretFileID,
+ CommonArgExpansions, IsBegin, SM);
+}
+
+/// Walk up the chain of macro expansions and collect the FileIDs identifying the
+/// expansions.
+static void getMacroArgExpansionFileIDs(SourceLocation Loc,
+ SmallVectorImpl<FileID> &IDs,
+ bool IsBegin, const SourceManager *SM) {
+ while (Loc.isMacroID()) {
+ if (SM->isMacroArgExpansion(Loc)) {
+ IDs.push_back(SM->getFileID(Loc));
+ Loc = SM->getImmediateSpellingLoc(Loc);
+ } else {
+ auto ExpRange = SM->getImmediateExpansionRange(Loc);
+ Loc = IsBegin ? ExpRange.first : ExpRange.second;
+ }
+ }
+}
+
+/// Collect the expansions of the begin and end locations and compute the set
+/// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions.
+static void computeCommonMacroArgExpansionFileIDs(
+ SourceLocation Begin, SourceLocation End, const SourceManager *SM,
+ SmallVectorImpl<FileID> &CommonArgExpansions) {
+ SmallVector<FileID, 4> BeginArgExpansions;
+ SmallVector<FileID, 4> EndArgExpansions;
+ getMacroArgExpansionFileIDs(Begin, BeginArgExpansions, /*IsBegin=*/true, SM);
+ getMacroArgExpansionFileIDs(End, EndArgExpansions, /*IsBegin=*/false, SM);
+ std::sort(BeginArgExpansions.begin(), BeginArgExpansions.end());
+ std::sort(EndArgExpansions.begin(), EndArgExpansions.end());
+ std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
+ EndArgExpansions.begin(), EndArgExpansions.end(),
+ std::back_inserter(CommonArgExpansions));
+}
+
// Helper function to fix up source ranges. It takes in an array of ranges,
// and outputs an array of ranges where we want to draw the range highlighting
// around the location specified by CaretLoc.
@@ -327,9 +398,9 @@ static void mapDiagnosticRanges(
const SourceManager *SM) {
FileID CaretLocFileID = SM->getFileID(CaretLoc);
- for (ArrayRef<CharSourceRange>::const_iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I) {
+ for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
+ if (I->isInvalid()) continue;
+
SourceLocation Begin = I->getBegin(), End = I->getEnd();
bool IsTokenRange = I->isTokenRange();
@@ -358,27 +429,19 @@ static void mapDiagnosticRanges(
}
}
- while (Begin.isMacroID() && BeginFileID != CaretLocFileID) {
- if (SM->isMacroArgExpansion(Begin)) {
- Begin = SM->getImmediateSpellingLoc(Begin);
- End = SM->getImmediateSpellingLoc(End);
- } else {
- Begin = SM->getImmediateExpansionRange(Begin).first;
- End = SM->getImmediateExpansionRange(End).second;
- }
- BeginFileID = SM->getFileID(Begin);
- if (BeginFileID != SM->getFileID(End)) {
- // FIXME: Ugly hack to stop a crash; this code is making bad
- // assumptions and it's too complicated for me to reason
- // about.
- Begin = End = SourceLocation();
- break;
- }
- }
+ // Do the backtracking.
+ SmallVector<FileID, 4> CommonArgExpansions;
+ computeCommonMacroArgExpansionFileIDs(Begin, End, SM, CommonArgExpansions);
+ Begin = retrieveMacroLocation(Begin, BeginFileID, CaretLocFileID,
+ CommonArgExpansions, /*IsBegin=*/true, SM);
+ End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID,
+ CommonArgExpansions, /*IsBegin=*/false, SM);
+ if (Begin.isInvalid() || End.isInvalid()) continue;
// Return the spelling location of the beginning and end of the range.
Begin = SM->getSpellingLoc(Begin);
End = SM->getSpellingLoc(End);
+
SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End),
IsTokenRange));
}
@@ -394,6 +457,96 @@ void DiagnosticRenderer::emitCaret(SourceLocation Loc,
emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
}
+/// \brief A helper function for emitMacroExpansion to print the
+/// macro expansion message
+void DiagnosticRenderer::emitSingleMacroExpansion(
+ SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges,
+ const SourceManager &SM) {
+ // Find the spelling location for the macro definition. We must use the
+ // spelling location here to avoid emitting a macro backtrace for the note.
+ SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
+
+ // Map the ranges into the FileID of the diagnostic location.
+ SmallVector<CharSourceRange, 4> SpellingRanges;
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+
+ SmallString<100> MessageStorage;
+ llvm::raw_svector_ostream Message(MessageStorage);
+ StringRef MacroName = getImmediateMacroName(Loc, SM, LangOpts);
+ if (MacroName.empty())
+ Message << "expanded from here";
+ else
+ Message << "expanded from macro '" << MacroName << "'";
+
+ emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(),
+ SpellingRanges, None, &SM);
+}
+
+/// Check that the macro argument location of Loc starts with ArgumentLoc.
+/// The starting location of the macro expansions is used to differeniate
+/// different macro expansions.
+static bool checkLocForMacroArgExpansion(SourceLocation Loc,
+ const SourceManager &SM,
+ SourceLocation ArgumentLoc) {
+ SourceLocation MacroLoc;
+ if (SM.isMacroArgExpansion(Loc, &MacroLoc)) {
+ if (ArgumentLoc == MacroLoc) return true;
+ }
+
+ return false;
+}
+
+/// Check if all the locations in the range have the same macro argument
+/// expansion, and that that expansion starts with ArgumentLoc.
+static bool checkRangeForMacroArgExpansion(CharSourceRange Range,
+ const SourceManager &SM,
+ SourceLocation ArgumentLoc) {
+ SourceLocation BegLoc = Range.getBegin(), EndLoc = Range.getEnd();
+ while (BegLoc != EndLoc) {
+ if (!checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc))
+ return false;
+ BegLoc.getLocWithOffset(1);
+ }
+
+ return checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc);
+}
+
+/// A helper function to check if the current ranges are all inside the same
+/// macro argument expansion as Loc.
+static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
+ ArrayRef<CharSourceRange> Ranges,
+ const SourceManager &SM) {
+ assert(Loc.isMacroID() && "Must be a macro expansion!");
+
+ SmallVector<CharSourceRange, 4> SpellingRanges;
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+
+ /// Count all valid ranges.
+ unsigned ValidCount = 0;
+ for (auto I : Ranges)
+ if (I.isValid()) ValidCount++;
+
+ if (ValidCount > SpellingRanges.size())
+ return false;
+
+ /// To store the source location of the argument location.
+ SourceLocation ArgumentLoc;
+
+ /// Set the ArgumentLoc to the beginning location of the expansion of Loc
+ /// so to check if the ranges expands to the same beginning location.
+ if (!SM.isMacroArgExpansion(Loc,&ArgumentLoc))
+ return false;
+
+ for (auto I = SpellingRanges.begin(), E = SpellingRanges.end(); I != E; ++I) {
+ if (!checkRangeForMacroArgExpansion(*I, SM, ArgumentLoc))
+ return false;
+ }
+
+ return true;
+}
+
/// \brief Recursively emit notes for each macro expansion and caret
/// diagnostics where appropriate.
///
@@ -405,71 +558,68 @@ void DiagnosticRenderer::emitCaret(SourceLocation Loc,
/// \param Level The diagnostic level currently being emitted.
/// \param Ranges The underlined ranges for this code snippet.
/// \param Hints The FixIt hints active for this diagnostic.
-/// \param OnMacroInst The current depth of the macro expansion stack.
void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> Hints,
- const SourceManager &SM,
- unsigned &MacroDepth,
- unsigned OnMacroInst) {
- assert(!Loc.isInvalid() && "must have a valid source location here");
-
- // Walk up to the caller of this macro, and produce a backtrace down to there.
- SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc);
- if (OneLevelUp.isMacroID())
- emitMacroExpansions(OneLevelUp, Level, Ranges, Hints, SM,
- MacroDepth, OnMacroInst + 1);
- else
- MacroDepth = OnMacroInst + 1;
-
- unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
- if (MacroDepth > DiagOpts->MacroBacktraceLimit &&
- DiagOpts->MacroBacktraceLimit != 0) {
- MacroSkipStart = DiagOpts->MacroBacktraceLimit / 2 +
- DiagOpts->MacroBacktraceLimit % 2;
- MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2;
+ const SourceManager &SM) {
+ assert(Loc.isValid() && "must have a valid source location here");
+
+ // Produce a stack of macro backtraces.
+ SmallVector<SourceLocation, 8> LocationStack;
+ unsigned IgnoredEnd = 0;
+ while (Loc.isMacroID()) {
+ // If this is the expansion of a macro argument, point the caret at the
+ // use of the argument in the definition of the macro, not the expansion.
+ if (SM.isMacroArgExpansion(Loc))
+ LocationStack.push_back(SM.getImmediateExpansionRange(Loc).first);
+ else
+ LocationStack.push_back(Loc);
+
+ if (checkRangesForMacroArgExpansion(Loc, Ranges, SM))
+ IgnoredEnd = LocationStack.size();
+
+ Loc = SM.getImmediateMacroCallerLoc(Loc);
+
+ // Once the location no longer points into a macro, try stepping through
+ // the last found location. This sometimes produces additional useful
+ // backtraces.
+ if (Loc.isFileID())
+ Loc = SM.getImmediateMacroCallerLoc(LocationStack.back());
+ assert(Loc.isValid() && "must have a valid source location here");
}
- // Whether to suppress printing this macro expansion.
- bool Suppressed = (OnMacroInst >= MacroSkipStart &&
- OnMacroInst < MacroSkipEnd);
-
- if (Suppressed) {
- // Tell the user that we've skipped contexts.
- if (OnMacroInst == MacroSkipStart) {
- SmallString<200> MessageStorage;
- llvm::raw_svector_ostream Message(MessageStorage);
- Message << "(skipping " << (MacroSkipEnd - MacroSkipStart)
- << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
- "see all)";
- emitBasicNote(Message.str());
- }
+ LocationStack.erase(LocationStack.begin(),
+ LocationStack.begin() + IgnoredEnd);
+
+ unsigned MacroDepth = LocationStack.size();
+ unsigned MacroLimit = DiagOpts->MacroBacktraceLimit;
+ if (MacroDepth <= MacroLimit || MacroLimit == 0) {
+ for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
+ I != E; ++I)
+ emitSingleMacroExpansion(*I, Level, Ranges, SM);
return;
}
- // Find the spelling location for the macro definition. We must use the
- // spelling location here to avoid emitting a macro bactrace for the note.
- SourceLocation SpellingLoc = Loc;
- // If this is the expansion of a macro argument, point the caret at the
- // use of the argument in the definition of the macro, not the expansion.
- if (SM.isMacroArgExpansion(Loc))
- SpellingLoc = SM.getImmediateExpansionRange(Loc).first;
- SpellingLoc = SM.getSpellingLoc(SpellingLoc);
+ unsigned MacroStartMessages = MacroLimit / 2;
+ unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
- // Map the ranges into the FileID of the diagnostic location.
- SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+ for (auto I = LocationStack.rbegin(),
+ E = LocationStack.rbegin() + MacroStartMessages;
+ I != E; ++I)
+ emitSingleMacroExpansion(*I, Level, Ranges, SM);
- SmallString<100> MessageStorage;
+ SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
- StringRef MacroName = getImmediateMacroName(Loc, SM, LangOpts);
- if (MacroName.empty())
- Message << "expanded from here";
- else
- Message << "expanded from macro '" << MacroName << "'";
- emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(),
- SpellingRanges, None, &SM);
+ Message << "(skipping " << (MacroDepth - MacroLimit)
+ << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
+ "see all)";
+ emitBasicNote(Message.str());
+
+ for (auto I = LocationStack.rend() - MacroEndMessages,
+ E = LocationStack.rend();
+ I != E; ++I)
+ emitSingleMacroExpansion(*I, Level, Ranges, SM);
}
DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {}
@@ -492,8 +642,11 @@ void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
- Message << "in module '" << ModuleName << "' imported from "
- << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
+ Message << "in module '" << ModuleName;
+ if (PLoc.isValid())
+ Message << "' imported from " << PLoc.getFilename() << ':'
+ << PLoc.getLine();
+ Message << ":";
emitNote(Loc, Message.str(), &SM);
}
OpenPOWER on IntegriCloud