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/FileManager.h" 13 #include "clang/Basic/SourceManager.h" 14 #include "clang/Edit/Commit.h" 15 #include "clang/Edit/EditedSource.h" 16 #include "clang/Edit/EditsReceiver.h" 17 #include "clang/Lex/Lexer.h" 18 #include "llvm/ADT/SmallSet.h" 19 #include "llvm/ADT/SmallString.h" 20 #include "llvm/Support/ErrorHandling.h" 21 #include "llvm/Support/MemoryBuffer.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include <algorithm> 24 using namespace clang; 25 26 /// \brief Retrieve the name of the immediate macro expansion. 27 /// 28 /// This routine starts from a source location, and finds the name of the macro 29 /// responsible for its immediate expansion. It looks through any intervening 30 /// macro argument expansions to compute this. It returns a StringRef which 31 /// refers to the SourceManager-owned buffer of the source where that macro 32 /// name is spelled. Thus, the result shouldn't out-live that SourceManager. 33 /// 34 /// This differs from Lexer::getImmediateMacroName in that any macro argument 35 /// location will result in the topmost function macro that accepted it. 36 /// e.g. 37 /// \code 38 /// MAC1( MAC2(foo) ) 39 /// \endcode 40 /// for location of 'foo' token, this function will return "MAC1" while 41 /// Lexer::getImmediateMacroName will return "MAC2". 42 static StringRef getImmediateMacroName(SourceLocation Loc, 43 const SourceManager &SM, 44 const LangOptions &LangOpts) { 45 assert(Loc.isMacroID() && "Only reasonble to call this on macros"); 46 // Walk past macro argument expanions. 47 while (SM.isMacroArgExpansion(Loc)) 48 Loc = SM.getImmediateExpansionRange(Loc).first; 49 50 // If the macro's spelling has no FileID, then it's actually a token paste 51 // or stringization (or similar) and not a macro at all. 52 if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(Loc)))) 53 return StringRef(); 54 55 // Find the spelling location of the start of the non-argument expansion 56 // range. This is where the macro name was spelled in order to begin 57 // expanding this macro. 58 Loc = SM.getSpellingLoc(SM.getImmediateExpansionRange(Loc).first); 59 60 // Dig out the buffer where the macro name was spelled and the extents of the 61 // name so that we can render it into the expansion note. 62 std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc); 63 unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts); 64 StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first); 65 return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength); 66 } 67 68 DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts, 69 DiagnosticOptions *DiagOpts) 70 : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} 71 72 DiagnosticRenderer::~DiagnosticRenderer() {} 73 74 namespace { 75 76 class FixitReceiver : public edit::EditsReceiver { 77 SmallVectorImpl<FixItHint> &MergedFixits; 78 79 public: 80 FixitReceiver(SmallVectorImpl<FixItHint> &MergedFixits) 81 : MergedFixits(MergedFixits) { } 82 void insert(SourceLocation loc, StringRef text) override { 83 MergedFixits.push_back(FixItHint::CreateInsertion(loc, text)); 84 } 85 void replace(CharSourceRange range, StringRef text) override { 86 MergedFixits.push_back(FixItHint::CreateReplacement(range, text)); 87 } 88 }; 89 90 } 91 92 static void mergeFixits(ArrayRef<FixItHint> FixItHints, 93 const SourceManager &SM, const LangOptions &LangOpts, 94 SmallVectorImpl<FixItHint> &MergedFixits) { 95 edit::Commit commit(SM, LangOpts); 96 for (ArrayRef<FixItHint>::const_iterator 97 I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) { 98 const FixItHint &Hint = *I; 99 if (Hint.CodeToInsert.empty()) { 100 if (Hint.InsertFromRange.isValid()) 101 commit.insertFromRange(Hint.RemoveRange.getBegin(), 102 Hint.InsertFromRange, /*afterToken=*/false, 103 Hint.BeforePreviousInsertions); 104 else 105 commit.remove(Hint.RemoveRange); 106 } else { 107 if (Hint.RemoveRange.isTokenRange() || 108 Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd()) 109 commit.replace(Hint.RemoveRange, Hint.CodeToInsert); 110 else 111 commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert, 112 /*afterToken=*/false, Hint.BeforePreviousInsertions); 113 } 114 } 115 116 edit::EditedSource Editor(SM, LangOpts); 117 if (Editor.commit(commit)) { 118 FixitReceiver Rec(MergedFixits); 119 Editor.applyRewrites(Rec); 120 } 121 } 122 123 void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, 124 DiagnosticsEngine::Level Level, 125 StringRef Message, 126 ArrayRef<CharSourceRange> Ranges, 127 ArrayRef<FixItHint> FixItHints, 128 const SourceManager *SM, 129 DiagOrStoredDiag D) { 130 assert(SM || Loc.isInvalid()); 131 132 beginDiagnostic(D, Level); 133 134 if (!Loc.isValid()) 135 // If we have no source location, just emit the diagnostic message. 136 emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D); 137 else { 138 // Get the ranges into a local array we can hack on. 139 SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), 140 Ranges.end()); 141 142 SmallVector<FixItHint, 8> MergedFixits; 143 if (!FixItHints.empty()) { 144 mergeFixits(FixItHints, *SM, LangOpts, MergedFixits); 145 FixItHints = MergedFixits; 146 } 147 148 for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(), 149 E = FixItHints.end(); 150 I != E; ++I) 151 if (I->RemoveRange.isValid()) 152 MutableRanges.push_back(I->RemoveRange); 153 154 SourceLocation UnexpandedLoc = Loc; 155 156 // Find the ultimate expansion location for the diagnostic. 157 Loc = SM->getFileLoc(Loc); 158 159 PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); 160 161 // First, if this diagnostic is not in the main file, print out the 162 // "included from" lines. 163 emitIncludeStack(Loc, PLoc, Level, *SM); 164 165 // Next, emit the actual diagnostic message and caret. 166 emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D); 167 emitCaret(Loc, Level, MutableRanges, FixItHints, *SM); 168 169 // If this location is within a macro, walk from UnexpandedLoc up to Loc 170 // and produce a macro backtrace. 171 if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) { 172 unsigned MacroDepth = 0; 173 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM, 174 MacroDepth); 175 } 176 } 177 178 LastLoc = Loc; 179 LastLevel = Level; 180 181 endDiagnostic(D, Level); 182 } 183 184 185 void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { 186 emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(), 187 Diag.getRanges(), Diag.getFixIts(), 188 Diag.getLocation().isValid() ? &Diag.getLocation().getManager() 189 : nullptr, 190 &Diag); 191 } 192 193 void DiagnosticRenderer::emitBasicNote(StringRef Message) { 194 emitDiagnosticMessage( 195 SourceLocation(), PresumedLoc(), DiagnosticsEngine::Note, Message, 196 ArrayRef<CharSourceRange>(), nullptr, DiagOrStoredDiag()); 197 } 198 199 /// \brief Prints an include stack when appropriate for a particular 200 /// diagnostic level and location. 201 /// 202 /// This routine handles all the logic of suppressing particular include 203 /// stacks (such as those for notes) and duplicate include stacks when 204 /// repeated warnings occur within the same file. It also handles the logic 205 /// of customizing the formatting and display of the include stack. 206 /// 207 /// \param Loc The diagnostic location. 208 /// \param PLoc The presumed location of the diagnostic location. 209 /// \param Level The diagnostic level of the message this stack pertains to. 210 void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, 211 PresumedLoc PLoc, 212 DiagnosticsEngine::Level Level, 213 const SourceManager &SM) { 214 SourceLocation IncludeLoc = PLoc.getIncludeLoc(); 215 216 // Skip redundant include stacks altogether. 217 if (LastIncludeLoc == IncludeLoc) 218 return; 219 220 LastIncludeLoc = IncludeLoc; 221 222 if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) 223 return; 224 225 if (IncludeLoc.isValid()) 226 emitIncludeStackRecursively(IncludeLoc, SM); 227 else { 228 emitModuleBuildStack(SM); 229 emitImportStack(Loc, SM); 230 } 231 } 232 233 /// \brief Helper to recursivly walk up the include stack and print each layer 234 /// on the way back down. 235 void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, 236 const SourceManager &SM) { 237 if (Loc.isInvalid()) { 238 emitModuleBuildStack(SM); 239 return; 240 } 241 242 PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); 243 if (PLoc.isInvalid()) 244 return; 245 246 // If this source location was imported from a module, print the module 247 // import stack rather than the 248 // FIXME: We want submodule granularity here. 249 std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc); 250 if (Imported.first.isValid()) { 251 // This location was imported by a module. Emit the module import stack. 252 emitImportStackRecursively(Imported.first, Imported.second, SM); 253 return; 254 } 255 256 // Emit the other include frames first. 257 emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM); 258 259 // Emit the inclusion text/note. 260 emitIncludeLocation(Loc, PLoc, SM); 261 } 262 263 /// \brief Emit the module import stack associated with the current location. 264 void DiagnosticRenderer::emitImportStack(SourceLocation Loc, 265 const SourceManager &SM) { 266 if (Loc.isInvalid()) { 267 emitModuleBuildStack(SM); 268 return; 269 } 270 271 std::pair<SourceLocation, StringRef> NextImportLoc 272 = SM.getModuleImportLoc(Loc); 273 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); 274 } 275 276 /// \brief Helper to recursivly walk up the import stack and print each layer 277 /// on the way back down. 278 void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc, 279 StringRef ModuleName, 280 const SourceManager &SM) { 281 if (Loc.isInvalid()) { 282 return; 283 } 284 285 PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); 286 if (PLoc.isInvalid()) 287 return; 288 289 // Emit the other import frames first. 290 std::pair<SourceLocation, StringRef> NextImportLoc 291 = SM.getModuleImportLoc(Loc); 292 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); 293 294 // Emit the inclusion text/note. 295 emitImportLocation(Loc, PLoc, ModuleName, SM); 296 } 297 298 /// \brief Emit the module build stack, for cases where a module is (re-)built 299 /// on demand. 300 void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) { 301 ModuleBuildStack Stack = SM.getModuleBuildStack(); 302 for (unsigned I = 0, N = Stack.size(); I != N; ++I) { 303 const SourceManager &CurSM = Stack[I].second.getManager(); 304 SourceLocation CurLoc = Stack[I].second; 305 emitBuildingModuleLocation(CurLoc, 306 CurSM.getPresumedLoc(CurLoc, 307 DiagOpts->ShowPresumedLoc), 308 Stack[I].first, 309 CurSM); 310 } 311 } 312 313 // Helper function to fix up source ranges. It takes in an array of ranges, 314 // and outputs an array of ranges where we want to draw the range highlighting 315 // around the location specified by CaretLoc. 316 // 317 // To find locations which correspond to the caret, we crawl the macro caller 318 // chain for the beginning and end of each range. If the caret location 319 // is in a macro expansion, we search each chain for a location 320 // in the same expansion as the caret; otherwise, we crawl to the top of 321 // each chain. Two locations are part of the same macro expansion 322 // iff the FileID is the same. 323 static void mapDiagnosticRanges( 324 SourceLocation CaretLoc, 325 ArrayRef<CharSourceRange> Ranges, 326 SmallVectorImpl<CharSourceRange> &SpellingRanges, 327 const SourceManager *SM) { 328 FileID CaretLocFileID = SM->getFileID(CaretLoc); 329 330 for (ArrayRef<CharSourceRange>::const_iterator I = Ranges.begin(), 331 E = Ranges.end(); 332 I != E; ++I) { 333 SourceLocation Begin = I->getBegin(), End = I->getEnd(); 334 bool IsTokenRange = I->isTokenRange(); 335 336 FileID BeginFileID = SM->getFileID(Begin); 337 FileID EndFileID = SM->getFileID(End); 338 339 // Find the common parent for the beginning and end of the range. 340 341 // First, crawl the expansion chain for the beginning of the range. 342 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap; 343 while (Begin.isMacroID() && BeginFileID != EndFileID) { 344 BeginLocsMap[BeginFileID] = Begin; 345 Begin = SM->getImmediateExpansionRange(Begin).first; 346 BeginFileID = SM->getFileID(Begin); 347 } 348 349 // Then, crawl the expansion chain for the end of the range. 350 if (BeginFileID != EndFileID) { 351 while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) { 352 End = SM->getImmediateExpansionRange(End).second; 353 EndFileID = SM->getFileID(End); 354 } 355 if (End.isMacroID()) { 356 Begin = BeginLocsMap[EndFileID]; 357 BeginFileID = EndFileID; 358 } 359 } 360 361 while (Begin.isMacroID() && BeginFileID != CaretLocFileID) { 362 if (SM->isMacroArgExpansion(Begin)) { 363 Begin = SM->getImmediateSpellingLoc(Begin); 364 End = SM->getImmediateSpellingLoc(End); 365 } else { 366 Begin = SM->getImmediateExpansionRange(Begin).first; 367 End = SM->getImmediateExpansionRange(End).second; 368 } 369 BeginFileID = SM->getFileID(Begin); 370 if (BeginFileID != SM->getFileID(End)) { 371 // FIXME: Ugly hack to stop a crash; this code is making bad 372 // assumptions and it's too complicated for me to reason 373 // about. 374 Begin = End = SourceLocation(); 375 break; 376 } 377 } 378 379 // Return the spelling location of the beginning and end of the range. 380 Begin = SM->getSpellingLoc(Begin); 381 End = SM->getSpellingLoc(End); 382 SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End), 383 IsTokenRange)); 384 } 385 } 386 387 void DiagnosticRenderer::emitCaret(SourceLocation Loc, 388 DiagnosticsEngine::Level Level, 389 ArrayRef<CharSourceRange> Ranges, 390 ArrayRef<FixItHint> Hints, 391 const SourceManager &SM) { 392 SmallVector<CharSourceRange, 4> SpellingRanges; 393 mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); 394 emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); 395 } 396 397 /// \brief Recursively emit notes for each macro expansion and caret 398 /// diagnostics where appropriate. 399 /// 400 /// Walks up the macro expansion stack printing expansion notes, the code 401 /// snippet, caret, underlines and FixItHint display as appropriate at each 402 /// level. 403 /// 404 /// \param Loc The location for this caret. 405 /// \param Level The diagnostic level currently being emitted. 406 /// \param Ranges The underlined ranges for this code snippet. 407 /// \param Hints The FixIt hints active for this diagnostic. 408 /// \param OnMacroInst The current depth of the macro expansion stack. 409 void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, 410 DiagnosticsEngine::Level Level, 411 ArrayRef<CharSourceRange> Ranges, 412 ArrayRef<FixItHint> Hints, 413 const SourceManager &SM, 414 unsigned &MacroDepth, 415 unsigned OnMacroInst) { 416 assert(!Loc.isInvalid() && "must have a valid source location here"); 417 418 // Walk up to the caller of this macro, and produce a backtrace down to there. 419 SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc); 420 if (OneLevelUp.isMacroID()) 421 emitMacroExpansions(OneLevelUp, Level, Ranges, Hints, SM, 422 MacroDepth, OnMacroInst + 1); 423 else 424 MacroDepth = OnMacroInst + 1; 425 426 unsigned MacroSkipStart = 0, MacroSkipEnd = 0; 427 if (MacroDepth > DiagOpts->MacroBacktraceLimit && 428 DiagOpts->MacroBacktraceLimit != 0) { 429 MacroSkipStart = DiagOpts->MacroBacktraceLimit / 2 + 430 DiagOpts->MacroBacktraceLimit % 2; 431 MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2; 432 } 433 434 // Whether to suppress printing this macro expansion. 435 bool Suppressed = (OnMacroInst >= MacroSkipStart && 436 OnMacroInst < MacroSkipEnd); 437 438 if (Suppressed) { 439 // Tell the user that we've skipped contexts. 440 if (OnMacroInst == MacroSkipStart) { 441 SmallString<200> MessageStorage; 442 llvm::raw_svector_ostream Message(MessageStorage); 443 Message << "(skipping " << (MacroSkipEnd - MacroSkipStart) 444 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to " 445 "see all)"; 446 emitBasicNote(Message.str()); 447 } 448 return; 449 } 450 451 // Find the spelling location for the macro definition. We must use the 452 // spelling location here to avoid emitting a macro bactrace for the note. 453 SourceLocation SpellingLoc = Loc; 454 // If this is the expansion of a macro argument, point the caret at the 455 // use of the argument in the definition of the macro, not the expansion. 456 if (SM.isMacroArgExpansion(Loc)) 457 SpellingLoc = SM.getImmediateExpansionRange(Loc).first; 458 SpellingLoc = SM.getSpellingLoc(SpellingLoc); 459 460 // Map the ranges into the FileID of the diagnostic location. 461 SmallVector<CharSourceRange, 4> SpellingRanges; 462 mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); 463 464 SmallString<100> MessageStorage; 465 llvm::raw_svector_ostream Message(MessageStorage); 466 StringRef MacroName = getImmediateMacroName(Loc, SM, LangOpts); 467 if (MacroName.empty()) 468 Message << "expanded from here"; 469 else 470 Message << "expanded from macro '" << MacroName << "'"; 471 emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), 472 SpellingRanges, None, &SM); 473 } 474 475 DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} 476 477 void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc, 478 PresumedLoc PLoc, 479 const SourceManager &SM) { 480 // Generate a note indicating the include location. 481 SmallString<200> MessageStorage; 482 llvm::raw_svector_ostream Message(MessageStorage); 483 Message << "in file included from " << PLoc.getFilename() << ':' 484 << PLoc.getLine() << ":"; 485 emitNote(Loc, Message.str(), &SM); 486 } 487 488 void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc, 489 PresumedLoc PLoc, 490 StringRef ModuleName, 491 const SourceManager &SM) { 492 // Generate a note indicating the include location. 493 SmallString<200> MessageStorage; 494 llvm::raw_svector_ostream Message(MessageStorage); 495 Message << "in module '" << ModuleName << "' imported from " 496 << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; 497 emitNote(Loc, Message.str(), &SM); 498 } 499 500 void 501 DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc, 502 PresumedLoc PLoc, 503 StringRef ModuleName, 504 const SourceManager &SM) { 505 // Generate a note indicating the include location. 506 SmallString<200> MessageStorage; 507 llvm::raw_svector_ostream Message(MessageStorage); 508 if (PLoc.getFilename()) 509 Message << "while building module '" << ModuleName << "' imported from " 510 << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; 511 else 512 Message << "while building module '" << ModuleName << ":"; 513 emitNote(Loc, Message.str(), &SM); 514 } 515