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