1 //===- DiagnosticRenderer.cpp - Diagnostic Pretty-Printing ----------------===// 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 #include "clang/Frontend/DiagnosticRenderer.h" 11 #include "clang/Basic/Diagnostic.h" 12 #include "clang/Basic/DiagnosticOptions.h" 13 #include "clang/Basic/LLVM.h" 14 #include "clang/Basic/SourceLocation.h" 15 #include "clang/Basic/SourceManager.h" 16 #include "clang/Edit/Commit.h" 17 #include "clang/Edit/EditedSource.h" 18 #include "clang/Edit/EditsReceiver.h" 19 #include "clang/Lex/Lexer.h" 20 #include "llvm/ADT/ArrayRef.h" 21 #include "llvm/ADT/DenseMap.h" 22 #include "llvm/ADT/None.h" 23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/ADT/SmallVector.h" 25 #include "llvm/ADT/StringRef.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include <algorithm> 28 #include <cassert> 29 #include <iterator> 30 #include <utility> 31 32 using namespace clang; 33 34 DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts, 35 DiagnosticOptions *DiagOpts) 36 : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} 37 38 DiagnosticRenderer::~DiagnosticRenderer() = default; 39 40 namespace { 41 42 class FixitReceiver : public edit::EditsReceiver { 43 SmallVectorImpl<FixItHint> &MergedFixits; 44 45 public: 46 FixitReceiver(SmallVectorImpl<FixItHint> &MergedFixits) 47 : MergedFixits(MergedFixits) {} 48 49 void insert(SourceLocation loc, StringRef text) override { 50 MergedFixits.push_back(FixItHint::CreateInsertion(loc, text)); 51 } 52 53 void replace(CharSourceRange range, StringRef text) override { 54 MergedFixits.push_back(FixItHint::CreateReplacement(range, text)); 55 } 56 }; 57 58 } // namespace 59 60 static void mergeFixits(ArrayRef<FixItHint> FixItHints, 61 const SourceManager &SM, const LangOptions &LangOpts, 62 SmallVectorImpl<FixItHint> &MergedFixits) { 63 edit::Commit commit(SM, LangOpts); 64 for (const auto &Hint : FixItHints) 65 if (Hint.CodeToInsert.empty()) { 66 if (Hint.InsertFromRange.isValid()) 67 commit.insertFromRange(Hint.RemoveRange.getBegin(), 68 Hint.InsertFromRange, /*afterToken=*/false, 69 Hint.BeforePreviousInsertions); 70 else 71 commit.remove(Hint.RemoveRange); 72 } else { 73 if (Hint.RemoveRange.isTokenRange() || 74 Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd()) 75 commit.replace(Hint.RemoveRange, Hint.CodeToInsert); 76 else 77 commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert, 78 /*afterToken=*/false, Hint.BeforePreviousInsertions); 79 } 80 81 edit::EditedSource Editor(SM, LangOpts); 82 if (Editor.commit(commit)) { 83 FixitReceiver Rec(MergedFixits); 84 Editor.applyRewrites(Rec); 85 } 86 } 87 88 void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc, 89 DiagnosticsEngine::Level Level, 90 StringRef Message, 91 ArrayRef<CharSourceRange> Ranges, 92 ArrayRef<FixItHint> FixItHints, 93 DiagOrStoredDiag D) { 94 assert(Loc.hasManager() || Loc.isInvalid()); 95 96 beginDiagnostic(D, Level); 97 98 if (!Loc.isValid()) 99 // If we have no source location, just emit the diagnostic message. 100 emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, D); 101 else { 102 // Get the ranges into a local array we can hack on. 103 SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), 104 Ranges.end()); 105 106 SmallVector<FixItHint, 8> MergedFixits; 107 if (!FixItHints.empty()) { 108 mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits); 109 FixItHints = MergedFixits; 110 } 111 112 for (const auto &Hint : FixItHints) 113 if (Hint.RemoveRange.isValid()) 114 MutableRanges.push_back(Hint.RemoveRange); 115 116 FullSourceLoc UnexpandedLoc = Loc; 117 118 // Find the ultimate expansion location for the diagnostic. 119 Loc = Loc.getFileLoc(); 120 121 PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); 122 123 // First, if this diagnostic is not in the main file, print out the 124 // "included from" lines. 125 emitIncludeStack(Loc, PLoc, Level); 126 127 // Next, emit the actual diagnostic message and caret. 128 emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D); 129 emitCaret(Loc, Level, MutableRanges, FixItHints); 130 131 // If this location is within a macro, walk from UnexpandedLoc up to Loc 132 // and produce a macro backtrace. 133 if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) { 134 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints); 135 } 136 } 137 138 LastLoc = Loc; 139 LastLevel = Level; 140 141 endDiagnostic(D, Level); 142 } 143 144 void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { 145 emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(), 146 Diag.getRanges(), Diag.getFixIts(), 147 &Diag); 148 } 149 150 void DiagnosticRenderer::emitBasicNote(StringRef Message) { 151 emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note, 152 Message, None, DiagOrStoredDiag()); 153 } 154 155 /// Prints an include stack when appropriate for a particular 156 /// diagnostic level and location. 157 /// 158 /// This routine handles all the logic of suppressing particular include 159 /// stacks (such as those for notes) and duplicate include stacks when 160 /// repeated warnings occur within the same file. It also handles the logic 161 /// of customizing the formatting and display of the include stack. 162 /// 163 /// \param Loc The diagnostic location. 164 /// \param PLoc The presumed location of the diagnostic location. 165 /// \param Level The diagnostic level of the message this stack pertains to. 166 void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc, 167 DiagnosticsEngine::Level Level) { 168 FullSourceLoc IncludeLoc = 169 PLoc.isInvalid() ? FullSourceLoc() 170 : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()); 171 172 // Skip redundant include stacks altogether. 173 if (LastIncludeLoc == IncludeLoc) 174 return; 175 176 LastIncludeLoc = IncludeLoc; 177 178 if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) 179 return; 180 181 if (IncludeLoc.isValid()) 182 emitIncludeStackRecursively(IncludeLoc); 183 else { 184 emitModuleBuildStack(Loc.getManager()); 185 emitImportStack(Loc); 186 } 187 } 188 189 /// Helper to recursively walk up the include stack and print each layer 190 /// on the way back down. 191 void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) { 192 if (Loc.isInvalid()) { 193 emitModuleBuildStack(Loc.getManager()); 194 return; 195 } 196 197 PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); 198 if (PLoc.isInvalid()) 199 return; 200 201 // If this source location was imported from a module, print the module 202 // import stack rather than the 203 // FIXME: We want submodule granularity here. 204 std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc(); 205 if (!Imported.second.empty()) { 206 // This location was imported by a module. Emit the module import stack. 207 emitImportStackRecursively(Imported.first, Imported.second); 208 return; 209 } 210 211 // Emit the other include frames first. 212 emitIncludeStackRecursively( 213 FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager())); 214 215 // Emit the inclusion text/note. 216 emitIncludeLocation(Loc, PLoc); 217 } 218 219 /// Emit the module import stack associated with the current location. 220 void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) { 221 if (Loc.isInvalid()) { 222 emitModuleBuildStack(Loc.getManager()); 223 return; 224 } 225 226 std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc(); 227 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second); 228 } 229 230 /// Helper to recursively walk up the import stack and print each layer 231 /// on the way back down. 232 void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc, 233 StringRef ModuleName) { 234 if (ModuleName.empty()) { 235 return; 236 } 237 238 PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); 239 240 // Emit the other import frames first. 241 std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc(); 242 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second); 243 244 // Emit the inclusion text/note. 245 emitImportLocation(Loc, PLoc, ModuleName); 246 } 247 248 /// Emit the module build stack, for cases where a module is (re-)built 249 /// on demand. 250 void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) { 251 ModuleBuildStack Stack = SM.getModuleBuildStack(); 252 for (const auto &I : Stack) { 253 emitBuildingModuleLocation(I.second, I.second.getPresumedLoc( 254 DiagOpts->ShowPresumedLoc), 255 I.first); 256 } 257 } 258 259 /// A recursive function to trace all possible backtrace locations 260 /// to match the \p CaretLocFileID. 261 static SourceLocation 262 retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID, 263 FileID CaretFileID, 264 const SmallVectorImpl<FileID> &CommonArgExpansions, 265 bool IsBegin, const SourceManager *SM, 266 bool &IsTokenRange) { 267 assert(SM->getFileID(Loc) == MacroFileID); 268 if (MacroFileID == CaretFileID) 269 return Loc; 270 if (!Loc.isMacroID()) 271 return {}; 272 273 CharSourceRange MacroRange, MacroArgRange; 274 275 if (SM->isMacroArgExpansion(Loc)) { 276 // Only look at the immediate spelling location of this macro argument if 277 // the other location in the source range is also present in that expansion. 278 if (std::binary_search(CommonArgExpansions.begin(), 279 CommonArgExpansions.end(), MacroFileID)) 280 MacroRange = 281 CharSourceRange(SM->getImmediateSpellingLoc(Loc), IsTokenRange); 282 MacroArgRange = SM->getImmediateExpansionRange(Loc); 283 } else { 284 MacroRange = SM->getImmediateExpansionRange(Loc); 285 MacroArgRange = 286 CharSourceRange(SM->getImmediateSpellingLoc(Loc), IsTokenRange); 287 } 288 289 SourceLocation MacroLocation = 290 IsBegin ? MacroRange.getBegin() : MacroRange.getEnd(); 291 if (MacroLocation.isValid()) { 292 MacroFileID = SM->getFileID(MacroLocation); 293 bool TokenRange = IsBegin ? IsTokenRange : MacroRange.isTokenRange(); 294 MacroLocation = 295 retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID, 296 CommonArgExpansions, IsBegin, SM, TokenRange); 297 if (MacroLocation.isValid()) { 298 IsTokenRange = TokenRange; 299 return MacroLocation; 300 } 301 } 302 303 // If we moved the end of the range to an expansion location, we now have 304 // a range of the same kind as the expansion range. 305 if (!IsBegin) 306 IsTokenRange = MacroArgRange.isTokenRange(); 307 308 SourceLocation MacroArgLocation = 309 IsBegin ? MacroArgRange.getBegin() : MacroArgRange.getEnd(); 310 MacroFileID = SM->getFileID(MacroArgLocation); 311 return retrieveMacroLocation(MacroArgLocation, MacroFileID, CaretFileID, 312 CommonArgExpansions, IsBegin, SM, IsTokenRange); 313 } 314 315 /// Walk up the chain of macro expansions and collect the FileIDs identifying the 316 /// expansions. 317 static void getMacroArgExpansionFileIDs(SourceLocation Loc, 318 SmallVectorImpl<FileID> &IDs, 319 bool IsBegin, const SourceManager *SM) { 320 while (Loc.isMacroID()) { 321 if (SM->isMacroArgExpansion(Loc)) { 322 IDs.push_back(SM->getFileID(Loc)); 323 Loc = SM->getImmediateSpellingLoc(Loc); 324 } else { 325 auto ExpRange = SM->getImmediateExpansionRange(Loc); 326 Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd(); 327 } 328 } 329 } 330 331 /// Collect the expansions of the begin and end locations and compute the set 332 /// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions. 333 static void computeCommonMacroArgExpansionFileIDs( 334 SourceLocation Begin, SourceLocation End, const SourceManager *SM, 335 SmallVectorImpl<FileID> &CommonArgExpansions) { 336 SmallVector<FileID, 4> BeginArgExpansions; 337 SmallVector<FileID, 4> EndArgExpansions; 338 getMacroArgExpansionFileIDs(Begin, BeginArgExpansions, /*IsBegin=*/true, SM); 339 getMacroArgExpansionFileIDs(End, EndArgExpansions, /*IsBegin=*/false, SM); 340 llvm::sort(BeginArgExpansions.begin(), BeginArgExpansions.end()); 341 llvm::sort(EndArgExpansions.begin(), EndArgExpansions.end()); 342 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(), 343 EndArgExpansions.begin(), EndArgExpansions.end(), 344 std::back_inserter(CommonArgExpansions)); 345 } 346 347 // Helper function to fix up source ranges. It takes in an array of ranges, 348 // and outputs an array of ranges where we want to draw the range highlighting 349 // around the location specified by CaretLoc. 350 // 351 // To find locations which correspond to the caret, we crawl the macro caller 352 // chain for the beginning and end of each range. If the caret location 353 // is in a macro expansion, we search each chain for a location 354 // in the same expansion as the caret; otherwise, we crawl to the top of 355 // each chain. Two locations are part of the same macro expansion 356 // iff the FileID is the same. 357 static void 358 mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef<CharSourceRange> Ranges, 359 SmallVectorImpl<CharSourceRange> &SpellingRanges) { 360 FileID CaretLocFileID = CaretLoc.getFileID(); 361 362 const SourceManager *SM = &CaretLoc.getManager(); 363 364 for (const auto &Range : Ranges) { 365 if (Range.isInvalid()) 366 continue; 367 368 SourceLocation Begin = Range.getBegin(), End = Range.getEnd(); 369 bool IsTokenRange = Range.isTokenRange(); 370 371 FileID BeginFileID = SM->getFileID(Begin); 372 FileID EndFileID = SM->getFileID(End); 373 374 // Find the common parent for the beginning and end of the range. 375 376 // First, crawl the expansion chain for the beginning of the range. 377 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap; 378 while (Begin.isMacroID() && BeginFileID != EndFileID) { 379 BeginLocsMap[BeginFileID] = Begin; 380 Begin = SM->getImmediateExpansionRange(Begin).getBegin(); 381 BeginFileID = SM->getFileID(Begin); 382 } 383 384 // Then, crawl the expansion chain for the end of the range. 385 if (BeginFileID != EndFileID) { 386 while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) { 387 auto Exp = SM->getImmediateExpansionRange(End); 388 IsTokenRange = Exp.isTokenRange(); 389 End = Exp.getEnd(); 390 EndFileID = SM->getFileID(End); 391 } 392 if (End.isMacroID()) { 393 Begin = BeginLocsMap[EndFileID]; 394 BeginFileID = EndFileID; 395 } 396 } 397 398 // Do the backtracking. 399 SmallVector<FileID, 4> CommonArgExpansions; 400 computeCommonMacroArgExpansionFileIDs(Begin, End, SM, CommonArgExpansions); 401 Begin = retrieveMacroLocation(Begin, BeginFileID, CaretLocFileID, 402 CommonArgExpansions, /*IsBegin=*/true, SM, 403 IsTokenRange); 404 End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID, 405 CommonArgExpansions, /*IsBegin=*/false, SM, 406 IsTokenRange); 407 if (Begin.isInvalid() || End.isInvalid()) continue; 408 409 // Return the spelling location of the beginning and end of the range. 410 Begin = SM->getSpellingLoc(Begin); 411 End = SM->getSpellingLoc(End); 412 413 SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End), 414 IsTokenRange)); 415 } 416 } 417 418 void DiagnosticRenderer::emitCaret(FullSourceLoc Loc, 419 DiagnosticsEngine::Level Level, 420 ArrayRef<CharSourceRange> Ranges, 421 ArrayRef<FixItHint> Hints) { 422 SmallVector<CharSourceRange, 4> SpellingRanges; 423 mapDiagnosticRanges(Loc, Ranges, SpellingRanges); 424 emitCodeContext(Loc, Level, SpellingRanges, Hints); 425 } 426 427 /// A helper function for emitMacroExpansion to print the 428 /// macro expansion message 429 void DiagnosticRenderer::emitSingleMacroExpansion( 430 FullSourceLoc Loc, DiagnosticsEngine::Level Level, 431 ArrayRef<CharSourceRange> Ranges) { 432 // Find the spelling location for the macro definition. We must use the 433 // spelling location here to avoid emitting a macro backtrace for the note. 434 FullSourceLoc SpellingLoc = Loc.getSpellingLoc(); 435 436 // Map the ranges into the FileID of the diagnostic location. 437 SmallVector<CharSourceRange, 4> SpellingRanges; 438 mapDiagnosticRanges(Loc, Ranges, SpellingRanges); 439 440 SmallString<100> MessageStorage; 441 llvm::raw_svector_ostream Message(MessageStorage); 442 StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( 443 Loc, Loc.getManager(), LangOpts); 444 if (MacroName.empty()) 445 Message << "expanded from here"; 446 else 447 Message << "expanded from macro '" << MacroName << "'"; 448 449 emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), 450 SpellingRanges, None); 451 } 452 453 /// Check that the macro argument location of Loc starts with ArgumentLoc. 454 /// The starting location of the macro expansions is used to differeniate 455 /// different macro expansions. 456 static bool checkLocForMacroArgExpansion(SourceLocation Loc, 457 const SourceManager &SM, 458 SourceLocation ArgumentLoc) { 459 SourceLocation MacroLoc; 460 if (SM.isMacroArgExpansion(Loc, &MacroLoc)) { 461 if (ArgumentLoc == MacroLoc) return true; 462 } 463 464 return false; 465 } 466 467 /// Check if all the locations in the range have the same macro argument 468 /// expansion, and that the expansion starts with ArgumentLoc. 469 static bool checkRangeForMacroArgExpansion(CharSourceRange Range, 470 const SourceManager &SM, 471 SourceLocation ArgumentLoc) { 472 SourceLocation BegLoc = Range.getBegin(), EndLoc = Range.getEnd(); 473 while (BegLoc != EndLoc) { 474 if (!checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc)) 475 return false; 476 BegLoc.getLocWithOffset(1); 477 } 478 479 return checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc); 480 } 481 482 /// A helper function to check if the current ranges are all inside the same 483 /// macro argument expansion as Loc. 484 static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc, 485 ArrayRef<CharSourceRange> Ranges) { 486 assert(Loc.isMacroID() && "Must be a macro expansion!"); 487 488 SmallVector<CharSourceRange, 4> SpellingRanges; 489 mapDiagnosticRanges(Loc, Ranges, SpellingRanges); 490 491 /// Count all valid ranges. 492 unsigned ValidCount = 0; 493 for (const auto &Range : Ranges) 494 if (Range.isValid()) 495 ValidCount++; 496 497 if (ValidCount > SpellingRanges.size()) 498 return false; 499 500 /// To store the source location of the argument location. 501 FullSourceLoc ArgumentLoc; 502 503 /// Set the ArgumentLoc to the beginning location of the expansion of Loc 504 /// so to check if the ranges expands to the same beginning location. 505 if (!Loc.isMacroArgExpansion(&ArgumentLoc)) 506 return false; 507 508 for (const auto &Range : SpellingRanges) 509 if (!checkRangeForMacroArgExpansion(Range, Loc.getManager(), ArgumentLoc)) 510 return false; 511 512 return true; 513 } 514 515 /// Recursively emit notes for each macro expansion and caret 516 /// diagnostics where appropriate. 517 /// 518 /// Walks up the macro expansion stack printing expansion notes, the code 519 /// snippet, caret, underlines and FixItHint display as appropriate at each 520 /// level. 521 /// 522 /// \param Loc The location for this caret. 523 /// \param Level The diagnostic level currently being emitted. 524 /// \param Ranges The underlined ranges for this code snippet. 525 /// \param Hints The FixIt hints active for this diagnostic. 526 void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc, 527 DiagnosticsEngine::Level Level, 528 ArrayRef<CharSourceRange> Ranges, 529 ArrayRef<FixItHint> Hints) { 530 assert(Loc.isValid() && "must have a valid source location here"); 531 const SourceManager &SM = Loc.getManager(); 532 SourceLocation L = Loc; 533 534 // Produce a stack of macro backtraces. 535 SmallVector<SourceLocation, 8> LocationStack; 536 unsigned IgnoredEnd = 0; 537 while (L.isMacroID()) { 538 // If this is the expansion of a macro argument, point the caret at the 539 // use of the argument in the definition of the macro, not the expansion. 540 if (SM.isMacroArgExpansion(L)) 541 LocationStack.push_back(SM.getImmediateExpansionRange(L).getBegin()); 542 else 543 LocationStack.push_back(L); 544 545 if (checkRangesForMacroArgExpansion(FullSourceLoc(L, SM), Ranges)) 546 IgnoredEnd = LocationStack.size(); 547 548 L = SM.getImmediateMacroCallerLoc(L); 549 550 // Once the location no longer points into a macro, try stepping through 551 // the last found location. This sometimes produces additional useful 552 // backtraces. 553 if (L.isFileID()) 554 L = SM.getImmediateMacroCallerLoc(LocationStack.back()); 555 assert(L.isValid() && "must have a valid source location here"); 556 } 557 558 LocationStack.erase(LocationStack.begin(), 559 LocationStack.begin() + IgnoredEnd); 560 561 unsigned MacroDepth = LocationStack.size(); 562 unsigned MacroLimit = DiagOpts->MacroBacktraceLimit; 563 if (MacroDepth <= MacroLimit || MacroLimit == 0) { 564 for (auto I = LocationStack.rbegin(), E = LocationStack.rend(); 565 I != E; ++I) 566 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges); 567 return; 568 } 569 570 unsigned MacroStartMessages = MacroLimit / 2; 571 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2; 572 573 for (auto I = LocationStack.rbegin(), 574 E = LocationStack.rbegin() + MacroStartMessages; 575 I != E; ++I) 576 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges); 577 578 SmallString<200> MessageStorage; 579 llvm::raw_svector_ostream Message(MessageStorage); 580 Message << "(skipping " << (MacroDepth - MacroLimit) 581 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to " 582 "see all)"; 583 emitBasicNote(Message.str()); 584 585 for (auto I = LocationStack.rend() - MacroEndMessages, 586 E = LocationStack.rend(); 587 I != E; ++I) 588 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges); 589 } 590 591 DiagnosticNoteRenderer::~DiagnosticNoteRenderer() = default; 592 593 void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc, 594 PresumedLoc PLoc) { 595 // Generate a note indicating the include location. 596 SmallString<200> MessageStorage; 597 llvm::raw_svector_ostream Message(MessageStorage); 598 Message << "in file included from " << PLoc.getFilename() << ':' 599 << PLoc.getLine() << ":"; 600 emitNote(Loc, Message.str()); 601 } 602 603 void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc, 604 PresumedLoc PLoc, 605 StringRef ModuleName) { 606 // Generate a note indicating the include location. 607 SmallString<200> MessageStorage; 608 llvm::raw_svector_ostream Message(MessageStorage); 609 Message << "in module '" << ModuleName; 610 if (PLoc.isValid()) 611 Message << "' imported from " << PLoc.getFilename() << ':' 612 << PLoc.getLine(); 613 Message << ":"; 614 emitNote(Loc, Message.str()); 615 } 616 617 void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc, 618 PresumedLoc PLoc, 619 StringRef ModuleName) { 620 // Generate a note indicating the include location. 621 SmallString<200> MessageStorage; 622 llvm::raw_svector_ostream Message(MessageStorage); 623 if (PLoc.isValid()) 624 Message << "while building module '" << ModuleName << "' imported from " 625 << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; 626 else 627 Message << "while building module '" << ModuleName << "':"; 628 emitNote(Loc, Message.str()); 629 } 630