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