DiagnosticRenderer.cpp revision 98cffc6b30dacd71434530fee368b1f7d03bd565
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>
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  if (!Loc.isValid())
130    // If we have no source location, just emit the diagnostic message.
131    emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D);
132  else {
133    // Get the ranges into a local array we can hack on.
134    SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
135                                                   Ranges.end());
136
137    llvm::SmallVector<FixItHint, 8> MergedFixits;
138    if (!FixItHints.empty()) {
139      mergeFixits(FixItHints, *SM, LangOpts, MergedFixits);
140      FixItHints = MergedFixits;
141    }
142
143    for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(),
144         E = FixItHints.end();
145         I != E; ++I)
146      if (I->RemoveRange.isValid())
147        MutableRanges.push_back(I->RemoveRange);
148
149    SourceLocation UnexpandedLoc = Loc;
150
151    // Perform the same walk as emitMacroExpansions, to find the ultimate
152    // expansion location for the diagnostic.
153    while (Loc.isMacroID())
154      Loc = SM->getImmediateMacroCallerLoc(Loc);
155
156    PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
157
158    // First, if this diagnostic is not in the main file, print out the
159    // "included from" lines.
160    emitIncludeStack(Loc, PLoc, Level, *SM);
161
162    // Next, emit the actual diagnostic message and caret.
163    emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D);
164    emitCaret(Loc, Level, MutableRanges, FixItHints, *SM);
165
166    // If this location is within a macro, walk from UnexpandedLoc up to Loc
167    // and produce a macro backtrace.
168    if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
169      unsigned MacroDepth = 0;
170      emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM,
171                          MacroDepth);
172    }
173  }
174
175  LastLoc = Loc;
176  LastLevel = Level;
177
178  endDiagnostic(D, Level);
179}
180
181
182void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
183  emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
184                 Diag.getRanges(), Diag.getFixIts(),
185                 Diag.getLocation().isValid() ? &Diag.getLocation().getManager()
186                                              : 0,
187                 &Diag);
188}
189
190/// \brief Prints an include stack when appropriate for a particular
191/// diagnostic level and location.
192///
193/// This routine handles all the logic of suppressing particular include
194/// stacks (such as those for notes) and duplicate include stacks when
195/// repeated warnings occur within the same file. It also handles the logic
196/// of customizing the formatting and display of the include stack.
197///
198/// \param Loc   The diagnostic location.
199/// \param PLoc  The presumed location of the diagnostic location.
200/// \param Level The diagnostic level of the message this stack pertains to.
201void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
202                                          PresumedLoc PLoc,
203                                          DiagnosticsEngine::Level Level,
204                                          const SourceManager &SM) {
205  SourceLocation IncludeLoc = PLoc.getIncludeLoc();
206
207  // Skip redundant include stacks altogether.
208  if (LastIncludeLoc == IncludeLoc)
209    return;
210
211  LastIncludeLoc = IncludeLoc;
212
213  if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
214    return;
215
216  if (IncludeLoc.isValid())
217    emitIncludeStackRecursively(IncludeLoc, SM);
218  else {
219    emitModuleBuildStack(SM);
220    emitImportStack(Loc, SM);
221  }
222}
223
224/// \brief Helper to recursivly walk up the include stack and print each layer
225/// on the way back down.
226void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
227                                                     const SourceManager &SM) {
228  if (Loc.isInvalid()) {
229    emitModuleBuildStack(SM);
230    return;
231  }
232
233  PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
234  if (PLoc.isInvalid())
235    return;
236
237  // If this source location was imported from a module, print the module
238  // import stack rather than the
239  // FIXME: We want submodule granularity here.
240  std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc);
241  if (Imported.first.isValid()) {
242    // This location was imported by a module. Emit the module import stack.
243    emitImportStackRecursively(Imported.first, Imported.second, SM);
244    return;
245  }
246
247  // Emit the other include frames first.
248  emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM);
249
250  // Emit the inclusion text/note.
251  emitIncludeLocation(Loc, PLoc, SM);
252}
253
254/// \brief Emit the module import stack associated with the current location.
255void DiagnosticRenderer::emitImportStack(SourceLocation Loc,
256                                         const SourceManager &SM) {
257  if (Loc.isInvalid()) {
258    emitModuleBuildStack(SM);
259    return;
260  }
261
262  std::pair<SourceLocation, StringRef> NextImportLoc
263    = SM.getModuleImportLoc(Loc);
264  emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
265}
266
267/// \brief Helper to recursivly walk up the import stack and print each layer
268/// on the way back down.
269void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
270                                                    StringRef ModuleName,
271                                                    const SourceManager &SM) {
272  if (Loc.isInvalid()) {
273    return;
274  }
275
276  PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
277  if (PLoc.isInvalid())
278    return;
279
280  // Emit the other import frames first.
281  std::pair<SourceLocation, StringRef> NextImportLoc
282    = SM.getModuleImportLoc(Loc);
283  emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
284
285  // Emit the inclusion text/note.
286  emitImportLocation(Loc, PLoc, ModuleName, SM);
287}
288
289/// \brief Emit the module build stack, for cases where a module is (re-)built
290/// on demand.
291void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
292  ModuleBuildStack Stack = SM.getModuleBuildStack();
293  for (unsigned I = 0, N = Stack.size(); I != N; ++I) {
294    const SourceManager &CurSM = Stack[I].second.getManager();
295    SourceLocation CurLoc = Stack[I].second;
296    emitBuildingModuleLocation(CurLoc,
297                               CurSM.getPresumedLoc(CurLoc,
298                                                    DiagOpts->ShowPresumedLoc),
299                               Stack[I].first,
300                               CurSM);
301  }
302}
303
304// Helper function to fix up source ranges.  It takes in an array of ranges,
305// and outputs an array of ranges where we want to draw the range highlighting
306// around the location specified by CaretLoc.
307//
308// To find locations which correspond to the caret, we crawl the macro caller
309// chain for the beginning and end of each range.  If the caret location
310// is in a macro expansion, we search each chain for a location
311// in the same expansion as the caret; otherwise, we crawl to the top of
312// each chain. Two locations are part of the same macro expansion
313// iff the FileID is the same.
314static void mapDiagnosticRanges(
315    SourceLocation CaretLoc,
316    ArrayRef<CharSourceRange> Ranges,
317    SmallVectorImpl<CharSourceRange> &SpellingRanges,
318    const SourceManager *SM) {
319  FileID CaretLocFileID = SM->getFileID(CaretLoc);
320
321  for (ArrayRef<CharSourceRange>::const_iterator I = Ranges.begin(),
322       E = Ranges.end();
323       I != E; ++I) {
324    SourceLocation Begin = I->getBegin(), End = I->getEnd();
325    bool IsTokenRange = I->isTokenRange();
326
327    FileID BeginFileID = SM->getFileID(Begin);
328    FileID EndFileID = SM->getFileID(End);
329
330    // Find the common parent for the beginning and end of the range.
331
332    // First, crawl the expansion chain for the beginning of the range.
333    llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
334    while (Begin.isMacroID() && BeginFileID != EndFileID) {
335      BeginLocsMap[BeginFileID] = Begin;
336      Begin = SM->getImmediateExpansionRange(Begin).first;
337      BeginFileID = SM->getFileID(Begin);
338    }
339
340    // Then, crawl the expansion chain for the end of the range.
341    if (BeginFileID != EndFileID) {
342      while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
343        End = SM->getImmediateExpansionRange(End).second;
344        EndFileID = SM->getFileID(End);
345      }
346      if (End.isMacroID()) {
347        Begin = BeginLocsMap[EndFileID];
348        BeginFileID = EndFileID;
349      }
350    }
351
352    while (Begin.isMacroID() && BeginFileID != CaretLocFileID) {
353      if (SM->isMacroArgExpansion(Begin)) {
354        Begin = SM->getImmediateSpellingLoc(Begin);
355        End = SM->getImmediateSpellingLoc(End);
356      } else {
357        Begin = SM->getImmediateExpansionRange(Begin).first;
358        End = SM->getImmediateExpansionRange(End).second;
359      }
360      BeginFileID = SM->getFileID(Begin);
361    }
362
363    // Return the spelling location of the beginning and end of the range.
364    Begin = SM->getSpellingLoc(Begin);
365    End = SM->getSpellingLoc(End);
366    SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End),
367                                             IsTokenRange));
368  }
369}
370
371void DiagnosticRenderer::emitCaret(SourceLocation Loc,
372                                   DiagnosticsEngine::Level Level,
373                                   ArrayRef<CharSourceRange> Ranges,
374                                   ArrayRef<FixItHint> Hints,
375                                   const SourceManager &SM) {
376  SmallVector<CharSourceRange, 4> SpellingRanges;
377  mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
378  emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
379}
380
381/// \brief Recursively emit notes for each macro expansion and caret
382/// diagnostics where appropriate.
383///
384/// Walks up the macro expansion stack printing expansion notes, the code
385/// snippet, caret, underlines and FixItHint display as appropriate at each
386/// level.
387///
388/// \param Loc The location for this caret.
389/// \param Level The diagnostic level currently being emitted.
390/// \param Ranges The underlined ranges for this code snippet.
391/// \param Hints The FixIt hints active for this diagnostic.
392/// \param MacroSkipEnd The depth to stop skipping macro expansions.
393/// \param OnMacroInst The current depth of the macro expansion stack.
394void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
395                                             DiagnosticsEngine::Level Level,
396                                             ArrayRef<CharSourceRange> Ranges,
397                                             ArrayRef<FixItHint> Hints,
398                                             const SourceManager &SM,
399                                             unsigned &MacroDepth,
400                                             unsigned OnMacroInst) {
401  assert(!Loc.isInvalid() && "must have a valid source location here");
402
403  // Walk up to the caller of this macro, and produce a backtrace down to there.
404  SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc);
405  if (OneLevelUp.isMacroID())
406    emitMacroExpansions(OneLevelUp, Level, Ranges, Hints, SM,
407                        MacroDepth, OnMacroInst + 1);
408  else
409    MacroDepth = OnMacroInst + 1;
410
411  unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
412  if (MacroDepth > DiagOpts->MacroBacktraceLimit &&
413      DiagOpts->MacroBacktraceLimit != 0) {
414    MacroSkipStart = DiagOpts->MacroBacktraceLimit / 2 +
415    DiagOpts->MacroBacktraceLimit % 2;
416    MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2;
417  }
418
419  // Whether to suppress printing this macro expansion.
420  bool Suppressed = (OnMacroInst >= MacroSkipStart &&
421                     OnMacroInst < MacroSkipEnd);
422
423  if (Suppressed) {
424    // Tell the user that we've skipped contexts.
425    if (OnMacroInst == MacroSkipStart) {
426      SmallString<200> MessageStorage;
427      llvm::raw_svector_ostream Message(MessageStorage);
428      Message << "(skipping " << (MacroSkipEnd - MacroSkipStart)
429              << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
430                 "see all)";
431      emitBasicNote(Message.str());
432    }
433    return;
434  }
435
436  // Find the spelling location for the macro definition. We must use the
437  // spelling location here to avoid emitting a macro bactrace for the note.
438  SourceLocation SpellingLoc = Loc;
439  // If this is the expansion of a macro argument, point the caret at the
440  // use of the argument in the definition of the macro, not the expansion.
441  if (SM.isMacroArgExpansion(Loc))
442    SpellingLoc = SM.getImmediateExpansionRange(Loc).first;
443  SpellingLoc = SM.getSpellingLoc(SpellingLoc);
444
445  // Map the ranges into the FileID of the diagnostic location.
446  SmallVector<CharSourceRange, 4> SpellingRanges;
447  mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
448
449  SmallString<100> MessageStorage;
450  llvm::raw_svector_ostream Message(MessageStorage);
451  Message << "expanded from macro '"
452          << getImmediateMacroName(Loc, SM, LangOpts) << "'";
453  emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note,
454                 Message.str(),
455                 SpellingRanges, ArrayRef<FixItHint>(), &SM);
456}
457
458DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {}
459
460void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc,
461                                                 PresumedLoc PLoc,
462                                                 const SourceManager &SM) {
463  // Generate a note indicating the include location.
464  SmallString<200> MessageStorage;
465  llvm::raw_svector_ostream Message(MessageStorage);
466  Message << "in file included from " << PLoc.getFilename() << ':'
467          << PLoc.getLine() << ":";
468  emitNote(Loc, Message.str(), &SM);
469}
470
471void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
472                                                PresumedLoc PLoc,
473                                                StringRef ModuleName,
474                                                const SourceManager &SM) {
475  // Generate a note indicating the include location.
476  SmallString<200> MessageStorage;
477  llvm::raw_svector_ostream Message(MessageStorage);
478  Message << "in module '" << ModuleName << "' imported from "
479          << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
480  emitNote(Loc, Message.str(), &SM);
481}
482
483void
484DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
485                                                   PresumedLoc PLoc,
486                                                   StringRef ModuleName,
487                                                   const SourceManager &SM) {
488  // Generate a note indicating the include location.
489  SmallString<200> MessageStorage;
490  llvm::raw_svector_ostream Message(MessageStorage);
491  Message << "while building module '" << ModuleName << "' imported from "
492          << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
493  emitNote(Loc, Message.str(), &SM);
494}
495
496
497void DiagnosticNoteRenderer::emitBasicNote(StringRef Message) {
498  emitNote(SourceLocation(), Message, 0);
499}
500