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/FileManager.h" 12 #include "clang/Basic/SourceManager.h" 13 #include "clang/Frontend/DiagnosticOptions.h" 14 #include "clang/Lex/Lexer.h" 15 #include "llvm/Support/MemoryBuffer.h" 16 #include "llvm/Support/raw_ostream.h" 17 #include "llvm/Support/ErrorHandling.h" 18 #include "llvm/ADT/SmallString.h" 19 #include <algorithm> 20 using namespace clang; 21 22 /// Look through spelling locations for a macro argument expansion, and 23 /// if found skip to it so that we can trace the argument rather than the macros 24 /// in which that argument is used. If no macro argument expansion is found, 25 /// don't skip anything and return the starting location. 26 static SourceLocation skipToMacroArgExpansion(const SourceManager &SM, 27 SourceLocation StartLoc) { 28 for (SourceLocation L = StartLoc; L.isMacroID(); 29 L = SM.getImmediateSpellingLoc(L)) { 30 if (SM.isMacroArgExpansion(L)) 31 return L; 32 } 33 34 // Otherwise just return initial location, there's nothing to skip. 35 return StartLoc; 36 } 37 38 /// Gets the location of the immediate macro caller, one level up the stack 39 /// toward the initial macro typed into the source. 40 static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM, 41 SourceLocation Loc) { 42 if (!Loc.isMacroID()) return Loc; 43 44 // When we have the location of (part of) an expanded parameter, its spelling 45 // location points to the argument as typed into the macro call, and 46 // therefore is used to locate the macro caller. 47 if (SM.isMacroArgExpansion(Loc)) 48 return SM.getImmediateSpellingLoc(Loc); 49 50 // Otherwise, the caller of the macro is located where this macro is 51 // expanded (while the spelling is part of the macro definition). 52 return SM.getImmediateExpansionRange(Loc).first; 53 } 54 55 /// Gets the location of the immediate macro callee, one level down the stack 56 /// toward the leaf macro. 57 static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM, 58 SourceLocation Loc) { 59 if (!Loc.isMacroID()) return Loc; 60 61 // When we have the location of (part of) an expanded parameter, its 62 // expansion location points to the unexpanded paramater reference within 63 // the macro definition (or callee). 64 if (SM.isMacroArgExpansion(Loc)) 65 return SM.getImmediateExpansionRange(Loc).first; 66 67 // Otherwise, the callee of the macro is located where this location was 68 // spelled inside the macro definition. 69 return SM.getImmediateSpellingLoc(Loc); 70 } 71 72 /// \brief Retrieve the name of the immediate macro expansion. 73 /// 74 /// This routine starts from a source location, and finds the name of the macro 75 /// responsible for its immediate expansion. It looks through any intervening 76 /// macro argument expansions to compute this. It returns a StringRef which 77 /// refers to the SourceManager-owned buffer of the source where that macro 78 /// name is spelled. Thus, the result shouldn't out-live that SourceManager. 79 /// 80 /// This differs from Lexer::getImmediateMacroName in that any macro argument 81 /// location will result in the topmost function macro that accepted it. 82 /// e.g. 83 /// \code 84 /// MAC1( MAC2(foo) ) 85 /// \endcode 86 /// for location of 'foo' token, this function will return "MAC1" while 87 /// Lexer::getImmediateMacroName will return "MAC2". 88 static StringRef getImmediateMacroName(SourceLocation Loc, 89 const SourceManager &SM, 90 const LangOptions &LangOpts) { 91 assert(Loc.isMacroID() && "Only reasonble to call this on macros"); 92 // Walk past macro argument expanions. 93 while (SM.isMacroArgExpansion(Loc)) 94 Loc = SM.getImmediateExpansionRange(Loc).first; 95 96 // Find the spelling location of the start of the non-argument expansion 97 // range. This is where the macro name was spelled in order to begin 98 // expanding this macro. 99 Loc = SM.getSpellingLoc(SM.getImmediateExpansionRange(Loc).first); 100 101 // Dig out the buffer where the macro name was spelled and the extents of the 102 // name so that we can render it into the expansion note. 103 std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc); 104 unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts); 105 StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first); 106 return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength); 107 } 108 109 /// Get the presumed location of a diagnostic message. This computes the 110 /// presumed location for the top of any macro backtrace when present. 111 static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM, 112 SourceLocation Loc) { 113 // This is a condensed form of the algorithm used by emitCaretDiagnostic to 114 // walk to the top of the macro call stack. 115 while (Loc.isMacroID()) { 116 Loc = skipToMacroArgExpansion(SM, Loc); 117 Loc = getImmediateMacroCallerLoc(SM, Loc); 118 } 119 120 return SM.getPresumedLoc(Loc); 121 } 122 123 DiagnosticRenderer::DiagnosticRenderer(const SourceManager &SM, 124 const LangOptions &LangOpts, 125 const DiagnosticOptions &DiagOpts) 126 : SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} 127 128 DiagnosticRenderer::~DiagnosticRenderer() {} 129 130 131 void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, 132 DiagnosticsEngine::Level Level, 133 StringRef Message, 134 ArrayRef<CharSourceRange> Ranges, 135 ArrayRef<FixItHint> FixItHints, 136 DiagOrStoredDiag D) { 137 138 beginDiagnostic(D, Level); 139 140 PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Loc); 141 142 // First, if this diagnostic is not in the main file, print out the 143 // "included from" lines. 144 emitIncludeStack(PLoc.getIncludeLoc(), Level); 145 146 // Next, emit the actual diagnostic message. 147 emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D); 148 149 // Only recurse if we have a valid location. 150 if (Loc.isValid()) { 151 // Get the ranges into a local array we can hack on. 152 SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), 153 Ranges.end()); 154 155 for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(), 156 E = FixItHints.end(); 157 I != E; ++I) 158 if (I->RemoveRange.isValid()) 159 MutableRanges.push_back(I->RemoveRange); 160 161 unsigned MacroDepth = 0; 162 emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints, 163 MacroDepth); 164 } 165 166 LastLoc = Loc; 167 LastLevel = Level; 168 169 endDiagnostic(D, Level); 170 } 171 172 173 void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { 174 emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(), 175 Diag.getRanges(), Diag.getFixIts(), 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). 190 void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, 191 DiagnosticsEngine::Level Level) { 192 // Skip redundant include stacks altogether. 193 if (LastIncludeLoc == Loc) 194 return; 195 LastIncludeLoc = Loc; 196 197 if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) 198 return; 199 200 emitIncludeStackRecursively(Loc); 201 } 202 203 /// \brief Helper to recursivly walk up the include stack and print each layer 204 /// on the way back down. 205 void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc) { 206 if (Loc.isInvalid()) 207 return; 208 209 PresumedLoc PLoc = SM.getPresumedLoc(Loc); 210 if (PLoc.isInvalid()) 211 return; 212 213 // Emit the other include frames first. 214 emitIncludeStackRecursively(PLoc.getIncludeLoc()); 215 216 // Emit the inclusion text/note. 217 emitIncludeLocation(Loc, PLoc); 218 } 219 220 /// \brief Recursively emit notes for each macro expansion and caret 221 /// diagnostics where appropriate. 222 /// 223 /// Walks up the macro expansion stack printing expansion notes, the code 224 /// snippet, caret, underlines and FixItHint display as appropriate at each 225 /// level. 226 /// 227 /// \param Loc The location for this caret. 228 /// \param Level The diagnostic level currently being emitted. 229 /// \param Ranges The underlined ranges for this code snippet. 230 /// \param Hints The FixIt hints active for this diagnostic. 231 /// \param MacroSkipEnd The depth to stop skipping macro expansions. 232 /// \param OnMacroInst The current depth of the macro expansion stack. 233 void DiagnosticRenderer::emitMacroExpansionsAndCarets( 234 SourceLocation Loc, 235 DiagnosticsEngine::Level Level, 236 SmallVectorImpl<CharSourceRange>& Ranges, 237 ArrayRef<FixItHint> Hints, 238 unsigned &MacroDepth, 239 unsigned OnMacroInst) 240 { 241 assert(!Loc.isInvalid() && "must have a valid source location here"); 242 243 // If this is a file source location, directly emit the source snippet and 244 // caret line. Also record the macro depth reached. 245 if (Loc.isFileID()) { 246 assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!"); 247 MacroDepth = OnMacroInst; 248 emitCodeContext(Loc, Level, Ranges, Hints); 249 return; 250 } 251 // Otherwise recurse through each macro expansion layer. 252 253 // When processing macros, skip over the expansions leading up to 254 // a macro argument, and trace the argument's expansion stack instead. 255 Loc = skipToMacroArgExpansion(SM, Loc); 256 257 SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc); 258 259 // FIXME: Map ranges? 260 emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, MacroDepth, 261 OnMacroInst + 1); 262 263 // Save the original location so we can find the spelling of the macro call. 264 SourceLocation MacroLoc = Loc; 265 266 // Map the location. 267 Loc = getImmediateMacroCalleeLoc(SM, Loc); 268 269 unsigned MacroSkipStart = 0, MacroSkipEnd = 0; 270 if (MacroDepth > DiagOpts.MacroBacktraceLimit && 271 DiagOpts.MacroBacktraceLimit != 0) { 272 MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 + 273 DiagOpts.MacroBacktraceLimit % 2; 274 MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2; 275 } 276 277 // Whether to suppress printing this macro expansion. 278 bool Suppressed = (OnMacroInst >= MacroSkipStart && 279 OnMacroInst < MacroSkipEnd); 280 281 // Map the ranges. 282 for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), 283 E = Ranges.end(); 284 I != E; ++I) { 285 SourceLocation Start = I->getBegin(), End = I->getEnd(); 286 if (Start.isMacroID()) 287 I->setBegin(getImmediateMacroCalleeLoc(SM, Start)); 288 if (End.isMacroID()) 289 I->setEnd(getImmediateMacroCalleeLoc(SM, End)); 290 } 291 292 if (Suppressed) { 293 // Tell the user that we've skipped contexts. 294 if (OnMacroInst == MacroSkipStart) { 295 SmallString<200> MessageStorage; 296 llvm::raw_svector_ostream Message(MessageStorage); 297 Message << "(skipping " << (MacroSkipEnd - MacroSkipStart) 298 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to " 299 "see all)"; 300 emitBasicNote(Message.str()); 301 } 302 return; 303 } 304 305 SmallString<100> MessageStorage; 306 llvm::raw_svector_ostream Message(MessageStorage); 307 Message << "expanded from macro '" 308 << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'"; 309 emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note, 310 Message.str(), 311 Ranges, ArrayRef<FixItHint>()); 312 } 313 314 DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} 315 316 void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc, 317 PresumedLoc PLoc) { 318 // Generate a note indicating the include location. 319 SmallString<200> MessageStorage; 320 llvm::raw_svector_ostream Message(MessageStorage); 321 Message << "in file included from " << PLoc.getFilename() << ':' 322 << PLoc.getLine() << ":"; 323 emitNote(Loc, Message.str()); 324 } 325 326 void DiagnosticNoteRenderer::emitBasicNote(StringRef Message) { 327 emitNote(SourceLocation(), Message); 328 } 329 330