1 //===- DiagnosticRenderer.cpp - Diagnostic Pretty-Printing ----------------===//
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
7 //===----------------------------------------------------------------------===//
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"
30 using namespace clang
;
32 DiagnosticRenderer::DiagnosticRenderer(const LangOptions
&LangOpts
,
33 DiagnosticOptions
*DiagOpts
)
34 : LangOpts(LangOpts
), DiagOpts(DiagOpts
), LastLevel() {}
36 DiagnosticRenderer::~DiagnosticRenderer() = default;
40 class FixitReceiver
: public edit::EditsReceiver
{
41 SmallVectorImpl
<FixItHint
> &MergedFixits
;
44 FixitReceiver(SmallVectorImpl
<FixItHint
> &MergedFixits
)
45 : MergedFixits(MergedFixits
) {}
47 void insert(SourceLocation loc
, StringRef text
) override
{
48 MergedFixits
.push_back(FixItHint::CreateInsertion(loc
, text
));
51 void replace(CharSourceRange range
, StringRef text
) override
{
52 MergedFixits
.push_back(FixItHint::CreateReplacement(range
, text
));
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
);
69 commit
.remove(Hint
.RemoveRange
);
71 if (Hint
.RemoveRange
.isTokenRange() ||
72 Hint
.RemoveRange
.getBegin() != Hint
.RemoveRange
.getEnd())
73 commit
.replace(Hint
.RemoveRange
, Hint
.CodeToInsert
);
75 commit
.insert(Hint
.RemoveRange
.getBegin(), Hint
.CodeToInsert
,
76 /*afterToken=*/false, Hint
.BeforePreviousInsertions
);
79 edit::EditedSource
Editor(SM
, LangOpts
);
80 if (Editor
.commit(commit
)) {
81 FixitReceiver
Rec(MergedFixits
);
82 Editor
.applyRewrites(Rec
);
86 void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc
,
87 DiagnosticsEngine::Level Level
,
89 ArrayRef
<CharSourceRange
> Ranges
,
90 ArrayRef
<FixItHint
> FixItHints
,
92 assert(Loc
.hasManager() || Loc
.isInvalid());
94 beginDiagnostic(D
, Level
);
97 // If we have no source location, just emit the diagnostic message.
98 emitDiagnosticMessage(Loc
, PresumedLoc(), Level
, Message
, Ranges
, D
);
100 // Get the ranges into a local array we can hack on.
101 SmallVector
<CharSourceRange
, 20> MutableRanges(Ranges
);
103 SmallVector
<FixItHint
, 8> MergedFixits
;
104 if (!FixItHints
.empty()) {
105 mergeFixits(FixItHints
, Loc
.getManager(), LangOpts
, MergedFixits
);
106 FixItHints
= MergedFixits
;
109 for (const auto &Hint
: FixItHints
)
110 if (Hint
.RemoveRange
.isValid())
111 MutableRanges
.push_back(Hint
.RemoveRange
);
113 FullSourceLoc UnexpandedLoc
= Loc
;
115 // Find the ultimate expansion location for the diagnostic.
116 Loc
= Loc
.getFileLoc();
118 PresumedLoc PLoc
= Loc
.getPresumedLoc(DiagOpts
->ShowPresumedLoc
);
120 // First, if this diagnostic is not in the main file, print out the
121 // "included from" lines.
122 emitIncludeStack(Loc
, PLoc
, Level
);
124 // Next, emit the actual diagnostic message and caret.
125 emitDiagnosticMessage(Loc
, PLoc
, Level
, Message
, Ranges
, D
);
126 emitCaret(Loc
, Level
, MutableRanges
, FixItHints
);
128 // If this location is within a macro, walk from UnexpandedLoc up to Loc
129 // and produce a macro backtrace.
130 if (UnexpandedLoc
.isValid() && UnexpandedLoc
.isMacroID()) {
131 emitMacroExpansions(UnexpandedLoc
, Level
, MutableRanges
, FixItHints
);
138 endDiagnostic(D
, Level
);
141 void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic
&Diag
) {
142 emitDiagnostic(Diag
.getLocation(), Diag
.getLevel(), Diag
.getMessage(),
143 Diag
.getRanges(), Diag
.getFixIts(),
147 void DiagnosticRenderer::emitBasicNote(StringRef Message
) {
148 emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note
,
149 Message
, {}, DiagOrStoredDiag());
152 /// Prints an include stack when appropriate for a particular
153 /// diagnostic level and location.
155 /// This routine handles all the logic of suppressing particular include
156 /// stacks (such as those for notes) and duplicate include stacks when
157 /// repeated warnings occur within the same file. It also handles the logic
158 /// of customizing the formatting and display of the include stack.
160 /// \param Loc The diagnostic location.
161 /// \param PLoc The presumed location of the diagnostic location.
162 /// \param Level The diagnostic level of the message this stack pertains to.
163 void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc
, PresumedLoc PLoc
,
164 DiagnosticsEngine::Level Level
) {
165 FullSourceLoc IncludeLoc
=
166 PLoc
.isInvalid() ? FullSourceLoc()
167 : FullSourceLoc(PLoc
.getIncludeLoc(), Loc
.getManager());
169 // Skip redundant include stacks altogether.
170 if (LastIncludeLoc
== IncludeLoc
)
173 LastIncludeLoc
= IncludeLoc
;
175 if (!DiagOpts
->ShowNoteIncludeStack
&& Level
== DiagnosticsEngine::Note
)
178 if (IncludeLoc
.isValid())
179 emitIncludeStackRecursively(IncludeLoc
);
181 emitModuleBuildStack(Loc
.getManager());
182 emitImportStack(Loc
);
186 /// Helper to recursively walk up the include stack and print each layer
187 /// on the way back down.
188 void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc
) {
189 if (Loc
.isInvalid()) {
190 emitModuleBuildStack(Loc
.getManager());
194 PresumedLoc PLoc
= Loc
.getPresumedLoc(DiagOpts
->ShowPresumedLoc
);
195 if (PLoc
.isInvalid())
198 // If this source location was imported from a module, print the module
199 // import stack rather than the
200 // FIXME: We want submodule granularity here.
201 std::pair
<FullSourceLoc
, StringRef
> Imported
= Loc
.getModuleImportLoc();
202 if (!Imported
.second
.empty()) {
203 // This location was imported by a module. Emit the module import stack.
204 emitImportStackRecursively(Imported
.first
, Imported
.second
);
208 // Emit the other include frames first.
209 emitIncludeStackRecursively(
210 FullSourceLoc(PLoc
.getIncludeLoc(), Loc
.getManager()));
212 // Emit the inclusion text/note.
213 emitIncludeLocation(Loc
, PLoc
);
216 /// Emit the module import stack associated with the current location.
217 void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc
) {
218 if (Loc
.isInvalid()) {
219 emitModuleBuildStack(Loc
.getManager());
223 std::pair
<FullSourceLoc
, StringRef
> NextImportLoc
= Loc
.getModuleImportLoc();
224 emitImportStackRecursively(NextImportLoc
.first
, NextImportLoc
.second
);
227 /// Helper to recursively walk up the import stack and print each layer
228 /// on the way back down.
229 void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc
,
230 StringRef ModuleName
) {
231 if (ModuleName
.empty()) {
235 PresumedLoc PLoc
= Loc
.getPresumedLoc(DiagOpts
->ShowPresumedLoc
);
237 // Emit the other import frames first.
238 std::pair
<FullSourceLoc
, StringRef
> NextImportLoc
= Loc
.getModuleImportLoc();
239 emitImportStackRecursively(NextImportLoc
.first
, NextImportLoc
.second
);
241 // Emit the inclusion text/note.
242 emitImportLocation(Loc
, PLoc
, ModuleName
);
245 /// Emit the module build stack, for cases where a module is (re-)built
247 void DiagnosticRenderer::emitModuleBuildStack(const SourceManager
&SM
) {
248 ModuleBuildStack Stack
= SM
.getModuleBuildStack();
249 for (const auto &I
: Stack
) {
250 emitBuildingModuleLocation(I
.second
, I
.second
.getPresumedLoc(
251 DiagOpts
->ShowPresumedLoc
),
256 /// A recursive function to trace all possible backtrace locations
257 /// to match the \p CaretLocFileID.
258 static SourceLocation
259 retrieveMacroLocation(SourceLocation Loc
, FileID MacroFileID
,
261 const SmallVectorImpl
<FileID
> &CommonArgExpansions
,
262 bool IsBegin
, const SourceManager
*SM
,
263 bool &IsTokenRange
) {
264 assert(SM
->getFileID(Loc
) == MacroFileID
);
265 if (MacroFileID
== CaretFileID
)
267 if (!Loc
.isMacroID())
270 CharSourceRange MacroRange
, MacroArgRange
;
272 if (SM
->isMacroArgExpansion(Loc
)) {
273 // Only look at the immediate spelling location of this macro argument if
274 // the other location in the source range is also present in that expansion.
275 if (std::binary_search(CommonArgExpansions
.begin(),
276 CommonArgExpansions
.end(), MacroFileID
))
278 CharSourceRange(SM
->getImmediateSpellingLoc(Loc
), IsTokenRange
);
279 MacroArgRange
= SM
->getImmediateExpansionRange(Loc
);
281 MacroRange
= SM
->getImmediateExpansionRange(Loc
);
283 CharSourceRange(SM
->getImmediateSpellingLoc(Loc
), IsTokenRange
);
286 SourceLocation MacroLocation
=
287 IsBegin
? MacroRange
.getBegin() : MacroRange
.getEnd();
288 if (MacroLocation
.isValid()) {
289 MacroFileID
= SM
->getFileID(MacroLocation
);
290 bool TokenRange
= IsBegin
? IsTokenRange
: MacroRange
.isTokenRange();
292 retrieveMacroLocation(MacroLocation
, MacroFileID
, CaretFileID
,
293 CommonArgExpansions
, IsBegin
, SM
, TokenRange
);
294 if (MacroLocation
.isValid()) {
295 IsTokenRange
= TokenRange
;
296 return MacroLocation
;
300 // If we moved the end of the range to an expansion location, we now have
301 // a range of the same kind as the expansion range.
303 IsTokenRange
= MacroArgRange
.isTokenRange();
305 SourceLocation MacroArgLocation
=
306 IsBegin
? MacroArgRange
.getBegin() : MacroArgRange
.getEnd();
307 MacroFileID
= SM
->getFileID(MacroArgLocation
);
308 return retrieveMacroLocation(MacroArgLocation
, MacroFileID
, CaretFileID
,
309 CommonArgExpansions
, IsBegin
, SM
, IsTokenRange
);
312 /// Walk up the chain of macro expansions and collect the FileIDs identifying the
314 static void getMacroArgExpansionFileIDs(SourceLocation Loc
,
315 SmallVectorImpl
<FileID
> &IDs
,
316 bool IsBegin
, const SourceManager
*SM
) {
317 while (Loc
.isMacroID()) {
318 if (SM
->isMacroArgExpansion(Loc
)) {
319 IDs
.push_back(SM
->getFileID(Loc
));
320 Loc
= SM
->getImmediateSpellingLoc(Loc
);
322 auto ExpRange
= SM
->getImmediateExpansionRange(Loc
);
323 Loc
= IsBegin
? ExpRange
.getBegin() : ExpRange
.getEnd();
328 /// Collect the expansions of the begin and end locations and compute the set
329 /// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions.
330 static void computeCommonMacroArgExpansionFileIDs(
331 SourceLocation Begin
, SourceLocation End
, const SourceManager
*SM
,
332 SmallVectorImpl
<FileID
> &CommonArgExpansions
) {
333 SmallVector
<FileID
, 4> BeginArgExpansions
;
334 SmallVector
<FileID
, 4> EndArgExpansions
;
335 getMacroArgExpansionFileIDs(Begin
, BeginArgExpansions
, /*IsBegin=*/true, SM
);
336 getMacroArgExpansionFileIDs(End
, EndArgExpansions
, /*IsBegin=*/false, SM
);
337 llvm::sort(BeginArgExpansions
);
338 llvm::sort(EndArgExpansions
);
339 std::set_intersection(BeginArgExpansions
.begin(), BeginArgExpansions
.end(),
340 EndArgExpansions
.begin(), EndArgExpansions
.end(),
341 std::back_inserter(CommonArgExpansions
));
344 // Helper function to fix up source ranges. It takes in an array of ranges,
345 // and outputs an array of ranges where we want to draw the range highlighting
346 // around the location specified by CaretLoc.
348 // To find locations which correspond to the caret, we crawl the macro caller
349 // chain for the beginning and end of each range. If the caret location
350 // is in a macro expansion, we search each chain for a location
351 // in the same expansion as the caret; otherwise, we crawl to the top of
352 // each chain. Two locations are part of the same macro expansion
353 // iff the FileID is the same.
355 mapDiagnosticRanges(FullSourceLoc CaretLoc
, ArrayRef
<CharSourceRange
> Ranges
,
356 SmallVectorImpl
<CharSourceRange
> &SpellingRanges
) {
357 FileID CaretLocFileID
= CaretLoc
.getFileID();
359 const SourceManager
*SM
= &CaretLoc
.getManager();
361 for (const auto &Range
: Ranges
) {
362 if (Range
.isInvalid())
365 SourceLocation Begin
= Range
.getBegin(), End
= Range
.getEnd();
366 bool IsTokenRange
= Range
.isTokenRange();
368 FileID BeginFileID
= SM
->getFileID(Begin
);
369 FileID EndFileID
= SM
->getFileID(End
);
371 // Find the common parent for the beginning and end of the range.
373 // First, crawl the expansion chain for the beginning of the range.
374 llvm::SmallDenseMap
<FileID
, SourceLocation
> BeginLocsMap
;
375 while (Begin
.isMacroID() && BeginFileID
!= EndFileID
) {
376 BeginLocsMap
[BeginFileID
] = Begin
;
377 Begin
= SM
->getImmediateExpansionRange(Begin
).getBegin();
378 BeginFileID
= SM
->getFileID(Begin
);
381 // Then, crawl the expansion chain for the end of the range.
382 if (BeginFileID
!= EndFileID
) {
383 while (End
.isMacroID() && !BeginLocsMap
.count(EndFileID
)) {
384 auto Exp
= SM
->getImmediateExpansionRange(End
);
385 IsTokenRange
= Exp
.isTokenRange();
387 EndFileID
= SM
->getFileID(End
);
389 if (End
.isMacroID()) {
390 Begin
= BeginLocsMap
[EndFileID
];
391 BeginFileID
= EndFileID
;
395 // There is a chance that begin or end is invalid here, for example if
396 // specific compile error is reported.
397 // It is possible that the FileID's do not match, if one comes from an
398 // included file. In this case we can not produce a meaningful source range.
399 if (Begin
.isInvalid() || End
.isInvalid() || BeginFileID
!= EndFileID
)
402 // Do the backtracking.
403 SmallVector
<FileID
, 4> CommonArgExpansions
;
404 computeCommonMacroArgExpansionFileIDs(Begin
, End
, SM
, CommonArgExpansions
);
405 Begin
= retrieveMacroLocation(Begin
, BeginFileID
, CaretLocFileID
,
406 CommonArgExpansions
, /*IsBegin=*/true, SM
,
408 End
= retrieveMacroLocation(End
, BeginFileID
, CaretLocFileID
,
409 CommonArgExpansions
, /*IsBegin=*/false, SM
,
411 if (Begin
.isInvalid() || End
.isInvalid()) continue;
413 // Return the spelling location of the beginning and end of the range.
414 Begin
= SM
->getSpellingLoc(Begin
);
415 End
= SM
->getSpellingLoc(End
);
417 SpellingRanges
.push_back(CharSourceRange(SourceRange(Begin
, End
),
422 void DiagnosticRenderer::emitCaret(FullSourceLoc Loc
,
423 DiagnosticsEngine::Level Level
,
424 ArrayRef
<CharSourceRange
> Ranges
,
425 ArrayRef
<FixItHint
> Hints
) {
426 SmallVector
<CharSourceRange
, 4> SpellingRanges
;
427 mapDiagnosticRanges(Loc
, Ranges
, SpellingRanges
);
428 emitCodeContext(Loc
, Level
, SpellingRanges
, Hints
);
431 /// A helper function for emitMacroExpansion to print the
432 /// macro expansion message
433 void DiagnosticRenderer::emitSingleMacroExpansion(
434 FullSourceLoc Loc
, DiagnosticsEngine::Level Level
,
435 ArrayRef
<CharSourceRange
> Ranges
) {
436 // Find the spelling location for the macro definition. We must use the
437 // spelling location here to avoid emitting a macro backtrace for the note.
438 FullSourceLoc SpellingLoc
= Loc
.getSpellingLoc();
440 // Map the ranges into the FileID of the diagnostic location.
441 SmallVector
<CharSourceRange
, 4> SpellingRanges
;
442 mapDiagnosticRanges(Loc
, Ranges
, SpellingRanges
);
444 SmallString
<100> MessageStorage
;
445 llvm::raw_svector_ostream
Message(MessageStorage
);
446 StringRef MacroName
= Lexer::getImmediateMacroNameForDiagnostics(
447 Loc
, Loc
.getManager(), LangOpts
);
448 if (MacroName
.empty())
449 Message
<< "expanded from here";
451 Message
<< "expanded from macro '" << MacroName
<< "'";
453 emitDiagnostic(SpellingLoc
, DiagnosticsEngine::Note
, Message
.str(),
457 /// Check that the macro argument location of Loc starts with ArgumentLoc.
458 /// The starting location of the macro expansions is used to differeniate
459 /// different macro expansions.
460 static bool checkLocForMacroArgExpansion(SourceLocation Loc
,
461 const SourceManager
&SM
,
462 SourceLocation ArgumentLoc
) {
463 SourceLocation MacroLoc
;
464 if (SM
.isMacroArgExpansion(Loc
, &MacroLoc
)) {
465 if (ArgumentLoc
== MacroLoc
) return true;
471 /// Check if all the locations in the range have the same macro argument
472 /// expansion, and that the expansion starts with ArgumentLoc.
473 static bool checkRangeForMacroArgExpansion(CharSourceRange Range
,
474 const SourceManager
&SM
,
475 SourceLocation ArgumentLoc
) {
476 SourceLocation BegLoc
= Range
.getBegin(), EndLoc
= Range
.getEnd();
477 while (BegLoc
!= EndLoc
) {
478 if (!checkLocForMacroArgExpansion(BegLoc
, SM
, ArgumentLoc
))
480 BegLoc
.getLocWithOffset(1);
483 return checkLocForMacroArgExpansion(BegLoc
, SM
, ArgumentLoc
);
486 /// A helper function to check if the current ranges are all inside the same
487 /// macro argument expansion as Loc.
488 static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc
,
489 ArrayRef
<CharSourceRange
> Ranges
) {
490 assert(Loc
.isMacroID() && "Must be a macro expansion!");
492 SmallVector
<CharSourceRange
, 4> SpellingRanges
;
493 mapDiagnosticRanges(Loc
, Ranges
, SpellingRanges
);
495 // Count all valid ranges.
496 unsigned ValidCount
=
497 llvm::count_if(Ranges
, [](const auto &R
) { return R
.isValid(); });
499 if (ValidCount
> SpellingRanges
.size())
502 // To store the source location of the argument location.
503 FullSourceLoc ArgumentLoc
;
505 // Set the ArgumentLoc to the beginning location of the expansion of Loc
506 // so to check if the ranges expands to the same beginning location.
507 if (!Loc
.isMacroArgExpansion(&ArgumentLoc
))
510 for (const auto &Range
: SpellingRanges
)
511 if (!checkRangeForMacroArgExpansion(Range
, Loc
.getManager(), ArgumentLoc
))
517 /// Recursively emit notes for each macro expansion and caret
518 /// diagnostics where appropriate.
520 /// Walks up the macro expansion stack printing expansion notes, the code
521 /// snippet, caret, underlines and FixItHint display as appropriate at each
524 /// \param Loc The location for this caret.
525 /// \param Level The diagnostic level currently being emitted.
526 /// \param Ranges The underlined ranges for this code snippet.
527 /// \param Hints The FixIt hints active for this diagnostic.
528 void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc
,
529 DiagnosticsEngine::Level Level
,
530 ArrayRef
<CharSourceRange
> Ranges
,
531 ArrayRef
<FixItHint
> Hints
) {
532 assert(Loc
.isValid() && "must have a valid source location here");
533 const SourceManager
&SM
= Loc
.getManager();
534 SourceLocation L
= Loc
;
536 // Produce a stack of macro backtraces.
537 SmallVector
<SourceLocation
, 8> LocationStack
;
538 unsigned IgnoredEnd
= 0;
539 while (L
.isMacroID()) {
540 // If this is the expansion of a macro argument, point the caret at the
541 // use of the argument in the definition of the macro, not the expansion.
542 if (SM
.isMacroArgExpansion(L
))
543 LocationStack
.push_back(SM
.getImmediateExpansionRange(L
).getBegin());
545 LocationStack
.push_back(L
);
547 if (checkRangesForMacroArgExpansion(FullSourceLoc(L
, SM
), Ranges
))
548 IgnoredEnd
= LocationStack
.size();
550 L
= SM
.getImmediateMacroCallerLoc(L
);
552 // Once the location no longer points into a macro, try stepping through
553 // the last found location. This sometimes produces additional useful
556 L
= SM
.getImmediateMacroCallerLoc(LocationStack
.back());
557 assert(L
.isValid() && "must have a valid source location here");
560 LocationStack
.erase(LocationStack
.begin(),
561 LocationStack
.begin() + IgnoredEnd
);
563 unsigned MacroDepth
= LocationStack
.size();
564 unsigned MacroLimit
= DiagOpts
->MacroBacktraceLimit
;
565 if (MacroDepth
<= MacroLimit
|| MacroLimit
== 0) {
566 for (auto I
= LocationStack
.rbegin(), E
= LocationStack
.rend();
568 emitSingleMacroExpansion(FullSourceLoc(*I
, SM
), Level
, Ranges
);
572 unsigned MacroStartMessages
= MacroLimit
/ 2;
573 unsigned MacroEndMessages
= MacroLimit
/ 2 + MacroLimit
% 2;
575 for (auto I
= LocationStack
.rbegin(),
576 E
= LocationStack
.rbegin() + MacroStartMessages
;
578 emitSingleMacroExpansion(FullSourceLoc(*I
, SM
), Level
, Ranges
);
580 SmallString
<200> MessageStorage
;
581 llvm::raw_svector_ostream
Message(MessageStorage
);
582 Message
<< "(skipping " << (MacroDepth
- MacroLimit
)
583 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
585 emitBasicNote(Message
.str());
587 for (auto I
= LocationStack
.rend() - MacroEndMessages
,
588 E
= LocationStack
.rend();
590 emitSingleMacroExpansion(FullSourceLoc(*I
, SM
), Level
, Ranges
);
593 DiagnosticNoteRenderer::~DiagnosticNoteRenderer() = default;
595 void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc
,
597 // Generate a note indicating the include location.
598 SmallString
<200> MessageStorage
;
599 llvm::raw_svector_ostream
Message(MessageStorage
);
600 Message
<< "in file included from " << PLoc
.getFilename() << ':'
601 << PLoc
.getLine() << ":";
602 emitNote(Loc
, Message
.str());
605 void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc
,
607 StringRef ModuleName
) {
608 // Generate a note indicating the include location.
609 SmallString
<200> MessageStorage
;
610 llvm::raw_svector_ostream
Message(MessageStorage
);
611 Message
<< "in module '" << ModuleName
;
613 Message
<< "' imported from " << PLoc
.getFilename() << ':'
616 emitNote(Loc
, Message
.str());
619 void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc
,
621 StringRef ModuleName
) {
622 // Generate a note indicating the include location.
623 SmallString
<200> MessageStorage
;
624 llvm::raw_svector_ostream
Message(MessageStorage
);
626 Message
<< "while building module '" << ModuleName
<< "' imported from "
627 << PLoc
.getFilename() << ':' << PLoc
.getLine() << ":";
629 Message
<< "while building module '" << ModuleName
<< "':";
630 emitNote(Loc
, Message
.str());