diff options
author | Ted Kremenek <kremenek@apple.com> | 2011-12-17 05:26:04 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2011-12-17 05:26:04 +0000 |
commit | 2898d4f7648e6ed5e9047068f1e8ee2f3c2bcd75 (patch) | |
tree | be41824d2640dc49bab6971470b099cb1a914e37 /lib/Frontend/TextDiagnostic.cpp | |
parent | 373cb7832090dd5a380be73fdff79881721eed00 (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.cpp | 284 |
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. |