From: Chandler Carruth Date: Wed, 7 Sep 2011 08:05:58 +0000 (+0000) Subject: Extract the emission of the diagnostic's location into a separate X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5770bb707db9169c258859a9e7c935f99a32d64c;p=clang Extract the emission of the diagnostic's location into a separate function. This is really the beginning of the second phase of refactorings here. The end goal is to have (roughly) three interfaces: 1) Base class to format a single diagnostic suitable for display on the console. 2) Extension of the base class which also displays a caret diagnostic suitable for display on the console. 3) An adaptor that implements the DiagnosticClient by delegating to #1 and/or #2 as appropriate. Once we have these, things like libclang's formatDiagnostic can use #1 and #2 to provide really well formatted (and consistently formatted!) textual formatting of diagnostics. Getting there is going to be quite a bit of shuffling. I'm basically sketching out where the interface boundaries can be drawn for #1 and #2 within the existing classes. That lets me shuffle with a minimum of fuss and delta. Once that's done, and any of the related interfaces that need to change are updated, I'll hoist these into separate headers and re-implement libclang in terms of their interfaces. Long WIP, but comments at each step welcome. =D git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139228 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h index 9f6f10029c..e4030bfb9a 100644 --- a/include/clang/Frontend/TextDiagnosticPrinter.h +++ b/include/clang/Frontend/TextDiagnosticPrinter.h @@ -60,6 +60,11 @@ public: const DiagnosticInfo &Info); private: + void EmitDiagnosticLoc(Diagnostic::Level Level, + const DiagnosticInfo &Info, + const SourceManager &SM, + PresumedLoc PLoc); + void EmitCaretDiagnostic(SourceLocation Loc, SmallVectorImpl &Ranges, const SourceManager &SM, diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 9fa23f8492..4fc694978c 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -942,6 +942,114 @@ static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM, return SM.getPresumedLoc(Loc); } +/// \brief Print out the file/line/column information and include trace. +/// +/// This method handlen the emission of the diagnostic location information. +/// This includes extracting as much location information as is present for the +/// diagnostic and printing it, as well as any include stack or source ranges +/// necessary. +void TextDiagnosticPrinter::EmitDiagnosticLoc(Diagnostic::Level Level, + const DiagnosticInfo &Info, + const SourceManager &SM, + PresumedLoc PLoc) { + if (PLoc.isInvalid()) { + // At least print the file name if available: + FileID FID = SM.getFileID(Info.getLocation()); + if (!FID.isInvalid()) { + const FileEntry* FE = SM.getFileEntryForID(FID); + if (FE && FE->getName()) { + OS << FE->getName(); + if (FE->getDevice() == 0 && FE->getInode() == 0 + && FE->getFileMode() == 0) { + // in PCH is a guess, but a good one: + OS << " (in PCH)"; + } + OS << ": "; + } + } + return; + } + unsigned LineNo = PLoc.getLine(); + + if (!DiagOpts->ShowLocation) + return; + + if (DiagOpts->ShowColors) + OS.changeColor(savedColor, true); + + OS << PLoc.getFilename(); + switch (DiagOpts->Format) { + case DiagnosticOptions::Clang: OS << ':' << LineNo; break; + case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; + case DiagnosticOptions::Vi: OS << " +" << LineNo; break; + } + + if (DiagOpts->ShowColumn) + // Compute the column number. + if (unsigned ColNo = PLoc.getColumn()) { + if (DiagOpts->Format == DiagnosticOptions::Msvc) { + OS << ','; + ColNo--; + } else + OS << ':'; + OS << ColNo; + } + switch (DiagOpts->Format) { + case DiagnosticOptions::Clang: + case DiagnosticOptions::Vi: OS << ':'; break; + case DiagnosticOptions::Msvc: OS << ") : "; break; + } + + if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { + FileID CaretFileID = + SM.getFileID(SM.getExpansionLoc(Info.getLocation())); + bool PrintedRange = false; + + for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { + // Ignore invalid ranges. + if (!Info.getRange(i).isValid()) continue; + + SourceLocation B = Info.getRange(i).getBegin(); + SourceLocation E = Info.getRange(i).getEnd(); + B = SM.getExpansionLoc(B); + E = SM.getExpansionLoc(E); + + // If the End location and the start location are the same and are a + // macro location, then the range was something that came from a + // macro expansion or _Pragma. If this is an object-like macro, the + // best we can do is to highlight the range. If this is a + // function-like macro, we'd also like to highlight the arguments. + if (B == E && Info.getRange(i).getEnd().isMacroID()) + E = SM.getExpansionRange(Info.getRange(i).getEnd()).second; + + std::pair BInfo = SM.getDecomposedLoc(B); + std::pair EInfo = SM.getDecomposedLoc(E); + + // If the start or end of the range is in another file, just discard + // it. + if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) + continue; + + // Add in the length of the token, so that we cover multi-char + // tokens. + unsigned TokSize = 0; + if (Info.getRange(i).isTokenRange()) + TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); + + OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' + << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' + << SM.getLineNumber(EInfo.first, EInfo.second) << ':' + << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) + << '}'; + PrintedRange = true; + } + + if (PrintedRange) + OS << ':'; + } + OS << ' '; +} + void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info) { // Default implementation (Warnings/errors count). @@ -956,113 +1064,20 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, if (!Prefix.empty()) OS << Prefix << ": "; - // If the location is specified, print out a file/line/col and include trace - // if enabled. if (Info.getLocation().isValid()) { const SourceManager &SM = Info.getSourceManager(); PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation()); - if (PLoc.isInvalid()) { - // At least print the file name if available: - FileID FID = SM.getFileID(Info.getLocation()); - if (!FID.isInvalid()) { - const FileEntry* FE = SM.getFileEntryForID(FID); - if (FE && FE->getName()) { - OS << FE->getName(); - if (FE->getDevice() == 0 && FE->getInode() == 0 - && FE->getFileMode() == 0) { - // in PCH is a guess, but a good one: - OS << " (in PCH)"; - } - OS << ": "; - } - } - } else { - unsigned LineNo = PLoc.getLine(); - - // First, if this diagnostic is not in the main file, print out the - // "included from" lines. - PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM); - StartOfLocationInfo = OS.tell(); - - // Compute the column number. - if (DiagOpts->ShowLocation) { - if (DiagOpts->ShowColors) - OS.changeColor(savedColor, true); - - OS << PLoc.getFilename(); - switch (DiagOpts->Format) { - case DiagnosticOptions::Clang: OS << ':' << LineNo; break; - case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; - case DiagnosticOptions::Vi: OS << " +" << LineNo; break; - } - if (DiagOpts->ShowColumn) - if (unsigned ColNo = PLoc.getColumn()) { - if (DiagOpts->Format == DiagnosticOptions::Msvc) { - OS << ','; - ColNo--; - } else - OS << ':'; - OS << ColNo; - } - switch (DiagOpts->Format) { - case DiagnosticOptions::Clang: - case DiagnosticOptions::Vi: OS << ':'; break; - case DiagnosticOptions::Msvc: OS << ") : "; break; - } - - if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { - FileID CaretFileID = - SM.getFileID(SM.getExpansionLoc(Info.getLocation())); - bool PrintedRange = false; - - for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { - // Ignore invalid ranges. - if (!Info.getRange(i).isValid()) continue; - - SourceLocation B = Info.getRange(i).getBegin(); - SourceLocation E = Info.getRange(i).getEnd(); - B = SM.getExpansionLoc(B); - E = SM.getExpansionLoc(E); - - // If the End location and the start location are the same and are a - // macro location, then the range was something that came from a - // macro expansion or _Pragma. If this is an object-like macro, the - // best we can do is to highlight the range. If this is a - // function-like macro, we'd also like to highlight the arguments. - if (B == E && Info.getRange(i).getEnd().isMacroID()) - E = SM.getExpansionRange(Info.getRange(i).getEnd()).second; - - std::pair BInfo = SM.getDecomposedLoc(B); - std::pair EInfo = SM.getDecomposedLoc(E); - - // If the start or end of the range is in another file, just discard - // it. - if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) - continue; - - // Add in the length of the token, so that we cover multi-char - // tokens. - unsigned TokSize = 0; - if (Info.getRange(i).isTokenRange()) - TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); - - OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' - << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' - << SM.getLineNumber(EInfo.first, EInfo.second) << ':' - << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) - << '}'; - PrintedRange = true; - } - - if (PrintedRange) - OS << ':'; - } - } - OS << ' '; - if (DiagOpts->ShowColors) - OS.resetColor(); - } + // First, if this diagnostic is not in the main file, print out the + // "included from" lines. + PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM); + StartOfLocationInfo = OS.tell(); + + // Next emit the location of this particular diagnostic. + EmitDiagnosticLoc(Level, Info, SM, PLoc); + + if (DiagOpts->ShowColors) + OS.resetColor(); } if (DiagOpts->ShowColors) {