TextDiagnosticPrinter.cpp revision d614040a678c994b0171234e7f5f9cf61e9f86fe
1//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This diagnostic client prints out their diagnostic messages. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/Frontend/TextDiagnosticPrinter.h" 15#include "clang/Basic/FileManager.h" 16#include "clang/Basic/SourceManager.h" 17#include "clang/Frontend/DiagnosticOptions.h" 18#include "clang/Lex/Lexer.h" 19#include "llvm/Support/MemoryBuffer.h" 20#include "llvm/Support/raw_ostream.h" 21#include "llvm/Support/ErrorHandling.h" 22#include "llvm/ADT/SmallString.h" 23#include <algorithm> 24using namespace clang; 25 26static const enum raw_ostream::Colors noteColor = 27 raw_ostream::BLACK; 28static const enum raw_ostream::Colors fixitColor = 29 raw_ostream::GREEN; 30static const enum raw_ostream::Colors caretColor = 31 raw_ostream::GREEN; 32static const enum raw_ostream::Colors warningColor = 33 raw_ostream::MAGENTA; 34static const enum raw_ostream::Colors errorColor = raw_ostream::RED; 35static const enum raw_ostream::Colors fatalColor = raw_ostream::RED; 36// Used for changing only the bold attribute. 37static const enum raw_ostream::Colors savedColor = 38 raw_ostream::SAVEDCOLOR; 39 40/// \brief Number of spaces to indent when word-wrapping. 41const unsigned WordWrapIndentation = 6; 42 43TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os, 44 const DiagnosticOptions &diags, 45 bool _OwnsOutputStream) 46 : OS(os), LangOpts(0), DiagOpts(&diags), 47 LastCaretDiagnosticWasNote(0), 48 OwnsOutputStream(_OwnsOutputStream) { 49} 50 51TextDiagnosticPrinter::~TextDiagnosticPrinter() { 52 if (OwnsOutputStream) 53 delete &OS; 54} 55 56/// \brief When the source code line we want to print is too long for 57/// the terminal, select the "interesting" region. 58static void SelectInterestingSourceRegion(std::string &SourceLine, 59 std::string &CaretLine, 60 std::string &FixItInsertionLine, 61 unsigned EndOfCaretToken, 62 unsigned Columns) { 63 unsigned MaxSize = std::max(SourceLine.size(), 64 std::max(CaretLine.size(), 65 FixItInsertionLine.size())); 66 if (MaxSize > SourceLine.size()) 67 SourceLine.resize(MaxSize, ' '); 68 if (MaxSize > CaretLine.size()) 69 CaretLine.resize(MaxSize, ' '); 70 if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size()) 71 FixItInsertionLine.resize(MaxSize, ' '); 72 73 // Find the slice that we need to display the full caret line 74 // correctly. 75 unsigned CaretStart = 0, CaretEnd = CaretLine.size(); 76 for (; CaretStart != CaretEnd; ++CaretStart) 77 if (!isspace(CaretLine[CaretStart])) 78 break; 79 80 for (; CaretEnd != CaretStart; --CaretEnd) 81 if (!isspace(CaretLine[CaretEnd - 1])) 82 break; 83 84 // Make sure we don't chop the string shorter than the caret token 85 // itself. 86 if (CaretEnd < EndOfCaretToken) 87 CaretEnd = EndOfCaretToken; 88 89 // If we have a fix-it line, make sure the slice includes all of the 90 // fix-it information. 91 if (!FixItInsertionLine.empty()) { 92 unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size(); 93 for (; FixItStart != FixItEnd; ++FixItStart) 94 if (!isspace(FixItInsertionLine[FixItStart])) 95 break; 96 97 for (; FixItEnd != FixItStart; --FixItEnd) 98 if (!isspace(FixItInsertionLine[FixItEnd - 1])) 99 break; 100 101 if (FixItStart < CaretStart) 102 CaretStart = FixItStart; 103 if (FixItEnd > CaretEnd) 104 CaretEnd = FixItEnd; 105 } 106 107 // CaretLine[CaretStart, CaretEnd) contains all of the interesting 108 // parts of the caret line. While this slice is smaller than the 109 // number of columns we have, try to grow the slice to encompass 110 // more context. 111 112 // If the end of the interesting region comes before we run out of 113 // space in the terminal, start at the beginning of the line. 114 if (Columns > 3 && CaretEnd < Columns - 3) 115 CaretStart = 0; 116 117 unsigned TargetColumns = Columns; 118 if (TargetColumns > 8) 119 TargetColumns -= 8; // Give us extra room for the ellipses. 120 unsigned SourceLength = SourceLine.size(); 121 while ((CaretEnd - CaretStart) < TargetColumns) { 122 bool ExpandedRegion = false; 123 // Move the start of the interesting region left until we've 124 // pulled in something else interesting. 125 if (CaretStart == 1) 126 CaretStart = 0; 127 else if (CaretStart > 1) { 128 unsigned NewStart = CaretStart - 1; 129 130 // Skip over any whitespace we see here; we're looking for 131 // another bit of interesting text. 132 while (NewStart && isspace(SourceLine[NewStart])) 133 --NewStart; 134 135 // Skip over this bit of "interesting" text. 136 while (NewStart && !isspace(SourceLine[NewStart])) 137 --NewStart; 138 139 // Move up to the non-whitespace character we just saw. 140 if (NewStart) 141 ++NewStart; 142 143 // If we're still within our limit, update the starting 144 // position within the source/caret line. 145 if (CaretEnd - NewStart <= TargetColumns) { 146 CaretStart = NewStart; 147 ExpandedRegion = true; 148 } 149 } 150 151 // Move the end of the interesting region right until we've 152 // pulled in something else interesting. 153 if (CaretEnd != SourceLength) { 154 assert(CaretEnd < SourceLength && "Unexpected caret position!"); 155 unsigned NewEnd = CaretEnd; 156 157 // Skip over any whitespace we see here; we're looking for 158 // another bit of interesting text. 159 while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1])) 160 ++NewEnd; 161 162 // Skip over this bit of "interesting" text. 163 while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1])) 164 ++NewEnd; 165 166 if (NewEnd - CaretStart <= TargetColumns) { 167 CaretEnd = NewEnd; 168 ExpandedRegion = true; 169 } 170 } 171 172 if (!ExpandedRegion) 173 break; 174 } 175 176 // [CaretStart, CaretEnd) is the slice we want. Update the various 177 // output lines to show only this slice, with two-space padding 178 // before the lines so that it looks nicer. 179 if (CaretEnd < SourceLine.size()) 180 SourceLine.replace(CaretEnd, std::string::npos, "..."); 181 if (CaretEnd < CaretLine.size()) 182 CaretLine.erase(CaretEnd, std::string::npos); 183 if (FixItInsertionLine.size() > CaretEnd) 184 FixItInsertionLine.erase(CaretEnd, std::string::npos); 185 186 if (CaretStart > 2) { 187 SourceLine.replace(0, CaretStart, " ..."); 188 CaretLine.replace(0, CaretStart, " "); 189 if (FixItInsertionLine.size() >= CaretStart) 190 FixItInsertionLine.replace(0, CaretStart, " "); 191 } 192} 193 194/// Look through spelling locations for a macro argument expansion, and 195/// if found skip to it so that we can trace the argument rather than the macros 196/// in which that argument is used. If no macro argument expansion is found, 197/// don't skip anything and return the starting location. 198static SourceLocation skipToMacroArgExpansion(const SourceManager &SM, 199 SourceLocation StartLoc) { 200 for (SourceLocation L = StartLoc; L.isMacroID(); 201 L = SM.getImmediateSpellingLoc(L)) { 202 if (SM.isMacroArgExpansion(L)) 203 return L; 204 } 205 206 // Otherwise just return initial location, there's nothing to skip. 207 return StartLoc; 208} 209 210/// Gets the location of the immediate macro caller, one level up the stack 211/// toward the initial macro typed into the source. 212static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM, 213 SourceLocation Loc) { 214 if (!Loc.isMacroID()) return Loc; 215 216 // When we have the location of (part of) an expanded parameter, its spelling 217 // location points to the argument as typed into the macro call, and 218 // therefore is used to locate the macro caller. 219 if (SM.isMacroArgExpansion(Loc)) 220 return SM.getImmediateSpellingLoc(Loc); 221 222 // Otherwise, the caller of the macro is located where this macro is 223 // expanded (while the spelling is part of the macro definition). 224 return SM.getImmediateExpansionRange(Loc).first; 225} 226 227/// Gets the location of the immediate macro callee, one level down the stack 228/// toward the leaf macro. 229static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM, 230 SourceLocation Loc) { 231 if (!Loc.isMacroID()) return Loc; 232 233 // When we have the location of (part of) an expanded parameter, its 234 // expansion location points to the unexpanded paramater reference within 235 // the macro definition (or callee). 236 if (SM.isMacroArgExpansion(Loc)) 237 return SM.getImmediateExpansionRange(Loc).first; 238 239 // Otherwise, the callee of the macro is located where this location was 240 // spelled inside the macro definition. 241 return SM.getImmediateSpellingLoc(Loc); 242} 243 244/// Get the presumed location of a diagnostic message. This computes the 245/// presumed location for the top of any macro backtrace when present. 246static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM, 247 SourceLocation Loc) { 248 // This is a condensed form of the algorithm used by EmitCaretDiagnostic to 249 // walk to the top of the macro call stack. 250 while (Loc.isMacroID()) { 251 Loc = skipToMacroArgExpansion(SM, Loc); 252 Loc = getImmediateMacroCallerLoc(SM, Loc); 253 } 254 255 return SM.getPresumedLoc(Loc); 256} 257 258/// \brief Print the diagonstic level to a raw_ostream. 259/// 260/// Handles colorizing the level and formatting. 261static void printDiagnosticLevel(raw_ostream &OS, 262 DiagnosticsEngine::Level Level, 263 bool ShowColors) { 264 if (ShowColors) { 265 // Print diagnostic category in bold and color 266 switch (Level) { 267 case DiagnosticsEngine::Ignored: 268 llvm_unreachable("Invalid diagnostic type"); 269 case DiagnosticsEngine::Note: OS.changeColor(noteColor, true); break; 270 case DiagnosticsEngine::Warning: OS.changeColor(warningColor, true); break; 271 case DiagnosticsEngine::Error: OS.changeColor(errorColor, true); break; 272 case DiagnosticsEngine::Fatal: OS.changeColor(fatalColor, true); break; 273 } 274 } 275 276 switch (Level) { 277 case DiagnosticsEngine::Ignored: llvm_unreachable("Invalid diagnostic type"); 278 case DiagnosticsEngine::Note: OS << "note: "; break; 279 case DiagnosticsEngine::Warning: OS << "warning: "; break; 280 case DiagnosticsEngine::Error: OS << "error: "; break; 281 case DiagnosticsEngine::Fatal: OS << "fatal error: "; break; 282 } 283 284 if (ShowColors) 285 OS.resetColor(); 286} 287 288/// \brief Skip over whitespace in the string, starting at the given 289/// index. 290/// 291/// \returns The index of the first non-whitespace character that is 292/// greater than or equal to Idx or, if no such character exists, 293/// returns the end of the string. 294static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) { 295 while (Idx < Length && isspace(Str[Idx])) 296 ++Idx; 297 return Idx; 298} 299 300/// \brief If the given character is the start of some kind of 301/// balanced punctuation (e.g., quotes or parentheses), return the 302/// character that will terminate the punctuation. 303/// 304/// \returns The ending punctuation character, if any, or the NULL 305/// character if the input character does not start any punctuation. 306static inline char findMatchingPunctuation(char c) { 307 switch (c) { 308 case '\'': return '\''; 309 case '`': return '\''; 310 case '"': return '"'; 311 case '(': return ')'; 312 case '[': return ']'; 313 case '{': return '}'; 314 default: break; 315 } 316 317 return 0; 318} 319 320/// \brief Find the end of the word starting at the given offset 321/// within a string. 322/// 323/// \returns the index pointing one character past the end of the 324/// word. 325static unsigned findEndOfWord(unsigned Start, StringRef Str, 326 unsigned Length, unsigned Column, 327 unsigned Columns) { 328 assert(Start < Str.size() && "Invalid start position!"); 329 unsigned End = Start + 1; 330 331 // If we are already at the end of the string, take that as the word. 332 if (End == Str.size()) 333 return End; 334 335 // Determine if the start of the string is actually opening 336 // punctuation, e.g., a quote or parentheses. 337 char EndPunct = findMatchingPunctuation(Str[Start]); 338 if (!EndPunct) { 339 // This is a normal word. Just find the first space character. 340 while (End < Length && !isspace(Str[End])) 341 ++End; 342 return End; 343 } 344 345 // We have the start of a balanced punctuation sequence (quotes, 346 // parentheses, etc.). Determine the full sequence is. 347 llvm::SmallString<16> PunctuationEndStack; 348 PunctuationEndStack.push_back(EndPunct); 349 while (End < Length && !PunctuationEndStack.empty()) { 350 if (Str[End] == PunctuationEndStack.back()) 351 PunctuationEndStack.pop_back(); 352 else if (char SubEndPunct = findMatchingPunctuation(Str[End])) 353 PunctuationEndStack.push_back(SubEndPunct); 354 355 ++End; 356 } 357 358 // Find the first space character after the punctuation ended. 359 while (End < Length && !isspace(Str[End])) 360 ++End; 361 362 unsigned PunctWordLength = End - Start; 363 if (// If the word fits on this line 364 Column + PunctWordLength <= Columns || 365 // ... or the word is "short enough" to take up the next line 366 // without too much ugly white space 367 PunctWordLength < Columns/3) 368 return End; // Take the whole thing as a single "word". 369 370 // The whole quoted/parenthesized string is too long to print as a 371 // single "word". Instead, find the "word" that starts just after 372 // the punctuation and use that end-point instead. This will recurse 373 // until it finds something small enough to consider a word. 374 return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns); 375} 376 377/// \brief Print the given string to a stream, word-wrapping it to 378/// some number of columns in the process. 379/// 380/// \param OS the stream to which the word-wrapping string will be 381/// emitted. 382/// \param Str the string to word-wrap and output. 383/// \param Columns the number of columns to word-wrap to. 384/// \param Column the column number at which the first character of \p 385/// Str will be printed. This will be non-zero when part of the first 386/// line has already been printed. 387/// \param Indentation the number of spaces to indent any lines beyond 388/// the first line. 389/// \returns true if word-wrapping was required, or false if the 390/// string fit on the first line. 391static bool printWordWrapped(raw_ostream &OS, StringRef Str, 392 unsigned Columns, 393 unsigned Column = 0, 394 unsigned Indentation = WordWrapIndentation) { 395 const unsigned Length = std::min(Str.find('\n'), Str.size()); 396 397 // The string used to indent each line. 398 llvm::SmallString<16> IndentStr; 399 IndentStr.assign(Indentation, ' '); 400 bool Wrapped = false; 401 for (unsigned WordStart = 0, WordEnd; WordStart < Length; 402 WordStart = WordEnd) { 403 // Find the beginning of the next word. 404 WordStart = skipWhitespace(WordStart, Str, Length); 405 if (WordStart == Length) 406 break; 407 408 // Find the end of this word. 409 WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns); 410 411 // Does this word fit on the current line? 412 unsigned WordLength = WordEnd - WordStart; 413 if (Column + WordLength < Columns) { 414 // This word fits on the current line; print it there. 415 if (WordStart) { 416 OS << ' '; 417 Column += 1; 418 } 419 OS << Str.substr(WordStart, WordLength); 420 Column += WordLength; 421 continue; 422 } 423 424 // This word does not fit on the current line, so wrap to the next 425 // line. 426 OS << '\n'; 427 OS.write(&IndentStr[0], Indentation); 428 OS << Str.substr(WordStart, WordLength); 429 Column = Indentation + WordLength; 430 Wrapped = true; 431 } 432 433 // Append any remaning text from the message with its existing formatting. 434 OS << Str.substr(Length); 435 436 return Wrapped; 437} 438 439static void printDiagnosticMessage(raw_ostream &OS, 440 DiagnosticsEngine::Level Level, 441 StringRef Message, 442 unsigned CurrentColumn, unsigned Columns, 443 bool ShowColors) { 444 if (ShowColors) { 445 // Print warnings, errors and fatal errors in bold, no color 446 switch (Level) { 447 case DiagnosticsEngine::Warning: OS.changeColor(savedColor, true); break; 448 case DiagnosticsEngine::Error: OS.changeColor(savedColor, true); break; 449 case DiagnosticsEngine::Fatal: OS.changeColor(savedColor, true); break; 450 default: break; //don't bold notes 451 } 452 } 453 454 if (Columns) 455 printWordWrapped(OS, Message, Columns, CurrentColumn); 456 else 457 OS << Message; 458 459 if (ShowColors) 460 OS.resetColor(); 461 OS << '\n'; 462} 463 464namespace { 465 466/// \brief Class to encapsulate the logic for formatting and printing a textual 467/// diagnostic message. 468/// 469/// This class provides an interface for building and emitting a textual 470/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt 471/// Hints, and code snippets. In the presence of macros this involves 472/// a recursive process, synthesizing notes for each macro expansion. 473/// 474/// The purpose of this class is to isolate the implementation of printing 475/// beautiful text diagnostics from any particular interfaces. The Clang 476/// DiagnosticClient is implemented through this class as is diagnostic 477/// printing coming out of libclang. 478/// 479/// A brief worklist: 480/// FIXME: Sink the recursive printing of template instantiations into this 481/// class. 482class TextDiagnostic { 483 raw_ostream &OS; 484 const SourceManager &SM; 485 const LangOptions &LangOpts; 486 const DiagnosticOptions &DiagOpts; 487 488 /// \brief The location of the previous diagnostic if known. 489 /// 490 /// This will be invalid in cases where there is no (known) previous 491 /// diagnostic location, or that location itself is invalid or comes from 492 /// a different source manager than SM. 493 SourceLocation LastLoc; 494 495 /// \brief The location of the last include whose stack was printed if known. 496 /// 497 /// Same restriction as \see LastLoc essentially, but tracking include stack 498 /// root locations rather than diagnostic locations. 499 SourceLocation LastIncludeLoc; 500 501public: 502 TextDiagnostic(raw_ostream &OS, 503 const SourceManager &SM, 504 const LangOptions &LangOpts, 505 const DiagnosticOptions &DiagOpts, 506 FullSourceLoc LastLoc = FullSourceLoc(), 507 FullSourceLoc LastIncludeLoc = FullSourceLoc()) 508 : OS(OS), SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts), 509 LastLoc(LastLoc), LastIncludeLoc(LastIncludeLoc) { 510 if (LastLoc.isValid() && &SM != &LastLoc.getManager()) 511 this->LastLoc = SourceLocation(); 512 if (LastIncludeLoc.isValid() && &SM != &LastIncludeLoc.getManager()) 513 this->LastIncludeLoc = SourceLocation(); 514 } 515 516 /// \brief Get the last diagnostic location emitted. 517 SourceLocation getLastLoc() const { return LastLoc; } 518 519 /// \brief Get the last emitted include stack location. 520 SourceLocation getLastIncludeLoc() const { return LastIncludeLoc; } 521 522 void Emit(SourceLocation Loc, DiagnosticsEngine::Level Level, 523 StringRef Message, ArrayRef<CharSourceRange> Ranges, 524 ArrayRef<FixItHint> FixItHints, 525 bool LastCaretDiagnosticWasNote = false) { 526 PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Loc); 527 528 // First, if this diagnostic is not in the main file, print out the 529 // "included from" lines. 530 emitIncludeStack(PLoc.getIncludeLoc(), Level); 531 532 uint64_t StartOfLocationInfo = OS.tell(); 533 534 // Next emit the location of this particular diagnostic. 535 EmitDiagnosticLoc(Loc, PLoc, Level, Ranges); 536 537 if (DiagOpts.ShowColors) 538 OS.resetColor(); 539 540 printDiagnosticLevel(OS, Level, DiagOpts.ShowColors); 541 printDiagnosticMessage(OS, Level, Message, 542 OS.tell() - StartOfLocationInfo, 543 DiagOpts.MessageLength, DiagOpts.ShowColors); 544 545 // If caret diagnostics are enabled and we have location, we want to 546 // emit the caret. However, we only do this if the location moved 547 // from the last diagnostic, if the last diagnostic was a note that 548 // was part of a different warning or error diagnostic, or if the 549 // diagnostic has ranges. We don't want to emit the same caret 550 // multiple times if one loc has multiple diagnostics. 551 if (DiagOpts.ShowCarets && 552 (Loc != LastLoc || !Ranges.empty() || !FixItHints.empty() || 553 (LastCaretDiagnosticWasNote && Level != DiagnosticsEngine::Note))) { 554 // Get the ranges into a local array we can hack on. 555 SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), 556 Ranges.end()); 557 558 for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(), 559 E = FixItHints.end(); 560 I != E; ++I) 561 if (I->RemoveRange.isValid()) 562 MutableRanges.push_back(I->RemoveRange); 563 564 unsigned MacroDepth = 0; 565 EmitCaret(Loc, MutableRanges, FixItHints, MacroDepth); 566 } 567 568 LastLoc = Loc; 569 } 570 571 /// \brief Emit the caret and underlining text. 572 /// 573 /// Walks up the macro expansion stack printing the code snippet, caret, 574 /// underlines and FixItHint display as appropriate at each level. Walk is 575 /// accomplished by calling itself recursively. 576 /// 577 /// FIXME: Remove macro expansion from this routine, it shouldn't be tied to 578 /// caret diagnostics. 579 /// FIXME: Break up massive function into logical units. 580 /// 581 /// \param Loc The location for this caret. 582 /// \param Ranges The underlined ranges for this code snippet. 583 /// \param Hints The FixIt hints active for this diagnostic. 584 /// \param MacroSkipEnd The depth to stop skipping macro expansions. 585 /// \param OnMacroInst The current depth of the macro expansion stack. 586 void EmitCaret(SourceLocation Loc, 587 SmallVectorImpl<CharSourceRange>& Ranges, 588 ArrayRef<FixItHint> Hints, 589 unsigned &MacroDepth, 590 unsigned OnMacroInst = 0) { 591 assert(!Loc.isInvalid() && "must have a valid source location here"); 592 593 // If this is a file source location, directly emit the source snippet and 594 // caret line. Also record the macro depth reached. 595 if (Loc.isFileID()) { 596 assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!"); 597 MacroDepth = OnMacroInst; 598 EmitSnippetAndCaret(Loc, Ranges, Hints); 599 return; 600 } 601 // Otherwise recurse through each macro expansion layer. 602 603 // When processing macros, skip over the expansions leading up to 604 // a macro argument, and trace the argument's expansion stack instead. 605 Loc = skipToMacroArgExpansion(SM, Loc); 606 607 SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc); 608 609 // FIXME: Map ranges? 610 EmitCaret(OneLevelUp, Ranges, Hints, MacroDepth, OnMacroInst + 1); 611 612 // Map the location. 613 Loc = getImmediateMacroCalleeLoc(SM, Loc); 614 615 unsigned MacroSkipStart = 0, MacroSkipEnd = 0; 616 if (MacroDepth > DiagOpts.MacroBacktraceLimit) { 617 MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 + 618 DiagOpts.MacroBacktraceLimit % 2; 619 MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2; 620 } 621 622 // Whether to suppress printing this macro expansion. 623 bool Suppressed = (OnMacroInst >= MacroSkipStart && 624 OnMacroInst < MacroSkipEnd); 625 626 // Map the ranges. 627 for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), 628 E = Ranges.end(); 629 I != E; ++I) { 630 SourceLocation Start = I->getBegin(), End = I->getEnd(); 631 if (Start.isMacroID()) 632 I->setBegin(getImmediateMacroCalleeLoc(SM, Start)); 633 if (End.isMacroID()) 634 I->setEnd(getImmediateMacroCalleeLoc(SM, End)); 635 } 636 637 if (!Suppressed) { 638 // Don't print recursive expansion notes from an expansion note. 639 Loc = SM.getSpellingLoc(Loc); 640 641 // Get the pretty name, according to #line directives etc. 642 PresumedLoc PLoc = SM.getPresumedLoc(Loc); 643 if (PLoc.isInvalid()) 644 return; 645 646 // If this diagnostic is not in the main file, print out the 647 // "included from" lines. 648 emitIncludeStack(PLoc.getIncludeLoc(), DiagnosticsEngine::Note); 649 650 if (DiagOpts.ShowLocation) { 651 // Emit the file/line/column that this expansion came from. 652 OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; 653 if (DiagOpts.ShowColumn) 654 OS << PLoc.getColumn() << ':'; 655 OS << ' '; 656 } 657 OS << "note: expanded from:\n"; 658 659 EmitSnippetAndCaret(Loc, Ranges, ArrayRef<FixItHint>()); 660 return; 661 } 662 663 if (OnMacroInst == MacroSkipStart) { 664 // Tell the user that we've skipped contexts. 665 OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart) 666 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to see " 667 "all)\n"; 668 } 669 } 670 671 /// \brief Emit a code snippet and caret line. 672 /// 673 /// This routine emits a single line's code snippet and caret line.. 674 /// 675 /// \param Loc The location for the caret. 676 /// \param Ranges The underlined ranges for this code snippet. 677 /// \param Hints The FixIt hints active for this diagnostic. 678 void EmitSnippetAndCaret(SourceLocation Loc, 679 SmallVectorImpl<CharSourceRange>& Ranges, 680 ArrayRef<FixItHint> Hints) { 681 assert(!Loc.isInvalid() && "must have a valid source location here"); 682 assert(Loc.isFileID() && "must have a file location here"); 683 684 // Decompose the location into a FID/Offset pair. 685 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 686 FileID FID = LocInfo.first; 687 unsigned FileOffset = LocInfo.second; 688 689 // Get information about the buffer it points into. 690 bool Invalid = false; 691 const char *BufStart = SM.getBufferData(FID, &Invalid).data(); 692 if (Invalid) 693 return; 694 695 unsigned LineNo = SM.getLineNumber(FID, FileOffset); 696 unsigned ColNo = SM.getColumnNumber(FID, FileOffset); 697 unsigned CaretEndColNo 698 = ColNo + Lexer::MeasureTokenLength(Loc, SM, LangOpts); 699 700 // Rewind from the current position to the start of the line. 701 const char *TokPtr = BufStart+FileOffset; 702 const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. 703 704 705 // Compute the line end. Scan forward from the error position to the end of 706 // the line. 707 const char *LineEnd = TokPtr; 708 while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') 709 ++LineEnd; 710 711 // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past 712 // the source line length as currently being computed. See 713 // test/Misc/message-length.c. 714 CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); 715 716 // Copy the line of code into an std::string for ease of manipulation. 717 std::string SourceLine(LineStart, LineEnd); 718 719 // Create a line for the caret that is filled with spaces that is the same 720 // length as the line of source code. 721 std::string CaretLine(LineEnd-LineStart, ' '); 722 723 // Highlight all of the characters covered by Ranges with ~ characters. 724 for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), 725 E = Ranges.end(); 726 I != E; ++I) 727 HighlightRange(*I, LineNo, FID, SourceLine, CaretLine); 728 729 // Next, insert the caret itself. 730 if (ColNo-1 < CaretLine.size()) 731 CaretLine[ColNo-1] = '^'; 732 else 733 CaretLine.push_back('^'); 734 735 ExpandTabs(SourceLine, CaretLine); 736 737 // If we are in -fdiagnostics-print-source-range-info mode, we are trying 738 // to produce easily machine parsable output. Add a space before the 739 // source line and the caret to make it trivial to tell the main diagnostic 740 // line from what the user is intended to see. 741 if (DiagOpts.ShowSourceRanges) { 742 SourceLine = ' ' + SourceLine; 743 CaretLine = ' ' + CaretLine; 744 } 745 746 std::string FixItInsertionLine = BuildFixItInsertionLine(LineNo, 747 LineStart, LineEnd, 748 Hints); 749 750 // If the source line is too long for our terminal, select only the 751 // "interesting" source region within that line. 752 unsigned Columns = DiagOpts.MessageLength; 753 if (Columns && SourceLine.size() > Columns) 754 SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, 755 CaretEndColNo, Columns); 756 757 // Finally, remove any blank spaces from the end of CaretLine. 758 while (CaretLine[CaretLine.size()-1] == ' ') 759 CaretLine.erase(CaretLine.end()-1); 760 761 // Emit what we have computed. 762 OS << SourceLine << '\n'; 763 764 if (DiagOpts.ShowColors) 765 OS.changeColor(caretColor, true); 766 OS << CaretLine << '\n'; 767 if (DiagOpts.ShowColors) 768 OS.resetColor(); 769 770 if (!FixItInsertionLine.empty()) { 771 if (DiagOpts.ShowColors) 772 // Print fixit line in color 773 OS.changeColor(fixitColor, false); 774 if (DiagOpts.ShowSourceRanges) 775 OS << ' '; 776 OS << FixItInsertionLine << '\n'; 777 if (DiagOpts.ShowColors) 778 OS.resetColor(); 779 } 780 781 // Print out any parseable fixit information requested by the options. 782 EmitParseableFixits(Hints); 783 } 784 785private: 786 /// \brief Prints an include stack when appropriate for a particular 787 /// diagnostic level and location. 788 /// 789 /// This routine handles all the logic of suppressing particular include 790 /// stacks (such as those for notes) and duplicate include stacks when 791 /// repeated warnings occur within the same file. It also handles the logic 792 /// of customizing the formatting and display of the include stack. 793 /// 794 /// \param Level The diagnostic level of the message this stack pertains to. 795 /// \param Loc The include location of the current file (not the diagnostic 796 /// location). 797 void emitIncludeStack(SourceLocation Loc, DiagnosticsEngine::Level Level) { 798 // Skip redundant include stacks altogether. 799 if (LastIncludeLoc == Loc) 800 return; 801 LastIncludeLoc = Loc; 802 803 if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) 804 return; 805 806 emitIncludeStackRecursively(Loc); 807 } 808 809 /// \brief Helper to recursivly walk up the include stack and print each layer 810 /// on the way back down. 811 void emitIncludeStackRecursively(SourceLocation Loc) { 812 if (Loc.isInvalid()) 813 return; 814 815 PresumedLoc PLoc = SM.getPresumedLoc(Loc); 816 if (PLoc.isInvalid()) 817 return; 818 819 // Emit the other include frames first. 820 emitIncludeStackRecursively(PLoc.getIncludeLoc()); 821 822 if (DiagOpts.ShowLocation) 823 OS << "In file included from " << PLoc.getFilename() 824 << ':' << PLoc.getLine() << ":\n"; 825 else 826 OS << "In included file:\n"; 827 } 828 829 /// \brief Print out the file/line/column information and include trace. 830 /// 831 /// This method handlen the emission of the diagnostic location information. 832 /// This includes extracting as much location information as is present for 833 /// the diagnostic and printing it, as well as any include stack or source 834 /// ranges necessary. 835 void EmitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, 836 DiagnosticsEngine::Level Level, 837 ArrayRef<CharSourceRange> Ranges) { 838 if (PLoc.isInvalid()) { 839 // At least print the file name if available: 840 FileID FID = SM.getFileID(Loc); 841 if (!FID.isInvalid()) { 842 const FileEntry* FE = SM.getFileEntryForID(FID); 843 if (FE && FE->getName()) { 844 OS << FE->getName(); 845 if (FE->getDevice() == 0 && FE->getInode() == 0 846 && FE->getFileMode() == 0) { 847 // in PCH is a guess, but a good one: 848 OS << " (in PCH)"; 849 } 850 OS << ": "; 851 } 852 } 853 return; 854 } 855 unsigned LineNo = PLoc.getLine(); 856 857 if (!DiagOpts.ShowLocation) 858 return; 859 860 if (DiagOpts.ShowColors) 861 OS.changeColor(savedColor, true); 862 863 OS << PLoc.getFilename(); 864 switch (DiagOpts.Format) { 865 case DiagnosticOptions::Clang: OS << ':' << LineNo; break; 866 case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; 867 case DiagnosticOptions::Vi: OS << " +" << LineNo; break; 868 } 869 870 if (DiagOpts.ShowColumn) 871 // Compute the column number. 872 if (unsigned ColNo = PLoc.getColumn()) { 873 if (DiagOpts.Format == DiagnosticOptions::Msvc) { 874 OS << ','; 875 ColNo--; 876 } else 877 OS << ':'; 878 OS << ColNo; 879 } 880 switch (DiagOpts.Format) { 881 case DiagnosticOptions::Clang: 882 case DiagnosticOptions::Vi: OS << ':'; break; 883 case DiagnosticOptions::Msvc: OS << ") : "; break; 884 } 885 886 if (DiagOpts.ShowSourceRanges && !Ranges.empty()) { 887 FileID CaretFileID = 888 SM.getFileID(SM.getExpansionLoc(Loc)); 889 bool PrintedRange = false; 890 891 for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(), 892 RE = Ranges.end(); 893 RI != RE; ++RI) { 894 // Ignore invalid ranges. 895 if (!RI->isValid()) continue; 896 897 SourceLocation B = SM.getExpansionLoc(RI->getBegin()); 898 SourceLocation E = SM.getExpansionLoc(RI->getEnd()); 899 900 // If the End location and the start location are the same and are a 901 // macro location, then the range was something that came from a 902 // macro expansion or _Pragma. If this is an object-like macro, the 903 // best we can do is to highlight the range. If this is a 904 // function-like macro, we'd also like to highlight the arguments. 905 if (B == E && RI->getEnd().isMacroID()) 906 E = SM.getExpansionRange(RI->getEnd()).second; 907 908 std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); 909 std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); 910 911 // If the start or end of the range is in another file, just discard 912 // it. 913 if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) 914 continue; 915 916 // Add in the length of the token, so that we cover multi-char 917 // tokens. 918 unsigned TokSize = 0; 919 if (RI->isTokenRange()) 920 TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts); 921 922 OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' 923 << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' 924 << SM.getLineNumber(EInfo.first, EInfo.second) << ':' 925 << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) 926 << '}'; 927 PrintedRange = true; 928 } 929 930 if (PrintedRange) 931 OS << ':'; 932 } 933 OS << ' '; 934 } 935 936 /// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. 937 void HighlightRange(const CharSourceRange &R, 938 unsigned LineNo, FileID FID, 939 const std::string &SourceLine, 940 std::string &CaretLine) { 941 assert(CaretLine.size() == SourceLine.size() && 942 "Expect a correspondence between source and caret line!"); 943 if (!R.isValid()) return; 944 945 SourceLocation Begin = SM.getExpansionLoc(R.getBegin()); 946 SourceLocation End = SM.getExpansionLoc(R.getEnd()); 947 948 // If the End location and the start location are the same and are a macro 949 // location, then the range was something that came from a macro expansion 950 // or _Pragma. If this is an object-like macro, the best we can do is to 951 // highlight the range. If this is a function-like macro, we'd also like to 952 // highlight the arguments. 953 if (Begin == End && R.getEnd().isMacroID()) 954 End = SM.getExpansionRange(R.getEnd()).second; 955 956 unsigned StartLineNo = SM.getExpansionLineNumber(Begin); 957 if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) 958 return; // No intersection. 959 960 unsigned EndLineNo = SM.getExpansionLineNumber(End); 961 if (EndLineNo < LineNo || SM.getFileID(End) != FID) 962 return; // No intersection. 963 964 // Compute the column number of the start. 965 unsigned StartColNo = 0; 966 if (StartLineNo == LineNo) { 967 StartColNo = SM.getExpansionColumnNumber(Begin); 968 if (StartColNo) --StartColNo; // Zero base the col #. 969 } 970 971 // Compute the column number of the end. 972 unsigned EndColNo = CaretLine.size(); 973 if (EndLineNo == LineNo) { 974 EndColNo = SM.getExpansionColumnNumber(End); 975 if (EndColNo) { 976 --EndColNo; // Zero base the col #. 977 978 // Add in the length of the token, so that we cover multi-char tokens if 979 // this is a token range. 980 if (R.isTokenRange()) 981 EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts); 982 } else { 983 EndColNo = CaretLine.size(); 984 } 985 } 986 987 assert(StartColNo <= EndColNo && "Invalid range!"); 988 989 // Check that a token range does not highlight only whitespace. 990 if (R.isTokenRange()) { 991 // Pick the first non-whitespace column. 992 while (StartColNo < SourceLine.size() && 993 (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) 994 ++StartColNo; 995 996 // Pick the last non-whitespace column. 997 if (EndColNo > SourceLine.size()) 998 EndColNo = SourceLine.size(); 999 while (EndColNo-1 && 1000 (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) 1001 --EndColNo; 1002 1003 // If the start/end passed each other, then we are trying to highlight a 1004 // range that just exists in whitespace, which must be some sort of other 1005 // bug. 1006 assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); 1007 } 1008 1009 // Fill the range with ~'s. 1010 for (unsigned i = StartColNo; i < EndColNo; ++i) 1011 CaretLine[i] = '~'; 1012 } 1013 1014 std::string BuildFixItInsertionLine(unsigned LineNo, 1015 const char *LineStart, 1016 const char *LineEnd, 1017 ArrayRef<FixItHint> Hints) { 1018 std::string FixItInsertionLine; 1019 if (Hints.empty() || !DiagOpts.ShowFixits) 1020 return FixItInsertionLine; 1021 1022 for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); 1023 I != E; ++I) { 1024 if (!I->CodeToInsert.empty()) { 1025 // We have an insertion hint. Determine whether the inserted 1026 // code is on the same line as the caret. 1027 std::pair<FileID, unsigned> HintLocInfo 1028 = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); 1029 if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second)) { 1030 // Insert the new code into the line just below the code 1031 // that the user wrote. 1032 unsigned HintColNo 1033 = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second); 1034 unsigned LastColumnModified 1035 = HintColNo - 1 + I->CodeToInsert.size(); 1036 if (LastColumnModified > FixItInsertionLine.size()) 1037 FixItInsertionLine.resize(LastColumnModified, ' '); 1038 std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), 1039 FixItInsertionLine.begin() + HintColNo - 1); 1040 } else { 1041 FixItInsertionLine.clear(); 1042 break; 1043 } 1044 } 1045 } 1046 1047 if (FixItInsertionLine.empty()) 1048 return FixItInsertionLine; 1049 1050 // Now that we have the entire fixit line, expand the tabs in it. 1051 // Since we don't want to insert spaces in the middle of a word, 1052 // find each word and the column it should line up with and insert 1053 // spaces until they match. 1054 unsigned FixItPos = 0; 1055 unsigned LinePos = 0; 1056 unsigned TabExpandedCol = 0; 1057 unsigned LineLength = LineEnd - LineStart; 1058 1059 while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { 1060 // Find the next word in the FixIt line. 1061 while (FixItPos < FixItInsertionLine.size() && 1062 FixItInsertionLine[FixItPos] == ' ') 1063 ++FixItPos; 1064 unsigned CharDistance = FixItPos - TabExpandedCol; 1065 1066 // Walk forward in the source line, keeping track of 1067 // the tab-expanded column. 1068 for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) 1069 if (LinePos >= LineLength || LineStart[LinePos] != '\t') 1070 ++TabExpandedCol; 1071 else 1072 TabExpandedCol = 1073 (TabExpandedCol/DiagOpts.TabStop + 1) * DiagOpts.TabStop; 1074 1075 // Adjust the fixit line to match this column. 1076 FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); 1077 FixItPos = TabExpandedCol; 1078 1079 // Walk to the end of the word. 1080 while (FixItPos < FixItInsertionLine.size() && 1081 FixItInsertionLine[FixItPos] != ' ') 1082 ++FixItPos; 1083 } 1084 1085 return FixItInsertionLine; 1086 } 1087 1088 void ExpandTabs(std::string &SourceLine, std::string &CaretLine) { 1089 // Scan the source line, looking for tabs. If we find any, manually expand 1090 // them to spaces and update the CaretLine to match. 1091 for (unsigned i = 0; i != SourceLine.size(); ++i) { 1092 if (SourceLine[i] != '\t') continue; 1093 1094 // Replace this tab with at least one space. 1095 SourceLine[i] = ' '; 1096 1097 // Compute the number of spaces we need to insert. 1098 unsigned TabStop = DiagOpts.TabStop; 1099 assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && 1100 "Invalid -ftabstop value"); 1101 unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); 1102 assert(NumSpaces < TabStop && "Invalid computation of space amt"); 1103 1104 // Insert spaces into the SourceLine. 1105 SourceLine.insert(i+1, NumSpaces, ' '); 1106 1107 // Insert spaces or ~'s into CaretLine. 1108 CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); 1109 } 1110 } 1111 1112 void EmitParseableFixits(ArrayRef<FixItHint> Hints) { 1113 if (!DiagOpts.ShowParseableFixits) 1114 return; 1115 1116 // We follow FixItRewriter's example in not (yet) handling 1117 // fix-its in macros. 1118 for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); 1119 I != E; ++I) { 1120 if (I->RemoveRange.isInvalid() || 1121 I->RemoveRange.getBegin().isMacroID() || 1122 I->RemoveRange.getEnd().isMacroID()) 1123 return; 1124 } 1125 1126 for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); 1127 I != E; ++I) { 1128 SourceLocation BLoc = I->RemoveRange.getBegin(); 1129 SourceLocation ELoc = I->RemoveRange.getEnd(); 1130 1131 std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc); 1132 std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc); 1133 1134 // Adjust for token ranges. 1135 if (I->RemoveRange.isTokenRange()) 1136 EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts); 1137 1138 // We specifically do not do word-wrapping or tab-expansion here, 1139 // because this is supposed to be easy to parse. 1140 PresumedLoc PLoc = SM.getPresumedLoc(BLoc); 1141 if (PLoc.isInvalid()) 1142 break; 1143 1144 OS << "fix-it:\""; 1145 OS.write_escaped(PLoc.getFilename()); 1146 OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second) 1147 << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) 1148 << '-' << SM.getLineNumber(EInfo.first, EInfo.second) 1149 << ':' << SM.getColumnNumber(EInfo.first, EInfo.second) 1150 << "}:\""; 1151 OS.write_escaped(I->CodeToInsert); 1152 OS << "\"\n"; 1153 } 1154 } 1155}; 1156 1157} // end namespace 1158 1159/// \brief Print the diagnostic name to a raw_ostream. 1160/// 1161/// This prints the diagnostic name to a raw_ostream if it has one. It formats 1162/// the name according to the expected diagnostic message formatting: 1163/// " [diagnostic_name_here]" 1164static void printDiagnosticName(raw_ostream &OS, const Diagnostic &Info) { 1165 if (!DiagnosticIDs::isBuiltinNote(Info.getID())) 1166 OS << " [" << DiagnosticIDs::getName(Info.getID()) << "]"; 1167} 1168 1169/// \brief Print any diagnostic option information to a raw_ostream. 1170/// 1171/// This implements all of the logic for adding diagnostic options to a message 1172/// (via OS). Each relevant option is comma separated and all are enclosed in 1173/// the standard bracketing: " [...]". 1174static void printDiagnosticOptions(raw_ostream &OS, 1175 DiagnosticsEngine::Level Level, 1176 const Diagnostic &Info, 1177 const DiagnosticOptions &DiagOpts) { 1178 bool Started = false; 1179 if (DiagOpts.ShowOptionNames) { 1180 // Handle special cases for non-warnings early. 1181 if (Info.getID() == diag::fatal_too_many_errors) { 1182 OS << " [-ferror-limit=]"; 1183 return; 1184 } 1185 1186 // The code below is somewhat fragile because we are essentially trying to 1187 // report to the user what happened by inferring what the diagnostic engine 1188 // did. Eventually it might make more sense to have the diagnostic engine 1189 // include some "why" information in the diagnostic. 1190 1191 // If this is a warning which has been mapped to an error by the user (as 1192 // inferred by checking whether the default mapping is to an error) then 1193 // flag it as such. Note that diagnostics could also have been mapped by a 1194 // pragma, but we don't currently have a way to distinguish this. 1195 if (Level == DiagnosticsEngine::Error && 1196 DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) && 1197 !DiagnosticIDs::isDefaultMappingAsError(Info.getID())) { 1198 OS << " [-Werror"; 1199 Started = true; 1200 } 1201 1202 // If the diagnostic is an extension diagnostic and not enabled by default 1203 // then it must have been turned on with -pedantic. 1204 bool EnabledByDefault; 1205 if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(), 1206 EnabledByDefault) && 1207 !EnabledByDefault) { 1208 OS << (Started ? "," : " [") << "-pedantic"; 1209 Started = true; 1210 } 1211 1212 StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); 1213 if (!Opt.empty()) { 1214 OS << (Started ? "," : " [") << "-W" << Opt; 1215 Started = true; 1216 } 1217 } 1218 1219 // If the user wants to see category information, include it too. 1220 if (DiagOpts.ShowCategories) { 1221 unsigned DiagCategory = 1222 DiagnosticIDs::getCategoryNumberForDiag(Info.getID()); 1223 if (DiagCategory) { 1224 OS << (Started ? "," : " ["); 1225 Started = true; 1226 if (DiagOpts.ShowCategories == 1) 1227 OS << DiagCategory; 1228 else { 1229 assert(DiagOpts.ShowCategories == 2 && "Invalid ShowCategories value"); 1230 OS << DiagnosticIDs::getCategoryNameFromID(DiagCategory); 1231 } 1232 } 1233 } 1234 if (Started) 1235 OS << ']'; 1236} 1237 1238void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, 1239 const Diagnostic &Info) { 1240 // Default implementation (Warnings/errors count). 1241 DiagnosticConsumer::HandleDiagnostic(Level, Info); 1242 1243 // Render the diagnostic message into a temporary buffer eagerly. We'll use 1244 // this later as we print out the diagnostic to the terminal. 1245 llvm::SmallString<100> OutStr; 1246 Info.FormatDiagnostic(OutStr); 1247 1248 llvm::raw_svector_ostream DiagMessageStream(OutStr); 1249 if (DiagOpts->ShowNames) 1250 printDiagnosticName(DiagMessageStream, Info); 1251 printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts); 1252 1253 // Keeps track of the the starting position of the location 1254 // information (e.g., "foo.c:10:4:") that precedes the error 1255 // message. We use this information to determine how long the 1256 // file+line+column number prefix is. 1257 uint64_t StartOfLocationInfo = OS.tell(); 1258 1259 if (!Prefix.empty()) 1260 OS << Prefix << ": "; 1261 1262 // Use a dedicated, simpler path for diagnostics without a valid location. 1263 // This is important as if the location is missing, we may be emitting 1264 // diagnostics in a context that lacks language options, a source manager, or 1265 // other infrastructure necessary when emitting more rich diagnostics. 1266 if (!Info.getLocation().isValid()) { 1267 printDiagnosticLevel(OS, Level, DiagOpts->ShowColors); 1268 printDiagnosticMessage(OS, Level, DiagMessageStream.str(), 1269 OS.tell() - StartOfLocationInfo, 1270 DiagOpts->MessageLength, DiagOpts->ShowColors); 1271 OS.flush(); 1272 return; 1273 } 1274 1275 // Assert that the rest of our infrastructure is setup properly. 1276 assert(LangOpts && "Unexpected diagnostic outside source file processing"); 1277 assert(DiagOpts && "Unexpected diagnostic without options set"); 1278 assert(Info.hasSourceManager() && 1279 "Unexpected diagnostic with no source manager"); 1280 const SourceManager &SM = Info.getSourceManager(); 1281 TextDiagnostic TextDiag(OS, SM, *LangOpts, *DiagOpts, 1282 LastLoc, LastIncludeLoc); 1283 1284 TextDiag.Emit(Info.getLocation(), Level, DiagMessageStream.str(), 1285 Info.getRanges(), 1286 llvm::makeArrayRef(Info.getFixItHints(), 1287 Info.getNumFixItHints()), 1288 LastCaretDiagnosticWasNote); 1289 1290 // Cache the LastLoc from the TextDiagnostic printing. 1291 LastLoc = FullSourceLoc(TextDiag.getLastLoc(), SM); 1292 LastIncludeLoc = FullSourceLoc(TextDiag.getLastIncludeLoc(), SM); 1293 LastCaretDiagnosticWasNote = (Level == DiagnosticsEngine::Note); 1294 1295 OS.flush(); 1296} 1297 1298DiagnosticConsumer * 1299TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { 1300 return new TextDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); 1301} 1302