• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
24 using namespace clang;
25 
DiagnosticRenderer(const LangOptions & LangOpts,DiagnosticOptions * DiagOpts)26 DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts,
27                                        DiagnosticOptions *DiagOpts)
28   : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
29 
~DiagnosticRenderer()30 DiagnosticRenderer::~DiagnosticRenderer() {}
31 
32 namespace {
33 
34 class FixitReceiver : public edit::EditsReceiver {
35   SmallVectorImpl<FixItHint> &MergedFixits;
36 
37 public:
FixitReceiver(SmallVectorImpl<FixItHint> & MergedFixits)38   FixitReceiver(SmallVectorImpl<FixItHint> &MergedFixits)
39     : MergedFixits(MergedFixits) { }
insert(SourceLocation loc,StringRef text)40   void insert(SourceLocation loc, StringRef text) override {
41     MergedFixits.push_back(FixItHint::CreateInsertion(loc, text));
42   }
replace(CharSourceRange range,StringRef text)43   void replace(CharSourceRange range, StringRef text) override {
44     MergedFixits.push_back(FixItHint::CreateReplacement(range, text));
45   }
46 };
47 
48 }
49 
mergeFixits(ArrayRef<FixItHint> FixItHints,const SourceManager & SM,const LangOptions & LangOpts,SmallVectorImpl<FixItHint> & MergedFixits)50 static void mergeFixits(ArrayRef<FixItHint> FixItHints,
51                         const SourceManager &SM, const LangOptions &LangOpts,
52                         SmallVectorImpl<FixItHint> &MergedFixits) {
53   edit::Commit commit(SM, LangOpts);
54   for (ArrayRef<FixItHint>::const_iterator
55          I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) {
56     const FixItHint &Hint = *I;
57     if (Hint.CodeToInsert.empty()) {
58       if (Hint.InsertFromRange.isValid())
59         commit.insertFromRange(Hint.RemoveRange.getBegin(),
60                            Hint.InsertFromRange, /*afterToken=*/false,
61                            Hint.BeforePreviousInsertions);
62       else
63         commit.remove(Hint.RemoveRange);
64     } else {
65       if (Hint.RemoveRange.isTokenRange() ||
66           Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
67         commit.replace(Hint.RemoveRange, Hint.CodeToInsert);
68       else
69         commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
70                     /*afterToken=*/false, Hint.BeforePreviousInsertions);
71     }
72   }
73 
74   edit::EditedSource Editor(SM, LangOpts);
75   if (Editor.commit(commit)) {
76     FixitReceiver Rec(MergedFixits);
77     Editor.applyRewrites(Rec);
78   }
79 }
80 
emitDiagnostic(SourceLocation Loc,DiagnosticsEngine::Level Level,StringRef Message,ArrayRef<CharSourceRange> Ranges,ArrayRef<FixItHint> FixItHints,const SourceManager * SM,DiagOrStoredDiag D)81 void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
82                                         DiagnosticsEngine::Level Level,
83                                         StringRef Message,
84                                         ArrayRef<CharSourceRange> Ranges,
85                                         ArrayRef<FixItHint> FixItHints,
86                                         const SourceManager *SM,
87                                         DiagOrStoredDiag D) {
88   assert(SM || Loc.isInvalid());
89 
90   beginDiagnostic(D, Level);
91 
92   if (!Loc.isValid())
93     // If we have no source location, just emit the diagnostic message.
94     emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D);
95   else {
96     // Get the ranges into a local array we can hack on.
97     SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
98                                                    Ranges.end());
99 
100     SmallVector<FixItHint, 8> MergedFixits;
101     if (!FixItHints.empty()) {
102       mergeFixits(FixItHints, *SM, LangOpts, MergedFixits);
103       FixItHints = MergedFixits;
104     }
105 
106     for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(),
107          E = FixItHints.end();
108          I != E; ++I)
109       if (I->RemoveRange.isValid())
110         MutableRanges.push_back(I->RemoveRange);
111 
112     SourceLocation UnexpandedLoc = Loc;
113 
114     // Find the ultimate expansion location for the diagnostic.
115     Loc = SM->getFileLoc(Loc);
116 
117     PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
118 
119     // First, if this diagnostic is not in the main file, print out the
120     // "included from" lines.
121     emitIncludeStack(Loc, PLoc, Level, *SM);
122 
123     // Next, emit the actual diagnostic message and caret.
124     emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D);
125     emitCaret(Loc, Level, MutableRanges, FixItHints, *SM);
126 
127     // If this location is within a macro, walk from UnexpandedLoc up to Loc
128     // and produce a macro backtrace.
129     if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
130       emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM);
131     }
132   }
133 
134   LastLoc = Loc;
135   LastLevel = Level;
136 
137   endDiagnostic(D, Level);
138 }
139 
140 
emitStoredDiagnostic(StoredDiagnostic & Diag)141 void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
142   emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
143                  Diag.getRanges(), Diag.getFixIts(),
144                  Diag.getLocation().isValid() ? &Diag.getLocation().getManager()
145                                               : nullptr,
146                  &Diag);
147 }
148 
emitBasicNote(StringRef Message)149 void DiagnosticRenderer::emitBasicNote(StringRef Message) {
150   emitDiagnosticMessage(
151       SourceLocation(), PresumedLoc(), DiagnosticsEngine::Note, Message,
152       None, nullptr, DiagOrStoredDiag());
153 }
154 
155 /// \brief Prints an include stack when appropriate for a particular
156 /// diagnostic level and location.
157 ///
158 /// This routine handles all the logic of suppressing particular include
159 /// stacks (such as those for notes) and duplicate include stacks when
160 /// repeated warnings occur within the same file. It also handles the logic
161 /// of customizing the formatting and display of the include stack.
162 ///
163 /// \param Loc   The diagnostic location.
164 /// \param PLoc  The presumed location of the diagnostic location.
165 /// \param Level The diagnostic level of the message this stack pertains to.
emitIncludeStack(SourceLocation Loc,PresumedLoc PLoc,DiagnosticsEngine::Level Level,const SourceManager & SM)166 void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
167                                           PresumedLoc PLoc,
168                                           DiagnosticsEngine::Level Level,
169                                           const SourceManager &SM) {
170   SourceLocation IncludeLoc =
171       PLoc.isInvalid() ? SourceLocation() : PLoc.getIncludeLoc();
172 
173   // Skip redundant include stacks altogether.
174   if (LastIncludeLoc == IncludeLoc)
175     return;
176 
177   LastIncludeLoc = IncludeLoc;
178 
179   if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
180     return;
181 
182   if (IncludeLoc.isValid())
183     emitIncludeStackRecursively(IncludeLoc, SM);
184   else {
185     emitModuleBuildStack(SM);
186     emitImportStack(Loc, SM);
187   }
188 }
189 
190 /// \brief Helper to recursivly walk up the include stack and print each layer
191 /// on the way back down.
emitIncludeStackRecursively(SourceLocation Loc,const SourceManager & SM)192 void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
193                                                      const SourceManager &SM) {
194   if (Loc.isInvalid()) {
195     emitModuleBuildStack(SM);
196     return;
197   }
198 
199   PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
200   if (PLoc.isInvalid())
201     return;
202 
203   // If this source location was imported from a module, print the module
204   // import stack rather than the
205   // FIXME: We want submodule granularity here.
206   std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc);
207   if (!Imported.second.empty()) {
208     // This location was imported by a module. Emit the module import stack.
209     emitImportStackRecursively(Imported.first, Imported.second, SM);
210     return;
211   }
212 
213   // Emit the other include frames first.
214   emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM);
215 
216   // Emit the inclusion text/note.
217   emitIncludeLocation(Loc, PLoc, SM);
218 }
219 
220 /// \brief Emit the module import stack associated with the current location.
emitImportStack(SourceLocation Loc,const SourceManager & SM)221 void DiagnosticRenderer::emitImportStack(SourceLocation Loc,
222                                          const SourceManager &SM) {
223   if (Loc.isInvalid()) {
224     emitModuleBuildStack(SM);
225     return;
226   }
227 
228   std::pair<SourceLocation, StringRef> NextImportLoc
229     = SM.getModuleImportLoc(Loc);
230   emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
231 }
232 
233 /// \brief Helper to recursivly walk up the import stack and print each layer
234 /// on the way back down.
emitImportStackRecursively(SourceLocation Loc,StringRef ModuleName,const SourceManager & SM)235 void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
236                                                     StringRef ModuleName,
237                                                     const SourceManager &SM) {
238   if (ModuleName.empty()) {
239     return;
240   }
241 
242   PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
243 
244   // Emit the other import frames first.
245   std::pair<SourceLocation, StringRef> NextImportLoc
246     = SM.getModuleImportLoc(Loc);
247   emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
248 
249   // Emit the inclusion text/note.
250   emitImportLocation(Loc, PLoc, ModuleName, SM);
251 }
252 
253 /// \brief Emit the module build stack, for cases where a module is (re-)built
254 /// on demand.
emitModuleBuildStack(const SourceManager & SM)255 void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
256   ModuleBuildStack Stack = SM.getModuleBuildStack();
257   for (unsigned I = 0, N = Stack.size(); I != N; ++I) {
258     const SourceManager &CurSM = Stack[I].second.getManager();
259     SourceLocation CurLoc = Stack[I].second;
260     emitBuildingModuleLocation(CurLoc,
261                                CurSM.getPresumedLoc(CurLoc,
262                                                     DiagOpts->ShowPresumedLoc),
263                                Stack[I].first,
264                                CurSM);
265   }
266 }
267 
268 /// A recursive function to trace all possible backtrace locations
269 /// to match the \p CaretLocFileID.
270 static SourceLocation
retrieveMacroLocation(SourceLocation Loc,FileID MacroFileID,FileID CaretFileID,const SmallVectorImpl<FileID> & CommonArgExpansions,bool IsBegin,const SourceManager * SM)271 retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID,
272                       FileID CaretFileID,
273                       const SmallVectorImpl<FileID> &CommonArgExpansions,
274                       bool IsBegin, const SourceManager *SM) {
275   assert(SM->getFileID(Loc) == MacroFileID);
276   if (MacroFileID == CaretFileID)
277     return Loc;
278   if (!Loc.isMacroID())
279     return SourceLocation();
280 
281   SourceLocation MacroLocation, MacroArgLocation;
282 
283   if (SM->isMacroArgExpansion(Loc)) {
284     // Only look at the immediate spelling location of this macro argument if
285     // the other location in the source range is also present in that expansion.
286     if (std::binary_search(CommonArgExpansions.begin(),
287                            CommonArgExpansions.end(), MacroFileID))
288       MacroLocation = SM->getImmediateSpellingLoc(Loc);
289     MacroArgLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first
290                                : SM->getImmediateExpansionRange(Loc).second;
291   } else {
292     MacroLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first
293                             : SM->getImmediateExpansionRange(Loc).second;
294     MacroArgLocation = SM->getImmediateSpellingLoc(Loc);
295   }
296 
297   if (MacroLocation.isValid()) {
298     MacroFileID = SM->getFileID(MacroLocation);
299     MacroLocation =
300         retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID,
301                               CommonArgExpansions, IsBegin, SM);
302     if (MacroLocation.isValid())
303       return MacroLocation;
304   }
305 
306   MacroFileID = SM->getFileID(MacroArgLocation);
307   return retrieveMacroLocation(MacroArgLocation, MacroFileID, CaretFileID,
308                                CommonArgExpansions, IsBegin, SM);
309 }
310 
311 /// Walk up the chain of macro expansions and collect the FileIDs identifying the
312 /// expansions.
getMacroArgExpansionFileIDs(SourceLocation Loc,SmallVectorImpl<FileID> & IDs,bool IsBegin,const SourceManager * SM)313 static void getMacroArgExpansionFileIDs(SourceLocation Loc,
314                                         SmallVectorImpl<FileID> &IDs,
315                                         bool IsBegin, const SourceManager *SM) {
316   while (Loc.isMacroID()) {
317     if (SM->isMacroArgExpansion(Loc)) {
318       IDs.push_back(SM->getFileID(Loc));
319       Loc = SM->getImmediateSpellingLoc(Loc);
320     } else {
321       auto ExpRange = SM->getImmediateExpansionRange(Loc);
322       Loc = IsBegin ? ExpRange.first : ExpRange.second;
323     }
324   }
325 }
326 
327 /// Collect the expansions of the begin and end locations and compute the set
328 /// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions.
computeCommonMacroArgExpansionFileIDs(SourceLocation Begin,SourceLocation End,const SourceManager * SM,SmallVectorImpl<FileID> & CommonArgExpansions)329 static void computeCommonMacroArgExpansionFileIDs(
330     SourceLocation Begin, SourceLocation End, const SourceManager *SM,
331     SmallVectorImpl<FileID> &CommonArgExpansions) {
332   SmallVector<FileID, 4> BeginArgExpansions;
333   SmallVector<FileID, 4> EndArgExpansions;
334   getMacroArgExpansionFileIDs(Begin, BeginArgExpansions, /*IsBegin=*/true, SM);
335   getMacroArgExpansionFileIDs(End, EndArgExpansions, /*IsBegin=*/false, SM);
336   std::sort(BeginArgExpansions.begin(), BeginArgExpansions.end());
337   std::sort(EndArgExpansions.begin(), EndArgExpansions.end());
338   std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
339                         EndArgExpansions.begin(), EndArgExpansions.end(),
340                         std::back_inserter(CommonArgExpansions));
341 }
342 
343 // Helper function to fix up source ranges.  It takes in an array of ranges,
344 // and outputs an array of ranges where we want to draw the range highlighting
345 // around the location specified by CaretLoc.
346 //
347 // To find locations which correspond to the caret, we crawl the macro caller
348 // chain for the beginning and end of each range.  If the caret location
349 // is in a macro expansion, we search each chain for a location
350 // in the same expansion as the caret; otherwise, we crawl to the top of
351 // each chain. Two locations are part of the same macro expansion
352 // iff the FileID is the same.
mapDiagnosticRanges(SourceLocation CaretLoc,ArrayRef<CharSourceRange> Ranges,SmallVectorImpl<CharSourceRange> & SpellingRanges,const SourceManager * SM)353 static void mapDiagnosticRanges(
354     SourceLocation CaretLoc,
355     ArrayRef<CharSourceRange> Ranges,
356     SmallVectorImpl<CharSourceRange> &SpellingRanges,
357     const SourceManager *SM) {
358   FileID CaretLocFileID = SM->getFileID(CaretLoc);
359 
360   for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
361     if (I->isInvalid()) continue;
362 
363     SourceLocation Begin = I->getBegin(), End = I->getEnd();
364     bool IsTokenRange = I->isTokenRange();
365 
366     FileID BeginFileID = SM->getFileID(Begin);
367     FileID EndFileID = SM->getFileID(End);
368 
369     // Find the common parent for the beginning and end of the range.
370 
371     // First, crawl the expansion chain for the beginning of the range.
372     llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
373     while (Begin.isMacroID() && BeginFileID != EndFileID) {
374       BeginLocsMap[BeginFileID] = Begin;
375       Begin = SM->getImmediateExpansionRange(Begin).first;
376       BeginFileID = SM->getFileID(Begin);
377     }
378 
379     // Then, crawl the expansion chain for the end of the range.
380     if (BeginFileID != EndFileID) {
381       while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
382         End = SM->getImmediateExpansionRange(End).second;
383         EndFileID = SM->getFileID(End);
384       }
385       if (End.isMacroID()) {
386         Begin = BeginLocsMap[EndFileID];
387         BeginFileID = EndFileID;
388       }
389     }
390 
391     // Do the backtracking.
392     SmallVector<FileID, 4> CommonArgExpansions;
393     computeCommonMacroArgExpansionFileIDs(Begin, End, SM, CommonArgExpansions);
394     Begin = retrieveMacroLocation(Begin, BeginFileID, CaretLocFileID,
395                                   CommonArgExpansions, /*IsBegin=*/true, SM);
396     End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID,
397                                 CommonArgExpansions, /*IsBegin=*/false, SM);
398     if (Begin.isInvalid() || End.isInvalid()) continue;
399 
400     // Return the spelling location of the beginning and end of the range.
401     Begin = SM->getSpellingLoc(Begin);
402     End = SM->getSpellingLoc(End);
403 
404     SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End),
405                                              IsTokenRange));
406   }
407 }
408 
emitCaret(SourceLocation Loc,DiagnosticsEngine::Level Level,ArrayRef<CharSourceRange> Ranges,ArrayRef<FixItHint> Hints,const SourceManager & SM)409 void DiagnosticRenderer::emitCaret(SourceLocation Loc,
410                                    DiagnosticsEngine::Level Level,
411                                    ArrayRef<CharSourceRange> Ranges,
412                                    ArrayRef<FixItHint> Hints,
413                                    const SourceManager &SM) {
414   SmallVector<CharSourceRange, 4> SpellingRanges;
415   mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
416   emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
417 }
418 
419 /// \brief A helper function for emitMacroExpansion to print the
420 /// macro expansion message
emitSingleMacroExpansion(SourceLocation Loc,DiagnosticsEngine::Level Level,ArrayRef<CharSourceRange> Ranges,const SourceManager & SM)421 void DiagnosticRenderer::emitSingleMacroExpansion(
422     SourceLocation Loc,
423     DiagnosticsEngine::Level Level,
424     ArrayRef<CharSourceRange> Ranges,
425     const SourceManager &SM) {
426   // Find the spelling location for the macro definition. We must use the
427   // spelling location here to avoid emitting a macro backtrace for the note.
428   SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
429 
430   // Map the ranges into the FileID of the diagnostic location.
431   SmallVector<CharSourceRange, 4> SpellingRanges;
432   mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
433 
434   SmallString<100> MessageStorage;
435   llvm::raw_svector_ostream Message(MessageStorage);
436   StringRef MacroName =
437       Lexer::getImmediateMacroNameForDiagnostics(Loc, SM, LangOpts);
438   if (MacroName.empty())
439     Message << "expanded from here";
440   else
441     Message << "expanded from macro '" << MacroName << "'";
442 
443   emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(),
444                  SpellingRanges, None, &SM);
445 }
446 
447 /// Check that the macro argument location of Loc starts with ArgumentLoc.
448 /// The starting location of the macro expansions is used to differeniate
449 /// different macro expansions.
checkLocForMacroArgExpansion(SourceLocation Loc,const SourceManager & SM,SourceLocation ArgumentLoc)450 static bool checkLocForMacroArgExpansion(SourceLocation Loc,
451                                          const SourceManager &SM,
452                                          SourceLocation ArgumentLoc) {
453   SourceLocation MacroLoc;
454   if (SM.isMacroArgExpansion(Loc, &MacroLoc)) {
455     if (ArgumentLoc == MacroLoc) return true;
456   }
457 
458   return false;
459 }
460 
461 /// Check if all the locations in the range have the same macro argument
462 /// expansion, and that that expansion starts with ArgumentLoc.
checkRangeForMacroArgExpansion(CharSourceRange Range,const SourceManager & SM,SourceLocation ArgumentLoc)463 static bool checkRangeForMacroArgExpansion(CharSourceRange Range,
464                                            const SourceManager &SM,
465                                            SourceLocation ArgumentLoc) {
466   SourceLocation BegLoc = Range.getBegin(), EndLoc = Range.getEnd();
467   while (BegLoc != EndLoc) {
468     if (!checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc))
469       return false;
470     BegLoc.getLocWithOffset(1);
471   }
472 
473   return checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc);
474 }
475 
476 /// A helper function to check if the current ranges are all inside the same
477 /// macro argument expansion as Loc.
checkRangesForMacroArgExpansion(SourceLocation Loc,ArrayRef<CharSourceRange> Ranges,const SourceManager & SM)478 static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
479                                             ArrayRef<CharSourceRange> Ranges,
480                                             const SourceManager &SM) {
481   assert(Loc.isMacroID() && "Must be a macro expansion!");
482 
483   SmallVector<CharSourceRange, 4> SpellingRanges;
484   mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
485 
486   /// Count all valid ranges.
487   unsigned ValidCount = 0;
488   for (auto I : Ranges)
489     if (I.isValid()) ValidCount++;
490 
491   if (ValidCount > SpellingRanges.size())
492     return false;
493 
494   /// To store the source location of the argument location.
495   SourceLocation ArgumentLoc;
496 
497   /// Set the ArgumentLoc to the beginning location of the expansion of Loc
498   /// so to check if the ranges expands to the same beginning location.
499   if (!SM.isMacroArgExpansion(Loc,&ArgumentLoc))
500     return false;
501 
502   for (auto I = SpellingRanges.begin(), E = SpellingRanges.end(); I != E; ++I) {
503     if (!checkRangeForMacroArgExpansion(*I, SM, ArgumentLoc))
504       return false;
505   }
506 
507   return true;
508 }
509 
510 /// \brief Recursively emit notes for each macro expansion and caret
511 /// diagnostics where appropriate.
512 ///
513 /// Walks up the macro expansion stack printing expansion notes, the code
514 /// snippet, caret, underlines and FixItHint display as appropriate at each
515 /// level.
516 ///
517 /// \param Loc The location for this caret.
518 /// \param Level The diagnostic level currently being emitted.
519 /// \param Ranges The underlined ranges for this code snippet.
520 /// \param Hints The FixIt hints active for this diagnostic.
emitMacroExpansions(SourceLocation Loc,DiagnosticsEngine::Level Level,ArrayRef<CharSourceRange> Ranges,ArrayRef<FixItHint> Hints,const SourceManager & SM)521 void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
522                                              DiagnosticsEngine::Level Level,
523                                              ArrayRef<CharSourceRange> Ranges,
524                                              ArrayRef<FixItHint> Hints,
525                                              const SourceManager &SM) {
526   assert(Loc.isValid() && "must have a valid source location here");
527 
528   // Produce a stack of macro backtraces.
529   SmallVector<SourceLocation, 8> LocationStack;
530   unsigned IgnoredEnd = 0;
531   while (Loc.isMacroID()) {
532     // If this is the expansion of a macro argument, point the caret at the
533     // use of the argument in the definition of the macro, not the expansion.
534     if (SM.isMacroArgExpansion(Loc))
535       LocationStack.push_back(SM.getImmediateExpansionRange(Loc).first);
536     else
537       LocationStack.push_back(Loc);
538 
539     if (checkRangesForMacroArgExpansion(Loc, Ranges, SM))
540       IgnoredEnd = LocationStack.size();
541 
542     Loc = SM.getImmediateMacroCallerLoc(Loc);
543 
544     // Once the location no longer points into a macro, try stepping through
545     // the last found location.  This sometimes produces additional useful
546     // backtraces.
547     if (Loc.isFileID())
548       Loc = SM.getImmediateMacroCallerLoc(LocationStack.back());
549     assert(Loc.isValid() && "must have a valid source location here");
550   }
551 
552   LocationStack.erase(LocationStack.begin(),
553                       LocationStack.begin() + IgnoredEnd);
554 
555   unsigned MacroDepth = LocationStack.size();
556   unsigned MacroLimit = DiagOpts->MacroBacktraceLimit;
557   if (MacroDepth <= MacroLimit || MacroLimit == 0) {
558     for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
559          I != E; ++I)
560       emitSingleMacroExpansion(*I, Level, Ranges, SM);
561     return;
562   }
563 
564   unsigned MacroStartMessages = MacroLimit / 2;
565   unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
566 
567   for (auto I = LocationStack.rbegin(),
568             E = LocationStack.rbegin() + MacroStartMessages;
569        I != E; ++I)
570     emitSingleMacroExpansion(*I, Level, Ranges, SM);
571 
572   SmallString<200> MessageStorage;
573   llvm::raw_svector_ostream Message(MessageStorage);
574   Message << "(skipping " << (MacroDepth - MacroLimit)
575           << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
576              "see all)";
577   emitBasicNote(Message.str());
578 
579   for (auto I = LocationStack.rend() - MacroEndMessages,
580             E = LocationStack.rend();
581        I != E; ++I)
582     emitSingleMacroExpansion(*I, Level, Ranges, SM);
583 }
584 
~DiagnosticNoteRenderer()585 DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {}
586 
emitIncludeLocation(SourceLocation Loc,PresumedLoc PLoc,const SourceManager & SM)587 void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc,
588                                                  PresumedLoc PLoc,
589                                                  const SourceManager &SM) {
590   // Generate a note indicating the include location.
591   SmallString<200> MessageStorage;
592   llvm::raw_svector_ostream Message(MessageStorage);
593   Message << "in file included from " << PLoc.getFilename() << ':'
594           << PLoc.getLine() << ":";
595   emitNote(Loc, Message.str(), &SM);
596 }
597 
emitImportLocation(SourceLocation Loc,PresumedLoc PLoc,StringRef ModuleName,const SourceManager & SM)598 void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
599                                                 PresumedLoc PLoc,
600                                                 StringRef ModuleName,
601                                                 const SourceManager &SM) {
602   // Generate a note indicating the include location.
603   SmallString<200> MessageStorage;
604   llvm::raw_svector_ostream Message(MessageStorage);
605   Message << "in module '" << ModuleName;
606   if (PLoc.isValid())
607     Message << "' imported from " << PLoc.getFilename() << ':'
608             << PLoc.getLine();
609   Message << ":";
610   emitNote(Loc, Message.str(), &SM);
611 }
612 
613 void
emitBuildingModuleLocation(SourceLocation Loc,PresumedLoc PLoc,StringRef ModuleName,const SourceManager & SM)614 DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
615                                                    PresumedLoc PLoc,
616                                                    StringRef ModuleName,
617                                                    const SourceManager &SM) {
618   // Generate a note indicating the include location.
619   SmallString<200> MessageStorage;
620   llvm::raw_svector_ostream Message(MessageStorage);
621   if (PLoc.isValid())
622     Message << "while building module '" << ModuleName << "' imported from "
623             << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
624   else
625     Message << "while building module '" << ModuleName << "':";
626   emitNote(Loc, Message.str(), &SM);
627 }
628