TextDiagnosticPrinter.cpp revision cb7b1e17b63967317ab5cc55682168cf0380519a
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/SourceManager.h" 16#include "clang/Frontend/DiagnosticOptions.h" 17#include "clang/Lex/Lexer.h" 18#include "llvm/Support/MemoryBuffer.h" 19#include "llvm/Support/raw_ostream.h" 20#include "llvm/ADT/SmallString.h" 21#include "llvm/ADT/StringExtras.h" 22#include <algorithm> 23using namespace clang; 24 25static const enum llvm::raw_ostream::Colors noteColor = 26 llvm::raw_ostream::BLACK; 27static const enum llvm::raw_ostream::Colors fixitColor = 28 llvm::raw_ostream::GREEN; 29static const enum llvm::raw_ostream::Colors caretColor = 30 llvm::raw_ostream::GREEN; 31static const enum llvm::raw_ostream::Colors warningColor = 32 llvm::raw_ostream::MAGENTA; 33static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED; 34static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED; 35// Used for changing only the bold attribute. 36static const enum llvm::raw_ostream::Colors savedColor = 37 llvm::raw_ostream::SAVEDCOLOR; 38 39/// \brief Number of spaces to indent when word-wrapping. 40const unsigned WordWrapIndentation = 6; 41 42TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, 43 const DiagnosticOptions &diags, 44 bool _OwnsOutputStream) 45 : OS(os), LangOpts(0), DiagOpts(&diags), 46 LastCaretDiagnosticWasNote(0), 47 OwnsOutputStream(_OwnsOutputStream) { 48} 49 50TextDiagnosticPrinter::~TextDiagnosticPrinter() { 51 if (OwnsOutputStream) 52 delete &OS; 53} 54 55void TextDiagnosticPrinter:: 56PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { 57 if (Loc.isInvalid()) return; 58 59 PresumedLoc PLoc = SM.getPresumedLoc(Loc); 60 if (PLoc.isInvalid()) 61 return; 62 63 // Print out the other include frames first. 64 PrintIncludeStack(PLoc.getIncludeLoc(), SM); 65 66 if (DiagOpts->ShowLocation) 67 OS << "In file included from " << PLoc.getFilename() 68 << ':' << PLoc.getLine() << ":\n"; 69 else 70 OS << "In included file:\n"; 71} 72 73/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s) 74/// any characters in LineNo that intersect the SourceRange. 75void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R, 76 const SourceManager &SM, 77 unsigned LineNo, FileID FID, 78 std::string &CaretLine, 79 const std::string &SourceLine) { 80 assert(CaretLine.size() == SourceLine.size() && 81 "Expect a correspondence between source and caret line!"); 82 if (!R.isValid()) return; 83 84 SourceLocation Begin = SM.getInstantiationLoc(R.getBegin()); 85 SourceLocation End = SM.getInstantiationLoc(R.getEnd()); 86 87 // If the End location and the start location are the same and are a macro 88 // location, then the range was something that came from a macro expansion 89 // or _Pragma. If this is an object-like macro, the best we can do is to 90 // highlight the range. If this is a function-like macro, we'd also like to 91 // highlight the arguments. 92 if (Begin == End && R.getEnd().isMacroID()) 93 End = SM.getInstantiationRange(R.getEnd()).second; 94 95 unsigned StartLineNo = SM.getInstantiationLineNumber(Begin); 96 if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) 97 return; // No intersection. 98 99 unsigned EndLineNo = SM.getInstantiationLineNumber(End); 100 if (EndLineNo < LineNo || SM.getFileID(End) != FID) 101 return; // No intersection. 102 103 // Compute the column number of the start. 104 unsigned StartColNo = 0; 105 if (StartLineNo == LineNo) { 106 StartColNo = SM.getInstantiationColumnNumber(Begin); 107 if (StartColNo) --StartColNo; // Zero base the col #. 108 } 109 110 // Compute the column number of the end. 111 unsigned EndColNo = CaretLine.size(); 112 if (EndLineNo == LineNo) { 113 EndColNo = SM.getInstantiationColumnNumber(End); 114 if (EndColNo) { 115 --EndColNo; // Zero base the col #. 116 117 // Add in the length of the token, so that we cover multi-char tokens if 118 // this is a token range. 119 if (R.isTokenRange()) 120 EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts); 121 } else { 122 EndColNo = CaretLine.size(); 123 } 124 } 125 126 assert(StartColNo <= EndColNo && "Invalid range!"); 127 128 // Check that a token range does not highlight only whitespace. 129 if (R.isTokenRange()) { 130 // Pick the first non-whitespace column. 131 while (StartColNo < SourceLine.size() && 132 (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) 133 ++StartColNo; 134 135 // Pick the last non-whitespace column. 136 if (EndColNo > SourceLine.size()) 137 EndColNo = SourceLine.size(); 138 while (EndColNo-1 && 139 (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) 140 --EndColNo; 141 142 // If the start/end passed each other, then we are trying to highlight a range 143 // that just exists in whitespace, which must be some sort of other bug. 144 assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); 145 } 146 147 // Fill the range with ~'s. 148 for (unsigned i = StartColNo; i < EndColNo; ++i) 149 CaretLine[i] = '~'; 150} 151 152/// \brief When the source code line we want to print is too long for 153/// the terminal, select the "interesting" region. 154static void SelectInterestingSourceRegion(std::string &SourceLine, 155 std::string &CaretLine, 156 std::string &FixItInsertionLine, 157 unsigned EndOfCaretToken, 158 unsigned Columns) { 159 unsigned MaxSize = std::max(SourceLine.size(), 160 std::max(CaretLine.size(), 161 FixItInsertionLine.size())); 162 if (MaxSize > SourceLine.size()) 163 SourceLine.resize(MaxSize, ' '); 164 if (MaxSize > CaretLine.size()) 165 CaretLine.resize(MaxSize, ' '); 166 if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size()) 167 FixItInsertionLine.resize(MaxSize, ' '); 168 169 // Find the slice that we need to display the full caret line 170 // correctly. 171 unsigned CaretStart = 0, CaretEnd = CaretLine.size(); 172 for (; CaretStart != CaretEnd; ++CaretStart) 173 if (!isspace(CaretLine[CaretStart])) 174 break; 175 176 for (; CaretEnd != CaretStart; --CaretEnd) 177 if (!isspace(CaretLine[CaretEnd - 1])) 178 break; 179 180 // Make sure we don't chop the string shorter than the caret token 181 // itself. 182 if (CaretEnd < EndOfCaretToken) 183 CaretEnd = EndOfCaretToken; 184 185 // If we have a fix-it line, make sure the slice includes all of the 186 // fix-it information. 187 if (!FixItInsertionLine.empty()) { 188 unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size(); 189 for (; FixItStart != FixItEnd; ++FixItStart) 190 if (!isspace(FixItInsertionLine[FixItStart])) 191 break; 192 193 for (; FixItEnd != FixItStart; --FixItEnd) 194 if (!isspace(FixItInsertionLine[FixItEnd - 1])) 195 break; 196 197 if (FixItStart < CaretStart) 198 CaretStart = FixItStart; 199 if (FixItEnd > CaretEnd) 200 CaretEnd = FixItEnd; 201 } 202 203 // CaretLine[CaretStart, CaretEnd) contains all of the interesting 204 // parts of the caret line. While this slice is smaller than the 205 // number of columns we have, try to grow the slice to encompass 206 // more context. 207 208 // If the end of the interesting region comes before we run out of 209 // space in the terminal, start at the beginning of the line. 210 if (Columns > 3 && CaretEnd < Columns - 3) 211 CaretStart = 0; 212 213 unsigned TargetColumns = Columns; 214 if (TargetColumns > 8) 215 TargetColumns -= 8; // Give us extra room for the ellipses. 216 unsigned SourceLength = SourceLine.size(); 217 while ((CaretEnd - CaretStart) < TargetColumns) { 218 bool ExpandedRegion = false; 219 // Move the start of the interesting region left until we've 220 // pulled in something else interesting. 221 if (CaretStart == 1) 222 CaretStart = 0; 223 else if (CaretStart > 1) { 224 unsigned NewStart = CaretStart - 1; 225 226 // Skip over any whitespace we see here; we're looking for 227 // another bit of interesting text. 228 while (NewStart && isspace(SourceLine[NewStart])) 229 --NewStart; 230 231 // Skip over this bit of "interesting" text. 232 while (NewStart && !isspace(SourceLine[NewStart])) 233 --NewStart; 234 235 // Move up to the non-whitespace character we just saw. 236 if (NewStart) 237 ++NewStart; 238 239 // If we're still within our limit, update the starting 240 // position within the source/caret line. 241 if (CaretEnd - NewStart <= TargetColumns) { 242 CaretStart = NewStart; 243 ExpandedRegion = true; 244 } 245 } 246 247 // Move the end of the interesting region right until we've 248 // pulled in something else interesting. 249 if (CaretEnd != SourceLength) { 250 assert(CaretEnd < SourceLength && "Unexpected caret position!"); 251 unsigned NewEnd = CaretEnd; 252 253 // Skip over any whitespace we see here; we're looking for 254 // another bit of interesting text. 255 while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1])) 256 ++NewEnd; 257 258 // Skip over this bit of "interesting" text. 259 while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1])) 260 ++NewEnd; 261 262 if (NewEnd - CaretStart <= TargetColumns) { 263 CaretEnd = NewEnd; 264 ExpandedRegion = true; 265 } 266 } 267 268 if (!ExpandedRegion) 269 break; 270 } 271 272 // [CaretStart, CaretEnd) is the slice we want. Update the various 273 // output lines to show only this slice, with two-space padding 274 // before the lines so that it looks nicer. 275 if (CaretEnd < SourceLine.size()) 276 SourceLine.replace(CaretEnd, std::string::npos, "..."); 277 if (CaretEnd < CaretLine.size()) 278 CaretLine.erase(CaretEnd, std::string::npos); 279 if (FixItInsertionLine.size() > CaretEnd) 280 FixItInsertionLine.erase(CaretEnd, std::string::npos); 281 282 if (CaretStart > 2) { 283 SourceLine.replace(0, CaretStart, " ..."); 284 CaretLine.replace(0, CaretStart, " "); 285 if (FixItInsertionLine.size() >= CaretStart) 286 FixItInsertionLine.replace(0, CaretStart, " "); 287 } 288} 289 290void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, 291 CharSourceRange *Ranges, 292 unsigned NumRanges, 293 const SourceManager &SM, 294 const FixItHint *Hints, 295 unsigned NumHints, 296 unsigned Columns, 297 unsigned OnMacroInst, 298 unsigned MacroSkipStart, 299 unsigned MacroSkipEnd) { 300 assert(LangOpts && "Unexpected diagnostic outside source file processing"); 301 assert(!Loc.isInvalid() && "must have a valid source location here"); 302 303 // If this is a macro ID, first emit information about where this was 304 // instantiated (recursively) then emit information about where the token was 305 // spelled from. 306 if (!Loc.isFileID()) { 307 // Whether to suppress printing this macro instantiation. 308 bool Suppressed 309 = OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd; 310 311 312 SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first; 313 // FIXME: Map ranges? 314 EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns, 315 OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); 316 317 // Map the location. 318 Loc = SM.getImmediateSpellingLoc(Loc); 319 320 // Map the ranges. 321 for (unsigned i = 0; i != NumRanges; ++i) { 322 CharSourceRange &R = Ranges[i]; 323 SourceLocation S = R.getBegin(), E = R.getEnd(); 324 if (S.isMacroID()) 325 R.setBegin(SM.getImmediateSpellingLoc(S)); 326 if (E.isMacroID()) 327 R.setEnd(SM.getImmediateSpellingLoc(E)); 328 } 329 330 if (!Suppressed) { 331 // Get the pretty name, according to #line directives etc. 332 PresumedLoc PLoc = SM.getPresumedLoc(Loc); 333 if (PLoc.isInvalid()) 334 return; 335 336 // If this diagnostic is not in the main file, print out the 337 // "included from" lines. 338 if (LastWarningLoc != PLoc.getIncludeLoc()) { 339 LastWarningLoc = PLoc.getIncludeLoc(); 340 PrintIncludeStack(LastWarningLoc, SM); 341 } 342 343 if (DiagOpts->ShowLocation) { 344 // Emit the file/line/column that this expansion came from. 345 OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; 346 if (DiagOpts->ShowColumn) 347 OS << PLoc.getColumn() << ':'; 348 OS << ' '; 349 } 350 OS << "note: instantiated from:\n"; 351 352 EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns, 353 OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); 354 return; 355 } 356 357 if (OnMacroInst == MacroSkipStart) { 358 // Tell the user that we've skipped contexts. 359 OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart) 360 << " contexts in backtrace; use -fmacro-backtrace-limit=0 to see " 361 "all)\n"; 362 } 363 364 return; 365 } 366 367 // Decompose the location into a FID/Offset pair. 368 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 369 FileID FID = LocInfo.first; 370 unsigned FileOffset = LocInfo.second; 371 372 // Get information about the buffer it points into. 373 bool Invalid = false; 374 const char *BufStart = SM.getBufferData(FID, &Invalid).data(); 375 if (Invalid) 376 return; 377 378 unsigned ColNo = SM.getColumnNumber(FID, FileOffset); 379 unsigned CaretEndColNo 380 = ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts); 381 382 // Rewind from the current position to the start of the line. 383 const char *TokPtr = BufStart+FileOffset; 384 const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. 385 386 387 // Compute the line end. Scan forward from the error position to the end of 388 // the line. 389 const char *LineEnd = TokPtr; 390 while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') 391 ++LineEnd; 392 393 // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past 394 // the source line length as currently being computed. See 395 // test/Misc/message-length.c. 396 CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); 397 398 // Copy the line of code into an std::string for ease of manipulation. 399 std::string SourceLine(LineStart, LineEnd); 400 401 // Create a line for the caret that is filled with spaces that is the same 402 // length as the line of source code. 403 std::string CaretLine(LineEnd-LineStart, ' '); 404 405 // Highlight all of the characters covered by Ranges with ~ characters. 406 if (NumRanges) { 407 unsigned LineNo = SM.getLineNumber(FID, FileOffset); 408 409 for (unsigned i = 0, e = NumRanges; i != e; ++i) 410 HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine); 411 } 412 413 // Next, insert the caret itself. 414 if (ColNo-1 < CaretLine.size()) 415 CaretLine[ColNo-1] = '^'; 416 else 417 CaretLine.push_back('^'); 418 419 // Scan the source line, looking for tabs. If we find any, manually expand 420 // them to spaces and update the CaretLine to match. 421 for (unsigned i = 0; i != SourceLine.size(); ++i) { 422 if (SourceLine[i] != '\t') continue; 423 424 // Replace this tab with at least one space. 425 SourceLine[i] = ' '; 426 427 // Compute the number of spaces we need to insert. 428 unsigned TabStop = DiagOpts->TabStop; 429 assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && 430 "Invalid -ftabstop value"); 431 unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); 432 assert(NumSpaces < TabStop && "Invalid computation of space amt"); 433 434 // Insert spaces into the SourceLine. 435 SourceLine.insert(i+1, NumSpaces, ' '); 436 437 // Insert spaces or ~'s into CaretLine. 438 CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); 439 } 440 441 // If we are in -fdiagnostics-print-source-range-info mode, we are trying to 442 // produce easily machine parsable output. Add a space before the source line 443 // and the caret to make it trivial to tell the main diagnostic line from what 444 // the user is intended to see. 445 if (DiagOpts->ShowSourceRanges) { 446 SourceLine = ' ' + SourceLine; 447 CaretLine = ' ' + CaretLine; 448 } 449 450 std::string FixItInsertionLine; 451 if (NumHints && DiagOpts->ShowFixits) { 452 for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints; 453 Hint != LastHint; ++Hint) { 454 if (!Hint->CodeToInsert.empty()) { 455 // We have an insertion hint. Determine whether the inserted 456 // code is on the same line as the caret. 457 std::pair<FileID, unsigned> HintLocInfo 458 = SM.getDecomposedInstantiationLoc(Hint->RemoveRange.getBegin()); 459 if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) == 460 SM.getLineNumber(FID, FileOffset)) { 461 // Insert the new code into the line just below the code 462 // that the user wrote. 463 unsigned HintColNo 464 = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second); 465 unsigned LastColumnModified 466 = HintColNo - 1 + Hint->CodeToInsert.size(); 467 if (LastColumnModified > FixItInsertionLine.size()) 468 FixItInsertionLine.resize(LastColumnModified, ' '); 469 std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(), 470 FixItInsertionLine.begin() + HintColNo - 1); 471 } else { 472 FixItInsertionLine.clear(); 473 break; 474 } 475 } 476 } 477 // Now that we have the entire fixit line, expand the tabs in it. 478 // Since we don't want to insert spaces in the middle of a word, 479 // find each word and the column it should line up with and insert 480 // spaces until they match. 481 if (!FixItInsertionLine.empty()) { 482 unsigned FixItPos = 0; 483 unsigned LinePos = 0; 484 unsigned TabExpandedCol = 0; 485 unsigned LineLength = LineEnd - LineStart; 486 487 while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { 488 // Find the next word in the FixIt line. 489 while (FixItPos < FixItInsertionLine.size() && 490 FixItInsertionLine[FixItPos] == ' ') 491 ++FixItPos; 492 unsigned CharDistance = FixItPos - TabExpandedCol; 493 494 // Walk forward in the source line, keeping track of 495 // the tab-expanded column. 496 for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) 497 if (LinePos >= LineLength || LineStart[LinePos] != '\t') 498 ++TabExpandedCol; 499 else 500 TabExpandedCol = 501 (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop; 502 503 // Adjust the fixit line to match this column. 504 FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); 505 FixItPos = TabExpandedCol; 506 507 // Walk to the end of the word. 508 while (FixItPos < FixItInsertionLine.size() && 509 FixItInsertionLine[FixItPos] != ' ') 510 ++FixItPos; 511 } 512 } 513 } 514 515 // If the source line is too long for our terminal, select only the 516 // "interesting" source region within that line. 517 if (Columns && SourceLine.size() > Columns) 518 SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, 519 CaretEndColNo, Columns); 520 521 // Finally, remove any blank spaces from the end of CaretLine. 522 while (CaretLine[CaretLine.size()-1] == ' ') 523 CaretLine.erase(CaretLine.end()-1); 524 525 // Emit what we have computed. 526 OS << SourceLine << '\n'; 527 528 if (DiagOpts->ShowColors) 529 OS.changeColor(caretColor, true); 530 OS << CaretLine << '\n'; 531 if (DiagOpts->ShowColors) 532 OS.resetColor(); 533 534 if (!FixItInsertionLine.empty()) { 535 if (DiagOpts->ShowColors) 536 // Print fixit line in color 537 OS.changeColor(fixitColor, false); 538 if (DiagOpts->ShowSourceRanges) 539 OS << ' '; 540 OS << FixItInsertionLine << '\n'; 541 if (DiagOpts->ShowColors) 542 OS.resetColor(); 543 } 544 545 if (DiagOpts->ShowParseableFixits) { 546 547 // We follow FixItRewriter's example in not (yet) handling 548 // fix-its in macros. 549 bool BadApples = false; 550 for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) { 551 if (Hint->RemoveRange.isInvalid() || 552 Hint->RemoveRange.getBegin().isMacroID() || 553 Hint->RemoveRange.getEnd().isMacroID()) { 554 BadApples = true; 555 break; 556 } 557 } 558 559 if (!BadApples) { 560 for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) { 561 562 SourceLocation B = Hint->RemoveRange.getBegin(); 563 SourceLocation E = Hint->RemoveRange.getEnd(); 564 565 std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); 566 std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); 567 568 // Adjust for token ranges. 569 if (Hint->RemoveRange.isTokenRange()) 570 EInfo.second += Lexer::MeasureTokenLength(E, SM, *LangOpts); 571 572 // We specifically do not do word-wrapping or tab-expansion here, 573 // because this is supposed to be easy to parse. 574 PresumedLoc PLoc = SM.getPresumedLoc(B); 575 if (PLoc.isInvalid()) 576 break; 577 578 OS << "fix-it:\""; 579 OS.write_escaped(SM.getPresumedLoc(B).getFilename()); 580 OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second) 581 << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) 582 << '-' << SM.getLineNumber(EInfo.first, EInfo.second) 583 << ':' << SM.getColumnNumber(EInfo.first, EInfo.second) 584 << "}:\""; 585 OS.write_escaped(Hint->CodeToInsert); 586 OS << "\"\n"; 587 } 588 } 589 } 590} 591 592/// \brief Skip over whitespace in the string, starting at the given 593/// index. 594/// 595/// \returns The index of the first non-whitespace character that is 596/// greater than or equal to Idx or, if no such character exists, 597/// returns the end of the string. 598static unsigned skipWhitespace(unsigned Idx, 599 const llvm::SmallVectorImpl<char> &Str, 600 unsigned Length) { 601 while (Idx < Length && isspace(Str[Idx])) 602 ++Idx; 603 return Idx; 604} 605 606/// \brief If the given character is the start of some kind of 607/// balanced punctuation (e.g., quotes or parentheses), return the 608/// character that will terminate the punctuation. 609/// 610/// \returns The ending punctuation character, if any, or the NULL 611/// character if the input character does not start any punctuation. 612static inline char findMatchingPunctuation(char c) { 613 switch (c) { 614 case '\'': return '\''; 615 case '`': return '\''; 616 case '"': return '"'; 617 case '(': return ')'; 618 case '[': return ']'; 619 case '{': return '}'; 620 default: break; 621 } 622 623 return 0; 624} 625 626/// \brief Find the end of the word starting at the given offset 627/// within a string. 628/// 629/// \returns the index pointing one character past the end of the 630/// word. 631static unsigned findEndOfWord(unsigned Start, 632 const llvm::SmallVectorImpl<char> &Str, 633 unsigned Length, unsigned Column, 634 unsigned Columns) { 635 assert(Start < Str.size() && "Invalid start position!"); 636 unsigned End = Start + 1; 637 638 // If we are already at the end of the string, take that as the word. 639 if (End == Str.size()) 640 return End; 641 642 // Determine if the start of the string is actually opening 643 // punctuation, e.g., a quote or parentheses. 644 char EndPunct = findMatchingPunctuation(Str[Start]); 645 if (!EndPunct) { 646 // This is a normal word. Just find the first space character. 647 while (End < Length && !isspace(Str[End])) 648 ++End; 649 return End; 650 } 651 652 // We have the start of a balanced punctuation sequence (quotes, 653 // parentheses, etc.). Determine the full sequence is. 654 llvm::SmallString<16> PunctuationEndStack; 655 PunctuationEndStack.push_back(EndPunct); 656 while (End < Length && !PunctuationEndStack.empty()) { 657 if (Str[End] == PunctuationEndStack.back()) 658 PunctuationEndStack.pop_back(); 659 else if (char SubEndPunct = findMatchingPunctuation(Str[End])) 660 PunctuationEndStack.push_back(SubEndPunct); 661 662 ++End; 663 } 664 665 // Find the first space character after the punctuation ended. 666 while (End < Length && !isspace(Str[End])) 667 ++End; 668 669 unsigned PunctWordLength = End - Start; 670 if (// If the word fits on this line 671 Column + PunctWordLength <= Columns || 672 // ... or the word is "short enough" to take up the next line 673 // without too much ugly white space 674 PunctWordLength < Columns/3) 675 return End; // Take the whole thing as a single "word". 676 677 // The whole quoted/parenthesized string is too long to print as a 678 // single "word". Instead, find the "word" that starts just after 679 // the punctuation and use that end-point instead. This will recurse 680 // until it finds something small enough to consider a word. 681 return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns); 682} 683 684/// \brief Print the given string to a stream, word-wrapping it to 685/// some number of columns in the process. 686/// 687/// \brief OS the stream to which the word-wrapping string will be 688/// emitted. 689/// 690/// \brief Str the string to word-wrap and output. 691/// 692/// \brief Columns the number of columns to word-wrap to. 693/// 694/// \brief Column the column number at which the first character of \p 695/// Str will be printed. This will be non-zero when part of the first 696/// line has already been printed. 697/// 698/// \brief Indentation the number of spaces to indent any lines beyond 699/// the first line. 700/// 701/// \returns true if word-wrapping was required, or false if the 702/// string fit on the first line. 703static bool PrintWordWrapped(llvm::raw_ostream &OS, 704 const llvm::SmallVectorImpl<char> &Str, 705 unsigned Columns, 706 unsigned Column = 0, 707 unsigned Indentation = WordWrapIndentation) { 708 unsigned Length = Str.size(); 709 710 // If there is a newline in this message somewhere, find that 711 // newline and split the message into the part before the newline 712 // (which will be word-wrapped) and the part from the newline one 713 // (which will be emitted unchanged). 714 for (unsigned I = 0; I != Length; ++I) 715 if (Str[I] == '\n') { 716 Length = I; 717 break; 718 } 719 720 // The string used to indent each line. 721 llvm::SmallString<16> IndentStr; 722 IndentStr.assign(Indentation, ' '); 723 bool Wrapped = false; 724 for (unsigned WordStart = 0, WordEnd; WordStart < Length; 725 WordStart = WordEnd) { 726 // Find the beginning of the next word. 727 WordStart = skipWhitespace(WordStart, Str, Length); 728 if (WordStart == Length) 729 break; 730 731 // Find the end of this word. 732 WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns); 733 734 // Does this word fit on the current line? 735 unsigned WordLength = WordEnd - WordStart; 736 if (Column + WordLength < Columns) { 737 // This word fits on the current line; print it there. 738 if (WordStart) { 739 OS << ' '; 740 Column += 1; 741 } 742 OS.write(&Str[WordStart], WordLength); 743 Column += WordLength; 744 continue; 745 } 746 747 // This word does not fit on the current line, so wrap to the next 748 // line. 749 OS << '\n'; 750 OS.write(&IndentStr[0], Indentation); 751 OS.write(&Str[WordStart], WordLength); 752 Column = Indentation + WordLength; 753 Wrapped = true; 754 } 755 756 if (Length == Str.size()) 757 return Wrapped; // We're done. 758 759 // There is a newline in the message, followed by something that 760 // will not be word-wrapped. Print that. 761 OS.write(&Str[Length], Str.size() - Length); 762 return true; 763} 764 765void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, 766 const DiagnosticInfo &Info) { 767 // Keeps track of the the starting position of the location 768 // information (e.g., "foo.c:10:4:") that precedes the error 769 // message. We use this information to determine how long the 770 // file+line+column number prefix is. 771 uint64_t StartOfLocationInfo = OS.tell(); 772 773 if (!Prefix.empty()) 774 OS << Prefix << ": "; 775 776 // If the location is specified, print out a file/line/col and include trace 777 // if enabled. 778 if (Info.getLocation().isValid()) { 779 const SourceManager &SM = Info.getLocation().getManager(); 780 PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); 781 if (PLoc.isInvalid()) 782 return; 783 784 unsigned LineNo = PLoc.getLine(); 785 786 // First, if this diagnostic is not in the main file, print out the 787 // "included from" lines. 788 if (LastWarningLoc != PLoc.getIncludeLoc()) { 789 LastWarningLoc = PLoc.getIncludeLoc(); 790 PrintIncludeStack(LastWarningLoc, SM); 791 StartOfLocationInfo = OS.tell(); 792 } 793 794 // Compute the column number. 795 if (DiagOpts->ShowLocation && PLoc.isValid()) { 796 if (DiagOpts->ShowColors) 797 OS.changeColor(savedColor, true); 798 799 // Emit a Visual Studio compatible line number syntax. 800 if (LangOpts && LangOpts->Microsoft) { 801 OS << PLoc.getFilename() << '(' << LineNo << ')'; 802 OS << " : "; 803 } else { 804 OS << PLoc.getFilename() << ':' << LineNo << ':'; 805 if (DiagOpts->ShowColumn) 806 if (unsigned ColNo = PLoc.getColumn()) 807 OS << ColNo << ':'; 808 } 809 if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { 810 FileID CaretFileID = 811 SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); 812 bool PrintedRange = false; 813 814 for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { 815 // Ignore invalid ranges. 816 if (!Info.getRange(i).isValid()) continue; 817 818 SourceLocation B = Info.getRange(i).getBegin(); 819 SourceLocation E = Info.getRange(i).getEnd(); 820 B = SM.getInstantiationLoc(B); 821 E = SM.getInstantiationLoc(E); 822 823 // If the End location and the start location are the same and are a 824 // macro location, then the range was something that came from a macro 825 // expansion or _Pragma. If this is an object-like macro, the best we 826 // can do is to highlight the range. If this is a function-like 827 // macro, we'd also like to highlight the arguments. 828 if (B == E && Info.getRange(i).getEnd().isMacroID()) 829 E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; 830 831 std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); 832 std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); 833 834 // If the start or end of the range is in another file, just discard 835 // it. 836 if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) 837 continue; 838 839 // Add in the length of the token, so that we cover multi-char tokens. 840 unsigned TokSize = 0; 841 if (Info.getRange(i).isTokenRange()) 842 TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); 843 844 OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' 845 << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' 846 << SM.getLineNumber(EInfo.first, EInfo.second) << ':' 847 << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}'; 848 PrintedRange = true; 849 } 850 851 if (PrintedRange) 852 OS << ':'; 853 } 854 OS << ' '; 855 if (DiagOpts->ShowColors) 856 OS.resetColor(); 857 } 858 } 859 860 if (DiagOpts->ShowColors) { 861 // Print diagnostic category in bold and color 862 switch (Level) { 863 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); 864 case Diagnostic::Note: OS.changeColor(noteColor, true); break; 865 case Diagnostic::Warning: OS.changeColor(warningColor, true); break; 866 case Diagnostic::Error: OS.changeColor(errorColor, true); break; 867 case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break; 868 } 869 } 870 871 switch (Level) { 872 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); 873 case Diagnostic::Note: OS << "note: "; break; 874 case Diagnostic::Warning: OS << "warning: "; break; 875 case Diagnostic::Error: OS << "error: "; break; 876 case Diagnostic::Fatal: OS << "fatal error: "; break; 877 } 878 879 if (DiagOpts->ShowColors) 880 OS.resetColor(); 881 882 llvm::SmallString<100> OutStr; 883 Info.FormatDiagnostic(OutStr); 884 885 std::string OptionName; 886 if (DiagOpts->ShowOptionNames) { 887 if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) { 888 OptionName = "-W"; 889 OptionName += Opt; 890 } else if (Info.getID() == diag::fatal_too_many_errors) { 891 OptionName = "-ferror-limit="; 892 } else { 893 // If the diagnostic is an extension diagnostic and not enabled by default 894 // then it must have been turned on with -pedantic. 895 bool EnabledByDefault; 896 if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) && 897 !EnabledByDefault) 898 OptionName = "-pedantic"; 899 } 900 } 901 902 // If the user wants to see category information, include it too. 903 unsigned DiagCategory = 0; 904 if (DiagOpts->ShowCategories) 905 DiagCategory = Diagnostic::getCategoryNumberForDiag(Info.getID()); 906 907 // If there is any categorization information, include it. 908 if (!OptionName.empty() || DiagCategory != 0) { 909 bool NeedsComma = false; 910 OutStr += " ["; 911 912 if (!OptionName.empty()) { 913 OutStr += OptionName; 914 NeedsComma = true; 915 } 916 917 if (DiagCategory) { 918 if (NeedsComma) OutStr += ','; 919 if (DiagOpts->ShowCategories == 1) 920 OutStr += llvm::utostr(DiagCategory); 921 else { 922 assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value"); 923 OutStr += Diagnostic::getCategoryNameFromID(DiagCategory); 924 } 925 } 926 927 OutStr += "]"; 928 } 929 930 931 if (DiagOpts->ShowColors) { 932 // Print warnings, errors and fatal errors in bold, no color 933 switch (Level) { 934 case Diagnostic::Warning: OS.changeColor(savedColor, true); break; 935 case Diagnostic::Error: OS.changeColor(savedColor, true); break; 936 case Diagnostic::Fatal: OS.changeColor(savedColor, true); break; 937 default: break; //don't bold notes 938 } 939 } 940 941 if (DiagOpts->MessageLength) { 942 // We will be word-wrapping the error message, so compute the 943 // column number where we currently are (after printing the 944 // location information). 945 unsigned Column = OS.tell() - StartOfLocationInfo; 946 PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column); 947 } else { 948 OS.write(OutStr.begin(), OutStr.size()); 949 } 950 OS << '\n'; 951 if (DiagOpts->ShowColors) 952 OS.resetColor(); 953 954 // If caret diagnostics are enabled and we have location, we want to 955 // emit the caret. However, we only do this if the location moved 956 // from the last diagnostic, if the last diagnostic was a note that 957 // was part of a different warning or error diagnostic, or if the 958 // diagnostic has ranges. We don't want to emit the same caret 959 // multiple times if one loc has multiple diagnostics. 960 if (DiagOpts->ShowCarets && Info.getLocation().isValid() && 961 ((LastLoc != Info.getLocation()) || Info.getNumRanges() || 962 (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || 963 Info.getNumFixItHints())) { 964 // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. 965 LastLoc = Info.getLocation(); 966 LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); 967 968 // Get the ranges into a local array we can hack on. 969 CharSourceRange Ranges[20]; 970 unsigned NumRanges = Info.getNumRanges(); 971 assert(NumRanges < 20 && "Out of space"); 972 for (unsigned i = 0; i != NumRanges; ++i) 973 Ranges[i] = Info.getRange(i); 974 975 unsigned NumHints = Info.getNumFixItHints(); 976 for (unsigned i = 0; i != NumHints; ++i) { 977 const FixItHint &Hint = Info.getFixItHint(i); 978 if (Hint.RemoveRange.isValid()) { 979 assert(NumRanges < 20 && "Out of space"); 980 Ranges[NumRanges++] = Hint.RemoveRange; 981 } 982 } 983 984 unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0; 985 if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) { 986 // Compute the length of the macro-instantiation backtrace, so that we 987 // can establish which steps in the macro backtrace we'll skip. 988 SourceLocation Loc = LastLoc; 989 unsigned Depth = 0; 990 do { 991 ++Depth; 992 Loc = LastLoc.getManager().getImmediateInstantiationRange(Loc).first; 993 } while (!Loc.isFileID()); 994 995 if (Depth > DiagOpts->MacroBacktraceLimit) { 996 MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 + 997 DiagOpts->MacroBacktraceLimit % 2; 998 MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2; 999 } 1000 } 1001 1002 EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), 1003 Info.getFixItHints(), 1004 Info.getNumFixItHints(), 1005 DiagOpts->MessageLength, 1006 0, MacroInstSkipStart, MacroInstSkipEnd); 1007 } 1008 1009 OS.flush(); 1010} 1011