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