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