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