aboutsummaryrefslogtreecommitdiff
path: root/lib/Frontend/TextDiagnostic.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2011-12-17 05:26:04 +0000
committerTed Kremenek <kremenek@apple.com>2011-12-17 05:26:04 +0000
commit2898d4f7648e6ed5e9047068f1e8ee2f3c2bcd75 (patch)
treebe41824d2640dc49bab6971470b099cb1a914e37 /lib/Frontend/TextDiagnostic.cpp
parent373cb7832090dd5a380be73fdff79881721eed00 (diff)
Refactor 'TextDiagnostic' to have a parent class 'DiagnosticRenderer' which handles
the policy of how diagnostics are lowered/rendered, while TextDiagnostic handles the actual pretty-printing. This is a first part of reworking SerializedDiagnosticPrinter to use the same inclusion-stack/macro-expansion logic as TextDiagnostic. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146819 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend/TextDiagnostic.cpp')
-rw-r--r--lib/Frontend/TextDiagnostic.cpp284
1 files changed, 24 insertions, 260 deletions
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index 425bc26fcc..d2b8660c62 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -174,70 +174,6 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
}
}
-/// Look through spelling locations for a macro argument expansion, and
-/// if found skip to it so that we can trace the argument rather than the macros
-/// in which that argument is used. If no macro argument expansion is found,
-/// don't skip anything and return the starting location.
-static SourceLocation skipToMacroArgExpansion(const SourceManager &SM,
- SourceLocation StartLoc) {
- for (SourceLocation L = StartLoc; L.isMacroID();
- L = SM.getImmediateSpellingLoc(L)) {
- if (SM.isMacroArgExpansion(L))
- return L;
- }
-
- // Otherwise just return initial location, there's nothing to skip.
- return StartLoc;
-}
-
-/// Gets the location of the immediate macro caller, one level up the stack
-/// toward the initial macro typed into the source.
-static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM,
- SourceLocation Loc) {
- if (!Loc.isMacroID()) return Loc;
-
- // When we have the location of (part of) an expanded parameter, its spelling
- // location points to the argument as typed into the macro call, and
- // therefore is used to locate the macro caller.
- if (SM.isMacroArgExpansion(Loc))
- return SM.getImmediateSpellingLoc(Loc);
-
- // Otherwise, the caller of the macro is located where this macro is
- // expanded (while the spelling is part of the macro definition).
- return SM.getImmediateExpansionRange(Loc).first;
-}
-
-/// Gets the location of the immediate macro callee, one level down the stack
-/// toward the leaf macro.
-static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM,
- SourceLocation Loc) {
- if (!Loc.isMacroID()) return Loc;
-
- // When we have the location of (part of) an expanded parameter, its
- // expansion location points to the unexpanded paramater reference within
- // the macro definition (or callee).
- if (SM.isMacroArgExpansion(Loc))
- return SM.getImmediateExpansionRange(Loc).first;
-
- // Otherwise, the callee of the macro is located where this location was
- // spelled inside the macro definition.
- return SM.getImmediateSpellingLoc(Loc);
-}
-
-/// Get the presumed location of a diagnostic message. This computes the
-/// presumed location for the top of any macro backtrace when present.
-static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM,
- SourceLocation Loc) {
- // This is a condensed form of the algorithm used by emitCaretDiagnostic to
- // walk to the top of the macro call stack.
- while (Loc.isMacroID()) {
- Loc = skipToMacroArgExpansion(SM, Loc);
- Loc = getImmediateMacroCallerLoc(SM, Loc);
- }
-
- return SM.getPresumedLoc(Loc);
-}
-
/// \brief Skip over whitespace in the string, starting at the given
/// index.
///
@@ -389,85 +325,33 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str,
return Wrapped;
}
-/// \brief Retrieve the name of the immediate macro expansion.
-///
-/// This routine starts from a source location, and finds the name of the macro
-/// responsible for its immediate expansion. It looks through any intervening
-/// macro argument expansions to compute this. It returns a StringRef which
-/// refers to the SourceManager-owned buffer of the source where that macro
-/// name is spelled. Thus, the result shouldn't out-live that SourceManager.
-///
-static StringRef getImmediateMacroName(SourceLocation Loc,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
- assert(Loc.isMacroID() && "Only reasonble to call this on macros");
- // Walk past macro argument expanions.
- while (SM.isMacroArgExpansion(Loc))
- Loc = SM.getImmediateExpansionRange(Loc).first;
-
- // Find the spelling location of the start of the non-argument expansion
- // range. This is where the macro name was spelled in order to begin
- // expanding this macro.
- Loc = SM.getSpellingLoc(SM.getImmediateExpansionRange(Loc).first);
-
- // Dig out the buffer where the macro name was spelled and the extents of the
- // name so that we can render it into the expansion note.
- std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc);
- unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
- StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first);
- return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
-}
-
TextDiagnostic::TextDiagnostic(raw_ostream &OS,
const SourceManager &SM,
const LangOptions &LangOpts,
const DiagnosticOptions &DiagOpts)
- : OS(OS), SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {
-}
-
-void TextDiagnostic::emitDiagnostic(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> FixItHints) {
- PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Loc);
+ : DiagnosticRenderer(SM, LangOpts, DiagOpts), OS(OS) {}
- // First, if this diagnostic is not in the main file, print out the
- // "included from" lines.
- emitIncludeStack(PLoc.getIncludeLoc(), Level);
+TextDiagnostic::~TextDiagnostic() {}
+void
+TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
+ PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<clang::CharSourceRange> Ranges,
+ const Diagnostic *Info) {
uint64_t StartOfLocationInfo = OS.tell();
- // Next emit the location of this particular diagnostic.
+ // Emit the location of this particular diagnostic.
emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
-
+
if (DiagOpts.ShowColors)
OS.resetColor();
-
+
printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
printDiagnosticMessage(OS, Level, Message,
OS.tell() - StartOfLocationInfo,
DiagOpts.MessageLength, DiagOpts.ShowColors);
-
- // Only recurse if we have a valid location.
- if (Loc.isValid()) {
- // Get the ranges into a local array we can hack on.
- SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
- Ranges.end());
-
- for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(),
- E = FixItHints.end();
- I != E; ++I)
- if (I->RemoveRange.isValid())
- MutableRanges.push_back(I->RemoveRange);
-
- unsigned MacroDepth = 0;
- emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints,
- MacroDepth);
- }
-
- LastLoc = Loc;
- LastLevel = Level;
}
/*static*/ void
@@ -525,50 +409,6 @@ TextDiagnostic::printDiagnosticMessage(raw_ostream &OS,
OS << '\n';
}
-/// \brief Prints an include stack when appropriate for a particular
-/// diagnostic level and location.
-///
-/// This routine handles all the logic of suppressing particular include
-/// stacks (such as those for notes) and duplicate include stacks when
-/// repeated warnings occur within the same file. It also handles the logic
-/// of customizing the formatting and display of the include stack.
-///
-/// \param Level The diagnostic level of the message this stack pertains to.
-/// \param Loc The include location of the current file (not the diagnostic
-/// location).
-void TextDiagnostic::emitIncludeStack(SourceLocation Loc,
- DiagnosticsEngine::Level Level) {
- // Skip redundant include stacks altogether.
- if (LastIncludeLoc == Loc)
- return;
- LastIncludeLoc = Loc;
-
- if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
- return;
-
- emitIncludeStackRecursively(Loc);
-}
-
-/// \brief Helper to recursivly walk up the include stack and print each layer
-/// on the way back down.
-void TextDiagnostic::emitIncludeStackRecursively(SourceLocation Loc) {
- if (Loc.isInvalid())
- return;
-
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
- if (PLoc.isInvalid())
- return;
-
- // Emit the other include frames first.
- emitIncludeStackRecursively(PLoc.getIncludeLoc());
-
- if (DiagOpts.ShowLocation)
- OS << "In file included from " << PLoc.getFilename()
- << ':' << PLoc.getLine() << ":\n";
- else
- OS << "In included file:\n";
-}
-
/// \brief Print out the file/line/column information and include trace.
///
/// This method handlen the emission of the diagnostic location information.
@@ -676,95 +516,19 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
OS << ' ';
}
-/// \brief Recursively emit notes for each macro expansion and caret
-/// diagnostics where appropriate.
-///
-/// Walks up the macro expansion stack printing expansion notes, the code
-/// snippet, caret, underlines and FixItHint display as appropriate at each
-/// level.
-///
-/// \param Loc The location for this caret.
-/// \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 MacroSkipEnd The depth to stop skipping macro expansions.
-/// \param OnMacroInst The current depth of the macro expansion stack.
-void TextDiagnostic::emitMacroExpansionsAndCarets(
- SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- unsigned &MacroDepth,
- unsigned OnMacroInst) {
- assert(!Loc.isInvalid() && "must have a valid source location here");
-
- // If this is a file source location, directly emit the source snippet and
- // caret line. Also record the macro depth reached.
- if (Loc.isFileID()) {
- assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!");
- MacroDepth = OnMacroInst;
- emitSnippetAndCaret(Loc, Level, Ranges, Hints);
- return;
- }
- // Otherwise recurse through each macro expansion layer.
-
- // When processing macros, skip over the expansions leading up to
- // a macro argument, and trace the argument's expansion stack instead.
- Loc = skipToMacroArgExpansion(SM, Loc);
-
- SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc);
-
- // FIXME: Map ranges?
- emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, MacroDepth,
- OnMacroInst + 1);
-
- // Save the original location so we can find the spelling of the macro call.
- SourceLocation MacroLoc = Loc;
-
- // Map the location.
- Loc = getImmediateMacroCalleeLoc(SM, Loc);
-
- unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
- if (MacroDepth > DiagOpts.MacroBacktraceLimit) {
- MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 +
- DiagOpts.MacroBacktraceLimit % 2;
- MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2;
- }
-
- // Whether to suppress printing this macro expansion.
- bool Suppressed = (OnMacroInst >= MacroSkipStart &&
- OnMacroInst < MacroSkipEnd);
-
- // Map the ranges.
- for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I) {
- SourceLocation Start = I->getBegin(), End = I->getEnd();
- if (Start.isMacroID())
- I->setBegin(getImmediateMacroCalleeLoc(SM, Start));
- if (End.isMacroID())
- I->setEnd(getImmediateMacroCalleeLoc(SM, End));
- }
-
- if (Suppressed) {
- // Tell the user that we've skipped contexts.
- if (OnMacroInst == MacroSkipStart) {
- // FIXME: Emit this as a real note diagnostic.
- // FIXME: Format an actual diagnostic rather than a hard coded string.
- OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart)
- << " expansions in backtrace; use -fmacro-backtrace-limit=0 to see "
- "all)\n";
- }
- return;
- }
+void TextDiagnostic::emitBasicNote(StringRef Message) {
+ // FIXME: Emit this as a real note diagnostic.
+ // FIXME: Format an actual diagnostic rather than a hard coded string.
+ OS << "note: " << Message << "\n";
+}
- llvm::SmallString<100> MessageStorage;
- llvm::raw_svector_ostream Message(MessageStorage);
- Message << "expanded from macro '"
- << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'";
- emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note,
- Message.str(),
- Ranges, ArrayRef<FixItHint>());
+void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
+ PresumedLoc PLoc) {
+ if (DiagOpts.ShowLocation)
+ OS << "In file included from " << PLoc.getFilename() << ':'
+ << PLoc.getLine() << ":\n";
+ else
+ OS << "In included file:\n";
}
/// \brief Emit a code snippet and caret line.