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
This commit is contained in:
Chandler Carruth 2011-09-07 08:05:58 +00:00
Родитель 6c57ccec99
Коммит 5770bb707d
2 изменённых файлов: 121 добавлений и 101 удалений

Просмотреть файл

@ -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<CharSourceRange> &Ranges,
const SourceManager &SM,

Просмотреть файл

@ -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<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
std::pair<FileID, unsigned> 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();
// 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);
// Next emit the location of this particular diagnostic.
EmitDiagnosticLoc(Level, Info, SM, PLoc);
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<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
std::pair<FileID, unsigned> 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();
}
if (DiagOpts->ShowColors)
OS.resetColor();
}
if (DiagOpts->ShowColors) {