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