DiagnosticRenderer.cpp revision 243830
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); 132 133 // First, if this diagnostic is not in the main file, print out the 134 // "included from" lines. 135 emitIncludeStack(PLoc.getIncludeLoc(), 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 Level The diagnostic level of the message this stack pertains to. 188/// \param Loc The include location of the current file (not the diagnostic 189/// location). 190void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, 191 DiagnosticsEngine::Level Level, 192 const SourceManager &SM) { 193 // Skip redundant include stacks altogether. 194 if (LastIncludeLoc == Loc) 195 return; 196 LastIncludeLoc = Loc; 197 198 if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) 199 return; 200 201 emitIncludeStackRecursively(Loc, SM); 202} 203 204/// \brief Helper to recursivly walk up the include stack and print each layer 205/// on the way back down. 206void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, 207 const SourceManager &SM) { 208 if (Loc.isInvalid()) 209 return; 210 211 PresumedLoc PLoc = SM.getPresumedLoc(Loc); 212 if (PLoc.isInvalid()) 213 return; 214 215 // Emit the other include frames first. 216 emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM); 217 218 // Emit the inclusion text/note. 219 emitIncludeLocation(Loc, PLoc, SM); 220} 221 222// Helper function to fix up source ranges. It takes in an array of ranges, 223// and outputs an array of ranges where we want to draw the range highlighting 224// around the location specified by CaretLoc. 225// 226// To find locations which correspond to the caret, we crawl the macro caller 227// chain for the beginning and end of each range. If the caret location 228// is in a macro expansion, we search each chain for a location 229// in the same expansion as the caret; otherwise, we crawl to the top of 230// each chain. Two locations are part of the same macro expansion 231// iff the FileID is the same. 232static void mapDiagnosticRanges( 233 SourceLocation CaretLoc, 234 const SmallVectorImpl<CharSourceRange>& Ranges, 235 SmallVectorImpl<CharSourceRange>& SpellingRanges, 236 const SourceManager *SM) { 237 FileID CaretLocFileID = SM->getFileID(CaretLoc); 238 239 for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(), 240 E = Ranges.end(); 241 I != E; ++I) { 242 SourceLocation Begin = I->getBegin(), End = I->getEnd(); 243 bool IsTokenRange = I->isTokenRange(); 244 245 // Search the macro caller chain for the beginning of the range. 246 while (Begin.isMacroID() && SM->getFileID(Begin) != CaretLocFileID) 247 Begin = SM->getImmediateMacroCallerLoc(Begin); 248 249 // Search the macro caller chain for the beginning of the range. 250 while (End.isMacroID() && SM->getFileID(End) != CaretLocFileID) { 251 // The computation of the next End is an inlined version of 252 // getImmediateMacroCallerLoc, except it chooses the end of an 253 // expansion range. 254 if (SM->isMacroArgExpansion(End)) { 255 End = SM->getImmediateSpellingLoc(End); 256 } else { 257 End = SM->getImmediateExpansionRange(End).second; 258 } 259 } 260 261 // Return the spelling location of the beginning and end of the range. 262 Begin = SM->getSpellingLoc(Begin); 263 End = SM->getSpellingLoc(End); 264 SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End), 265 IsTokenRange)); 266 } 267} 268 269/// \brief Recursively emit notes for each macro expansion and caret 270/// diagnostics where appropriate. 271/// 272/// Walks up the macro expansion stack printing expansion notes, the code 273/// snippet, caret, underlines and FixItHint display as appropriate at each 274/// level. 275/// 276/// \param Loc The location for this caret. 277/// \param Level The diagnostic level currently being emitted. 278/// \param Ranges The underlined ranges for this code snippet. 279/// \param Hints The FixIt hints active for this diagnostic. 280/// \param MacroSkipEnd The depth to stop skipping macro expansions. 281/// \param OnMacroInst The current depth of the macro expansion stack. 282void DiagnosticRenderer::emitMacroExpansionsAndCarets( 283 SourceLocation Loc, 284 DiagnosticsEngine::Level Level, 285 SmallVectorImpl<CharSourceRange>& Ranges, 286 ArrayRef<FixItHint> Hints, 287 const SourceManager &SM, 288 unsigned &MacroDepth, 289 unsigned OnMacroInst) 290{ 291 assert(!Loc.isInvalid() && "must have a valid source location here"); 292 293 // If this is a file source location, directly emit the source snippet and 294 // caret line. Also record the macro depth reached. 295 if (Loc.isFileID()) { 296 // Map the ranges. 297 SmallVector<CharSourceRange, 4> SpellingRanges; 298 mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); 299 300 assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!"); 301 MacroDepth = OnMacroInst; 302 emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); 303 return; 304 } 305 // Otherwise recurse through each macro expansion layer. 306 307 // When processing macros, skip over the expansions leading up to 308 // a macro argument, and trace the argument's expansion stack instead. 309 Loc = SM.skipToMacroArgExpansion(Loc); 310 311 SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc); 312 313 emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth, 314 OnMacroInst + 1); 315 316 // Save the original location so we can find the spelling of the macro call. 317 SourceLocation MacroLoc = Loc; 318 319 // Map the location. 320 Loc = SM.getImmediateMacroCalleeLoc(Loc); 321 322 unsigned MacroSkipStart = 0, MacroSkipEnd = 0; 323 if (MacroDepth > DiagOpts->MacroBacktraceLimit && 324 DiagOpts->MacroBacktraceLimit != 0) { 325 MacroSkipStart = DiagOpts->MacroBacktraceLimit / 2 + 326 DiagOpts->MacroBacktraceLimit % 2; 327 MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2; 328 } 329 330 // Whether to suppress printing this macro expansion. 331 bool Suppressed = (OnMacroInst >= MacroSkipStart && 332 OnMacroInst < MacroSkipEnd); 333 334 if (Suppressed) { 335 // Tell the user that we've skipped contexts. 336 if (OnMacroInst == MacroSkipStart) { 337 SmallString<200> MessageStorage; 338 llvm::raw_svector_ostream Message(MessageStorage); 339 Message << "(skipping " << (MacroSkipEnd - MacroSkipStart) 340 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to " 341 "see all)"; 342 emitBasicNote(Message.str()); 343 } 344 return; 345 } 346 347 // Map the ranges. 348 SmallVector<CharSourceRange, 4> SpellingRanges; 349 mapDiagnosticRanges(MacroLoc, Ranges, SpellingRanges, &SM); 350 351 SmallString<100> MessageStorage; 352 llvm::raw_svector_ostream Message(MessageStorage); 353 Message << "expanded from macro '" 354 << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'"; 355 emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note, 356 Message.str(), 357 SpellingRanges, ArrayRef<FixItHint>(), &SM); 358} 359 360DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} 361 362void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc, 363 PresumedLoc PLoc, 364 const SourceManager &SM) { 365 // Generate a note indicating the include location. 366 SmallString<200> MessageStorage; 367 llvm::raw_svector_ostream Message(MessageStorage); 368 Message << "in file included from " << PLoc.getFilename() << ':' 369 << PLoc.getLine() << ":"; 370 emitNote(Loc, Message.str(), &SM); 371} 372 373void DiagnosticNoteRenderer::emitBasicNote(StringRef Message) { 374 emitNote(SourceLocation(), Message, 0); 375} 376