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 /// \brief 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 /// \brief 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 /// \brief 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 /// \brief 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 /// \brief 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 assert(SM->getFileID(Loc) == MacroFileID); 267 if (MacroFileID == CaretFileID) 268 return Loc; 269 if (!Loc.isMacroID()) 270 return {}; 271 272 SourceLocation MacroLocation, MacroArgLocation; 273 274 if (SM->isMacroArgExpansion(Loc)) { 275 // Only look at the immediate spelling location of this macro argument if 276 // the other location in the source range is also present in that expansion. 277 if (std::binary_search(CommonArgExpansions.begin(), 278 CommonArgExpansions.end(), MacroFileID)) 279 MacroLocation = SM->getImmediateSpellingLoc(Loc); 280 MacroArgLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first 281 : SM->getImmediateExpansionRange(Loc).second; 282 } else { 283 MacroLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first 284 : SM->getImmediateExpansionRange(Loc).second; 285 MacroArgLocation = SM->getImmediateSpellingLoc(Loc); 286 } 287 288 if (MacroLocation.isValid()) { 289 MacroFileID = SM->getFileID(MacroLocation); 290 MacroLocation = 291 retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID, 292 CommonArgExpansions, IsBegin, SM); 293 if (MacroLocation.isValid()) 294 return MacroLocation; 295 } 296 297 MacroFileID = SM->getFileID(MacroArgLocation); 298 return retrieveMacroLocation(MacroArgLocation, MacroFileID, CaretFileID, 299 CommonArgExpansions, IsBegin, SM); 300 } 301 302 /// Walk up the chain of macro expansions and collect the FileIDs identifying the 303 /// expansions. 304 static void getMacroArgExpansionFileIDs(SourceLocation Loc, 305 SmallVectorImpl<FileID> &IDs, 306 bool IsBegin, const SourceManager *SM) { 307 while (Loc.isMacroID()) { 308 if (SM->isMacroArgExpansion(Loc)) { 309 IDs.push_back(SM->getFileID(Loc)); 310 Loc = SM->getImmediateSpellingLoc(Loc); 311 } else { 312 auto ExpRange = SM->getImmediateExpansionRange(Loc); 313 Loc = IsBegin ? ExpRange.first : ExpRange.second; 314 } 315 } 316 } 317 318 /// Collect the expansions of the begin and end locations and compute the set 319 /// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions. 320 static void computeCommonMacroArgExpansionFileIDs( 321 SourceLocation Begin, SourceLocation End, const SourceManager *SM, 322 SmallVectorImpl<FileID> &CommonArgExpansions) { 323 SmallVector<FileID, 4> BeginArgExpansions; 324 SmallVector<FileID, 4> EndArgExpansions; 325 getMacroArgExpansionFileIDs(Begin, BeginArgExpansions, /*IsBegin=*/true, SM); 326 getMacroArgExpansionFileIDs(End, EndArgExpansions, /*IsBegin=*/false, SM); 327 llvm::sort(BeginArgExpansions.begin(), BeginArgExpansions.end()); 328 llvm::sort(EndArgExpansions.begin(), EndArgExpansions.end()); 329 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(), 330 EndArgExpansions.begin(), EndArgExpansions.end(), 331 std::back_inserter(CommonArgExpansions)); 332 } 333 334 // Helper function to fix up source ranges. It takes in an array of ranges, 335 // and outputs an array of ranges where we want to draw the range highlighting 336 // around the location specified by CaretLoc. 337 // 338 // To find locations which correspond to the caret, we crawl the macro caller 339 // chain for the beginning and end of each range. If the caret location 340 // is in a macro expansion, we search each chain for a location 341 // in the same expansion as the caret; otherwise, we crawl to the top of 342 // each chain. Two locations are part of the same macro expansion 343 // iff the FileID is the same. 344 static void 345 mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef<CharSourceRange> Ranges, 346 SmallVectorImpl<CharSourceRange> &SpellingRanges) { 347 FileID CaretLocFileID = CaretLoc.getFileID(); 348 349 const SourceManager *SM = &CaretLoc.getManager(); 350 351 for (const auto &Range : Ranges) { 352 if (Range.isInvalid()) 353 continue; 354 355 SourceLocation Begin = Range.getBegin(), End = Range.getEnd(); 356 bool IsTokenRange = Range.isTokenRange(); 357 358 FileID BeginFileID = SM->getFileID(Begin); 359 FileID EndFileID = SM->getFileID(End); 360 361 // Find the common parent for the beginning and end of the range. 362 363 // First, crawl the expansion chain for the beginning of the range. 364 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap; 365 while (Begin.isMacroID() && BeginFileID != EndFileID) { 366 BeginLocsMap[BeginFileID] = Begin; 367 Begin = SM->getImmediateExpansionRange(Begin).first; 368 BeginFileID = SM->getFileID(Begin); 369 } 370 371 // Then, crawl the expansion chain for the end of the range. 372 if (BeginFileID != EndFileID) { 373 while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) { 374 End = SM->getImmediateExpansionRange(End).second; 375 EndFileID = SM->getFileID(End); 376 } 377 if (End.isMacroID()) { 378 Begin = BeginLocsMap[EndFileID]; 379 BeginFileID = EndFileID; 380 } 381 } 382 383 // Do the backtracking. 384 SmallVector<FileID, 4> CommonArgExpansions; 385 computeCommonMacroArgExpansionFileIDs(Begin, End, SM, CommonArgExpansions); 386 Begin = retrieveMacroLocation(Begin, BeginFileID, CaretLocFileID, 387 CommonArgExpansions, /*IsBegin=*/true, SM); 388 End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID, 389 CommonArgExpansions, /*IsBegin=*/false, SM); 390 if (Begin.isInvalid() || End.isInvalid()) continue; 391 392 // Return the spelling location of the beginning and end of the range. 393 Begin = SM->getSpellingLoc(Begin); 394 End = SM->getSpellingLoc(End); 395 396 SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End), 397 IsTokenRange)); 398 } 399 } 400 401 void DiagnosticRenderer::emitCaret(FullSourceLoc Loc, 402 DiagnosticsEngine::Level Level, 403 ArrayRef<CharSourceRange> Ranges, 404 ArrayRef<FixItHint> Hints) { 405 SmallVector<CharSourceRange, 4> SpellingRanges; 406 mapDiagnosticRanges(Loc, Ranges, SpellingRanges); 407 emitCodeContext(Loc, Level, SpellingRanges, Hints); 408 } 409 410 /// \brief A helper function for emitMacroExpansion to print the 411 /// macro expansion message 412 void DiagnosticRenderer::emitSingleMacroExpansion( 413 FullSourceLoc Loc, DiagnosticsEngine::Level Level, 414 ArrayRef<CharSourceRange> Ranges) { 415 // Find the spelling location for the macro definition. We must use the 416 // spelling location here to avoid emitting a macro backtrace for the note. 417 FullSourceLoc SpellingLoc = Loc.getSpellingLoc(); 418 419 // Map the ranges into the FileID of the diagnostic location. 420 SmallVector<CharSourceRange, 4> SpellingRanges; 421 mapDiagnosticRanges(Loc, Ranges, SpellingRanges); 422 423 SmallString<100> MessageStorage; 424 llvm::raw_svector_ostream Message(MessageStorage); 425 StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( 426 Loc, Loc.getManager(), LangOpts); 427 if (MacroName.empty()) 428 Message << "expanded from here"; 429 else 430 Message << "expanded from macro '" << MacroName << "'"; 431 432 emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), 433 SpellingRanges, None); 434 } 435 436 /// Check that the macro argument location of Loc starts with ArgumentLoc. 437 /// The starting location of the macro expansions is used to differeniate 438 /// different macro expansions. 439 static bool checkLocForMacroArgExpansion(SourceLocation Loc, 440 const SourceManager &SM, 441 SourceLocation ArgumentLoc) { 442 SourceLocation MacroLoc; 443 if (SM.isMacroArgExpansion(Loc, &MacroLoc)) { 444 if (ArgumentLoc == MacroLoc) return true; 445 } 446 447 return false; 448 } 449 450 /// Check if all the locations in the range have the same macro argument 451 /// expansion, and that the expansion starts with ArgumentLoc. 452 static bool checkRangeForMacroArgExpansion(CharSourceRange Range, 453 const SourceManager &SM, 454 SourceLocation ArgumentLoc) { 455 SourceLocation BegLoc = Range.getBegin(), EndLoc = Range.getEnd(); 456 while (BegLoc != EndLoc) { 457 if (!checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc)) 458 return false; 459 BegLoc.getLocWithOffset(1); 460 } 461 462 return checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc); 463 } 464 465 /// A helper function to check if the current ranges are all inside the same 466 /// macro argument expansion as Loc. 467 static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc, 468 ArrayRef<CharSourceRange> Ranges) { 469 assert(Loc.isMacroID() && "Must be a macro expansion!"); 470 471 SmallVector<CharSourceRange, 4> SpellingRanges; 472 mapDiagnosticRanges(Loc, Ranges, SpellingRanges); 473 474 /// Count all valid ranges. 475 unsigned ValidCount = 0; 476 for (const auto &Range : Ranges) 477 if (Range.isValid()) 478 ValidCount++; 479 480 if (ValidCount > SpellingRanges.size()) 481 return false; 482 483 /// To store the source location of the argument location. 484 FullSourceLoc ArgumentLoc; 485 486 /// Set the ArgumentLoc to the beginning location of the expansion of Loc 487 /// so to check if the ranges expands to the same beginning location. 488 if (!Loc.isMacroArgExpansion(&ArgumentLoc)) 489 return false; 490 491 for (const auto &Range : SpellingRanges) 492 if (!checkRangeForMacroArgExpansion(Range, Loc.getManager(), ArgumentLoc)) 493 return false; 494 495 return true; 496 } 497 498 /// \brief Recursively emit notes for each macro expansion and caret 499 /// diagnostics where appropriate. 500 /// 501 /// Walks up the macro expansion stack printing expansion notes, the code 502 /// snippet, caret, underlines and FixItHint display as appropriate at each 503 /// level. 504 /// 505 /// \param Loc The location for this caret. 506 /// \param Level The diagnostic level currently being emitted. 507 /// \param Ranges The underlined ranges for this code snippet. 508 /// \param Hints The FixIt hints active for this diagnostic. 509 void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc, 510 DiagnosticsEngine::Level Level, 511 ArrayRef<CharSourceRange> Ranges, 512 ArrayRef<FixItHint> Hints) { 513 assert(Loc.isValid() && "must have a valid source location here"); 514 515 // Produce a stack of macro backtraces. 516 SmallVector<FullSourceLoc, 8> LocationStack; 517 unsigned IgnoredEnd = 0; 518 while (Loc.isMacroID()) { 519 // If this is the expansion of a macro argument, point the caret at the 520 // use of the argument in the definition of the macro, not the expansion. 521 if (Loc.isMacroArgExpansion()) 522 LocationStack.push_back(Loc.getImmediateExpansionRange().first); 523 else 524 LocationStack.push_back(Loc); 525 526 if (checkRangesForMacroArgExpansion(Loc, Ranges)) 527 IgnoredEnd = LocationStack.size(); 528 529 Loc = Loc.getImmediateMacroCallerLoc(); 530 531 // Once the location no longer points into a macro, try stepping through 532 // the last found location. This sometimes produces additional useful 533 // backtraces. 534 if (Loc.isFileID()) 535 Loc = LocationStack.back().getImmediateMacroCallerLoc(); 536 assert(Loc.isValid() && "must have a valid source location here"); 537 } 538 539 LocationStack.erase(LocationStack.begin(), 540 LocationStack.begin() + IgnoredEnd); 541 542 unsigned MacroDepth = LocationStack.size(); 543 unsigned MacroLimit = DiagOpts->MacroBacktraceLimit; 544 if (MacroDepth <= MacroLimit || MacroLimit == 0) { 545 for (auto I = LocationStack.rbegin(), E = LocationStack.rend(); 546 I != E; ++I) 547 emitSingleMacroExpansion(*I, Level, Ranges); 548 return; 549 } 550 551 unsigned MacroStartMessages = MacroLimit / 2; 552 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2; 553 554 for (auto I = LocationStack.rbegin(), 555 E = LocationStack.rbegin() + MacroStartMessages; 556 I != E; ++I) 557 emitSingleMacroExpansion(*I, Level, Ranges); 558 559 SmallString<200> MessageStorage; 560 llvm::raw_svector_ostream Message(MessageStorage); 561 Message << "(skipping " << (MacroDepth - MacroLimit) 562 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to " 563 "see all)"; 564 emitBasicNote(Message.str()); 565 566 for (auto I = LocationStack.rend() - MacroEndMessages, 567 E = LocationStack.rend(); 568 I != E; ++I) 569 emitSingleMacroExpansion(*I, Level, Ranges); 570 } 571 572 DiagnosticNoteRenderer::~DiagnosticNoteRenderer() = default; 573 574 void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc, 575 PresumedLoc PLoc) { 576 // Generate a note indicating the include location. 577 SmallString<200> MessageStorage; 578 llvm::raw_svector_ostream Message(MessageStorage); 579 Message << "in file included from " << PLoc.getFilename() << ':' 580 << PLoc.getLine() << ":"; 581 emitNote(Loc, Message.str()); 582 } 583 584 void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc, 585 PresumedLoc PLoc, 586 StringRef ModuleName) { 587 // Generate a note indicating the include location. 588 SmallString<200> MessageStorage; 589 llvm::raw_svector_ostream Message(MessageStorage); 590 Message << "in module '" << ModuleName; 591 if (PLoc.isValid()) 592 Message << "' imported from " << PLoc.getFilename() << ':' 593 << PLoc.getLine(); 594 Message << ":"; 595 emitNote(Loc, Message.str()); 596 } 597 598 void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc, 599 PresumedLoc PLoc, 600 StringRef ModuleName) { 601 // Generate a note indicating the include location. 602 SmallString<200> MessageStorage; 603 llvm::raw_svector_ostream Message(MessageStorage); 604 if (PLoc.isValid()) 605 Message << "while building module '" << ModuleName << "' imported from " 606 << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; 607 else 608 Message << "while building module '" << ModuleName << "':"; 609 emitNote(Loc, Message.str()); 610 } 611