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