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/None.h"
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/raw_ostream.h"
31 using namespace clang
;
33 DiagnosticRenderer::DiagnosticRenderer(const LangOptions
&LangOpts
,
34 DiagnosticOptions
*DiagOpts
)
35 : LangOpts(LangOpts
), DiagOpts(DiagOpts
), LastLevel() {}
37 DiagnosticRenderer::~DiagnosticRenderer() = default;
41 class FixitReceiver
: public edit::EditsReceiver
{
42 SmallVectorImpl
<FixItHint
> &MergedFixits
;
45 FixitReceiver(SmallVectorImpl
<FixItHint
> &MergedFixits
)
46 : MergedFixits(MergedFixits
) {}
48 void insert(SourceLocation loc
, StringRef text
) override
{
49 MergedFixits
.push_back(FixItHint::CreateInsertion(loc
, text
));
52 void replace(CharSourceRange range
, StringRef text
) override
{
53 MergedFixits
.push_back(FixItHint::CreateReplacement(range
, text
));
59 static void mergeFixits(ArrayRef
<FixItHint
> FixItHints
,
60 const SourceManager
&SM
, const LangOptions
&LangOpts
,
61 SmallVectorImpl
<FixItHint
> &MergedFixits
) {
62 edit::Commit
commit(SM
, LangOpts
);
63 for (const auto &Hint
: FixItHints
)
64 if (Hint
.CodeToInsert
.empty()) {
65 if (Hint
.InsertFromRange
.isValid())
66 commit
.insertFromRange(Hint
.RemoveRange
.getBegin(),
67 Hint
.InsertFromRange
, /*afterToken=*/false,
68 Hint
.BeforePreviousInsertions
);
70 commit
.remove(Hint
.RemoveRange
);
72 if (Hint
.RemoveRange
.isTokenRange() ||
73 Hint
.RemoveRange
.getBegin() != Hint
.RemoveRange
.getEnd())
74 commit
.replace(Hint
.RemoveRange
, Hint
.CodeToInsert
);
76 commit
.insert(Hint
.RemoveRange
.getBegin(), Hint
.CodeToInsert
,
77 /*afterToken=*/false, Hint
.BeforePreviousInsertions
);
80 edit::EditedSource
Editor(SM
, LangOpts
);
81 if (Editor
.commit(commit
)) {
82 FixitReceiver
Rec(MergedFixits
);
83 Editor
.applyRewrites(Rec
);
87 void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc
,
88 DiagnosticsEngine::Level Level
,
90 ArrayRef
<CharSourceRange
> Ranges
,
91 ArrayRef
<FixItHint
> FixItHints
,
93 assert(Loc
.hasManager() || Loc
.isInvalid());
95 beginDiagnostic(D
, Level
);
98 // If we have no source location, just emit the diagnostic message.
99 emitDiagnosticMessage(Loc
, PresumedLoc(), Level
, Message
, Ranges
, D
);
101 // Get the ranges into a local array we can hack on.
102 SmallVector
<CharSourceRange
, 20> MutableRanges(Ranges
.begin(),
105 SmallVector
<FixItHint
, 8> MergedFixits
;
106 if (!FixItHints
.empty()) {
107 mergeFixits(FixItHints
, Loc
.getManager(), LangOpts
, MergedFixits
);
108 FixItHints
= MergedFixits
;
111 for (const auto &Hint
: FixItHints
)
112 if (Hint
.RemoveRange
.isValid())
113 MutableRanges
.push_back(Hint
.RemoveRange
);
115 FullSourceLoc UnexpandedLoc
= Loc
;
117 // Find the ultimate expansion location for the diagnostic.
118 Loc
= Loc
.getFileLoc();
120 PresumedLoc PLoc
= Loc
.getPresumedLoc(DiagOpts
->ShowPresumedLoc
);
122 // First, if this diagnostic is not in the main file, print out the
123 // "included from" lines.
124 emitIncludeStack(Loc
, PLoc
, Level
);
126 // Next, emit the actual diagnostic message and caret.
127 emitDiagnosticMessage(Loc
, PLoc
, Level
, Message
, Ranges
, D
);
128 emitCaret(Loc
, Level
, MutableRanges
, FixItHints
);
130 // If this location is within a macro, walk from UnexpandedLoc up to Loc
131 // and produce a macro backtrace.
132 if (UnexpandedLoc
.isValid() && UnexpandedLoc
.isMacroID()) {
133 emitMacroExpansions(UnexpandedLoc
, Level
, MutableRanges
, FixItHints
);
140 endDiagnostic(D
, Level
);
143 void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic
&Diag
) {
144 emitDiagnostic(Diag
.getLocation(), Diag
.getLevel(), Diag
.getMessage(),
145 Diag
.getRanges(), Diag
.getFixIts(),
149 void DiagnosticRenderer::emitBasicNote(StringRef Message
) {
150 emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note
,
151 Message
, None
, DiagOrStoredDiag());
154 /// Prints an include stack when appropriate for a particular
155 /// diagnostic level and location.
157 /// This routine handles all the logic of suppressing particular include
158 /// stacks (such as those for notes) and duplicate include stacks when
159 /// repeated warnings occur within the same file. It also handles the logic
160 /// of customizing the formatting and display of the include stack.
162 /// \param Loc The diagnostic location.
163 /// \param PLoc The presumed location of the diagnostic location.
164 /// \param Level The diagnostic level of the message this stack pertains to.
165 void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc
, PresumedLoc PLoc
,
166 DiagnosticsEngine::Level Level
) {
167 FullSourceLoc IncludeLoc
=
168 PLoc
.isInvalid() ? FullSourceLoc()
169 : FullSourceLoc(PLoc
.getIncludeLoc(), Loc
.getManager());
171 // Skip redundant include stacks altogether.
172 if (LastIncludeLoc
== IncludeLoc
)
175 LastIncludeLoc
= IncludeLoc
;
177 if (!DiagOpts
->ShowNoteIncludeStack
&& Level
== DiagnosticsEngine::Note
)
180 if (IncludeLoc
.isValid())
181 emitIncludeStackRecursively(IncludeLoc
);
183 emitModuleBuildStack(Loc
.getManager());
184 emitImportStack(Loc
);
188 /// Helper to recursively walk up the include stack and print each layer
189 /// on the way back down.
190 void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc
) {
191 if (Loc
.isInvalid()) {
192 emitModuleBuildStack(Loc
.getManager());
196 PresumedLoc PLoc
= Loc
.getPresumedLoc(DiagOpts
->ShowPresumedLoc
);
197 if (PLoc
.isInvalid())
200 // If this source location was imported from a module, print the module
201 // import stack rather than the
202 // FIXME: We want submodule granularity here.
203 std::pair
<FullSourceLoc
, StringRef
> Imported
= Loc
.getModuleImportLoc();
204 if (!Imported
.second
.empty()) {
205 // This location was imported by a module. Emit the module import stack.
206 emitImportStackRecursively(Imported
.first
, Imported
.second
);
210 // Emit the other include frames first.
211 emitIncludeStackRecursively(
212 FullSourceLoc(PLoc
.getIncludeLoc(), Loc
.getManager()));
214 // Emit the inclusion text/note.
215 emitIncludeLocation(Loc
, PLoc
);
218 /// Emit the module import stack associated with the current location.
219 void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc
) {
220 if (Loc
.isInvalid()) {
221 emitModuleBuildStack(Loc
.getManager());
225 std::pair
<FullSourceLoc
, StringRef
> NextImportLoc
= Loc
.getModuleImportLoc();
226 emitImportStackRecursively(NextImportLoc
.first
, NextImportLoc
.second
);
229 /// Helper to recursively walk up the import stack and print each layer
230 /// on the way back down.
231 void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc
,
232 StringRef ModuleName
) {
233 if (ModuleName
.empty()) {
237 PresumedLoc PLoc
= Loc
.getPresumedLoc(DiagOpts
->ShowPresumedLoc
);
239 // Emit the other import frames first.
240 std::pair
<FullSourceLoc
, StringRef
> NextImportLoc
= Loc
.getModuleImportLoc();
241 emitImportStackRecursively(NextImportLoc
.first
, NextImportLoc
.second
);
243 // Emit the inclusion text/note.
244 emitImportLocation(Loc
, PLoc
, ModuleName
);
247 /// Emit the module build stack, for cases where a module is (re-)built
249 void DiagnosticRenderer::emitModuleBuildStack(const SourceManager
&SM
) {
250 ModuleBuildStack Stack
= SM
.getModuleBuildStack();
251 for (const auto &I
: Stack
) {
252 emitBuildingModuleLocation(I
.second
, I
.second
.getPresumedLoc(
253 DiagOpts
->ShowPresumedLoc
),
258 /// A recursive function to trace all possible backtrace locations
259 /// to match the \p CaretLocFileID.
260 static SourceLocation
261 retrieveMacroLocation(SourceLocation Loc
, FileID MacroFileID
,
263 const SmallVectorImpl
<FileID
> &CommonArgExpansions
,
264 bool IsBegin
, const SourceManager
*SM
,
265 bool &IsTokenRange
) {
266 assert(SM
->getFileID(Loc
) == MacroFileID
);
267 if (MacroFileID
== CaretFileID
)
269 if (!Loc
.isMacroID())
272 CharSourceRange MacroRange
, MacroArgRange
;
274 if (SM
->isMacroArgExpansion(Loc
)) {
275 // Only look at the immediate spelling location of this macro argument if
276 // the other location in the source range is also present in that expansion.
277 if (std::binary_search(CommonArgExpansions
.begin(),
278 CommonArgExpansions
.end(), MacroFileID
))
280 CharSourceRange(SM
->getImmediateSpellingLoc(Loc
), IsTokenRange
);
281 MacroArgRange
= SM
->getImmediateExpansionRange(Loc
);
283 MacroRange
= SM
->getImmediateExpansionRange(Loc
);
285 CharSourceRange(SM
->getImmediateSpellingLoc(Loc
), IsTokenRange
);
288 SourceLocation MacroLocation
=
289 IsBegin
? MacroRange
.getBegin() : MacroRange
.getEnd();
290 if (MacroLocation
.isValid()) {
291 MacroFileID
= SM
->getFileID(MacroLocation
);
292 bool TokenRange
= IsBegin
? IsTokenRange
: MacroRange
.isTokenRange();
294 retrieveMacroLocation(MacroLocation
, MacroFileID
, CaretFileID
,
295 CommonArgExpansions
, IsBegin
, SM
, TokenRange
);
296 if (MacroLocation
.isValid()) {
297 IsTokenRange
= TokenRange
;
298 return MacroLocation
;
302 // If we moved the end of the range to an expansion location, we now have
303 // a range of the same kind as the expansion range.
305 IsTokenRange
= MacroArgRange
.isTokenRange();
307 SourceLocation MacroArgLocation
=
308 IsBegin
? MacroArgRange
.getBegin() : MacroArgRange
.getEnd();
309 MacroFileID
= SM
->getFileID(MacroArgLocation
);
310 return retrieveMacroLocation(MacroArgLocation
, MacroFileID
, CaretFileID
,
311 CommonArgExpansions
, IsBegin
, SM
, IsTokenRange
);
314 /// Walk up the chain of macro expansions and collect the FileIDs identifying the
316 static void getMacroArgExpansionFileIDs(SourceLocation Loc
,
317 SmallVectorImpl
<FileID
> &IDs
,
318 bool IsBegin
, const SourceManager
*SM
) {
319 while (Loc
.isMacroID()) {
320 if (SM
->isMacroArgExpansion(Loc
)) {
321 IDs
.push_back(SM
->getFileID(Loc
));
322 Loc
= SM
->getImmediateSpellingLoc(Loc
);
324 auto ExpRange
= SM
->getImmediateExpansionRange(Loc
);
325 Loc
= IsBegin
? ExpRange
.getBegin() : ExpRange
.getEnd();
330 /// Collect the expansions of the begin and end locations and compute the set
331 /// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions.
332 static void computeCommonMacroArgExpansionFileIDs(
333 SourceLocation Begin
, SourceLocation End
, const SourceManager
*SM
,
334 SmallVectorImpl
<FileID
> &CommonArgExpansions
) {
335 SmallVector
<FileID
, 4> BeginArgExpansions
;
336 SmallVector
<FileID
, 4> EndArgExpansions
;
337 getMacroArgExpansionFileIDs(Begin
, BeginArgExpansions
, /*IsBegin=*/true, SM
);
338 getMacroArgExpansionFileIDs(End
, EndArgExpansions
, /*IsBegin=*/false, SM
);
339 llvm::sort(BeginArgExpansions
);
340 llvm::sort(EndArgExpansions
);
341 std::set_intersection(BeginArgExpansions
.begin(), BeginArgExpansions
.end(),
342 EndArgExpansions
.begin(), EndArgExpansions
.end(),
343 std::back_inserter(CommonArgExpansions
));
346 // Helper function to fix up source ranges. It takes in an array of ranges,
347 // and outputs an array of ranges where we want to draw the range highlighting
348 // around the location specified by CaretLoc.
350 // To find locations which correspond to the caret, we crawl the macro caller
351 // chain for the beginning and end of each range. If the caret location
352 // is in a macro expansion, we search each chain for a location
353 // in the same expansion as the caret; otherwise, we crawl to the top of
354 // each chain. Two locations are part of the same macro expansion
355 // iff the FileID is the same.
357 mapDiagnosticRanges(FullSourceLoc CaretLoc
, ArrayRef
<CharSourceRange
> Ranges
,
358 SmallVectorImpl
<CharSourceRange
> &SpellingRanges
) {
359 FileID CaretLocFileID
= CaretLoc
.getFileID();
361 const SourceManager
*SM
= &CaretLoc
.getManager();
363 for (const auto &Range
: Ranges
) {
364 if (Range
.isInvalid())
367 SourceLocation Begin
= Range
.getBegin(), End
= Range
.getEnd();
368 bool IsTokenRange
= Range
.isTokenRange();
370 FileID BeginFileID
= SM
->getFileID(Begin
);
371 FileID EndFileID
= SM
->getFileID(End
);
373 // Find the common parent for the beginning and end of the range.
375 // First, crawl the expansion chain for the beginning of the range.
376 llvm::SmallDenseMap
<FileID
, SourceLocation
> BeginLocsMap
;
377 while (Begin
.isMacroID() && BeginFileID
!= EndFileID
) {
378 BeginLocsMap
[BeginFileID
] = Begin
;
379 Begin
= SM
->getImmediateExpansionRange(Begin
).getBegin();
380 BeginFileID
= SM
->getFileID(Begin
);
383 // Then, crawl the expansion chain for the end of the range.
384 if (BeginFileID
!= EndFileID
) {
385 while (End
.isMacroID() && !BeginLocsMap
.count(EndFileID
)) {
386 auto Exp
= SM
->getImmediateExpansionRange(End
);
387 IsTokenRange
= Exp
.isTokenRange();
389 EndFileID
= SM
->getFileID(End
);
391 if (End
.isMacroID()) {
392 Begin
= BeginLocsMap
[EndFileID
];
393 BeginFileID
= EndFileID
;
397 // There is a chance that begin or end is invalid here, for example if
398 // specific compile error is reported.
399 // It is possible that the FileID's do not match, if one comes from an
400 // included file. In this case we can not produce a meaningful source range.
401 if (Begin
.isInvalid() || End
.isInvalid() || BeginFileID
!= EndFileID
)
404 // Do the backtracking.
405 SmallVector
<FileID
, 4> CommonArgExpansions
;
406 computeCommonMacroArgExpansionFileIDs(Begin
, End
, SM
, CommonArgExpansions
);
407 Begin
= retrieveMacroLocation(Begin
, BeginFileID
, CaretLocFileID
,
408 CommonArgExpansions
, /*IsBegin=*/true, SM
,
410 End
= retrieveMacroLocation(End
, BeginFileID
, CaretLocFileID
,
411 CommonArgExpansions
, /*IsBegin=*/false, SM
,
413 if (Begin
.isInvalid() || End
.isInvalid()) continue;
415 // Return the spelling location of the beginning and end of the range.
416 Begin
= SM
->getSpellingLoc(Begin
);
417 End
= SM
->getSpellingLoc(End
);
419 SpellingRanges
.push_back(CharSourceRange(SourceRange(Begin
, End
),
424 void DiagnosticRenderer::emitCaret(FullSourceLoc Loc
,
425 DiagnosticsEngine::Level Level
,
426 ArrayRef
<CharSourceRange
> Ranges
,
427 ArrayRef
<FixItHint
> Hints
) {
428 SmallVector
<CharSourceRange
, 4> SpellingRanges
;
429 mapDiagnosticRanges(Loc
, Ranges
, SpellingRanges
);
430 emitCodeContext(Loc
, Level
, SpellingRanges
, Hints
);
433 /// A helper function for emitMacroExpansion to print the
434 /// macro expansion message
435 void DiagnosticRenderer::emitSingleMacroExpansion(
436 FullSourceLoc Loc
, DiagnosticsEngine::Level Level
,
437 ArrayRef
<CharSourceRange
> Ranges
) {
438 // Find the spelling location for the macro definition. We must use the
439 // spelling location here to avoid emitting a macro backtrace for the note.
440 FullSourceLoc SpellingLoc
= Loc
.getSpellingLoc();
442 // Map the ranges into the FileID of the diagnostic location.
443 SmallVector
<CharSourceRange
, 4> SpellingRanges
;
444 mapDiagnosticRanges(Loc
, Ranges
, SpellingRanges
);
446 SmallString
<100> MessageStorage
;
447 llvm::raw_svector_ostream
Message(MessageStorage
);
448 StringRef MacroName
= Lexer::getImmediateMacroNameForDiagnostics(
449 Loc
, Loc
.getManager(), LangOpts
);
450 if (MacroName
.empty())
451 Message
<< "expanded from here";
453 Message
<< "expanded from macro '" << MacroName
<< "'";
455 emitDiagnostic(SpellingLoc
, DiagnosticsEngine::Note
, Message
.str(),
456 SpellingRanges
, None
);
459 /// Check that the macro argument location of Loc starts with ArgumentLoc.
460 /// The starting location of the macro expansions is used to differeniate
461 /// different macro expansions.
462 static bool checkLocForMacroArgExpansion(SourceLocation Loc
,
463 const SourceManager
&SM
,
464 SourceLocation ArgumentLoc
) {
465 SourceLocation MacroLoc
;
466 if (SM
.isMacroArgExpansion(Loc
, &MacroLoc
)) {
467 if (ArgumentLoc
== MacroLoc
) return true;
473 /// Check if all the locations in the range have the same macro argument
474 /// expansion, and that the expansion starts with ArgumentLoc.
475 static bool checkRangeForMacroArgExpansion(CharSourceRange Range
,
476 const SourceManager
&SM
,
477 SourceLocation ArgumentLoc
) {
478 SourceLocation BegLoc
= Range
.getBegin(), EndLoc
= Range
.getEnd();
479 while (BegLoc
!= EndLoc
) {
480 if (!checkLocForMacroArgExpansion(BegLoc
, SM
, ArgumentLoc
))
482 BegLoc
.getLocWithOffset(1);
485 return checkLocForMacroArgExpansion(BegLoc
, SM
, ArgumentLoc
);
488 /// A helper function to check if the current ranges are all inside the same
489 /// macro argument expansion as Loc.
490 static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc
,
491 ArrayRef
<CharSourceRange
> Ranges
) {
492 assert(Loc
.isMacroID() && "Must be a macro expansion!");
494 SmallVector
<CharSourceRange
, 4> SpellingRanges
;
495 mapDiagnosticRanges(Loc
, Ranges
, SpellingRanges
);
497 /// Count all valid ranges.
498 unsigned ValidCount
= 0;
499 for (const auto &Range
: Ranges
)
503 if (ValidCount
> SpellingRanges
.size())
506 /// To store the source location of the argument location.
507 FullSourceLoc ArgumentLoc
;
509 /// Set the ArgumentLoc to the beginning location of the expansion of Loc
510 /// so to check if the ranges expands to the same beginning location.
511 if (!Loc
.isMacroArgExpansion(&ArgumentLoc
))
514 for (const auto &Range
: SpellingRanges
)
515 if (!checkRangeForMacroArgExpansion(Range
, Loc
.getManager(), ArgumentLoc
))
521 /// Recursively emit notes for each macro expansion and caret
522 /// diagnostics where appropriate.
524 /// Walks up the macro expansion stack printing expansion notes, the code
525 /// snippet, caret, underlines and FixItHint display as appropriate at each
528 /// \param Loc The location for this caret.
529 /// \param Level The diagnostic level currently being emitted.
530 /// \param Ranges The underlined ranges for this code snippet.
531 /// \param Hints The FixIt hints active for this diagnostic.
532 void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc
,
533 DiagnosticsEngine::Level Level
,
534 ArrayRef
<CharSourceRange
> Ranges
,
535 ArrayRef
<FixItHint
> Hints
) {
536 assert(Loc
.isValid() && "must have a valid source location here");
537 const SourceManager
&SM
= Loc
.getManager();
538 SourceLocation L
= Loc
;
540 // Produce a stack of macro backtraces.
541 SmallVector
<SourceLocation
, 8> LocationStack
;
542 unsigned IgnoredEnd
= 0;
543 while (L
.isMacroID()) {
544 // If this is the expansion of a macro argument, point the caret at the
545 // use of the argument in the definition of the macro, not the expansion.
546 if (SM
.isMacroArgExpansion(L
))
547 LocationStack
.push_back(SM
.getImmediateExpansionRange(L
).getBegin());
549 LocationStack
.push_back(L
);
551 if (checkRangesForMacroArgExpansion(FullSourceLoc(L
, SM
), Ranges
))
552 IgnoredEnd
= LocationStack
.size();
554 L
= SM
.getImmediateMacroCallerLoc(L
);
556 // Once the location no longer points into a macro, try stepping through
557 // the last found location. This sometimes produces additional useful
560 L
= SM
.getImmediateMacroCallerLoc(LocationStack
.back());
561 assert(L
.isValid() && "must have a valid source location here");
564 LocationStack
.erase(LocationStack
.begin(),
565 LocationStack
.begin() + IgnoredEnd
);
567 unsigned MacroDepth
= LocationStack
.size();
568 unsigned MacroLimit
= DiagOpts
->MacroBacktraceLimit
;
569 if (MacroDepth
<= MacroLimit
|| MacroLimit
== 0) {
570 for (auto I
= LocationStack
.rbegin(), E
= LocationStack
.rend();
572 emitSingleMacroExpansion(FullSourceLoc(*I
, SM
), Level
, Ranges
);
576 unsigned MacroStartMessages
= MacroLimit
/ 2;
577 unsigned MacroEndMessages
= MacroLimit
/ 2 + MacroLimit
% 2;
579 for (auto I
= LocationStack
.rbegin(),
580 E
= LocationStack
.rbegin() + MacroStartMessages
;
582 emitSingleMacroExpansion(FullSourceLoc(*I
, SM
), Level
, Ranges
);
584 SmallString
<200> MessageStorage
;
585 llvm::raw_svector_ostream
Message(MessageStorage
);
586 Message
<< "(skipping " << (MacroDepth
- MacroLimit
)
587 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
589 emitBasicNote(Message
.str());
591 for (auto I
= LocationStack
.rend() - MacroEndMessages
,
592 E
= LocationStack
.rend();
594 emitSingleMacroExpansion(FullSourceLoc(*I
, SM
), Level
, Ranges
);
597 DiagnosticNoteRenderer::~DiagnosticNoteRenderer() = default;
599 void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc
,
601 // Generate a note indicating the include location.
602 SmallString
<200> MessageStorage
;
603 llvm::raw_svector_ostream
Message(MessageStorage
);
604 Message
<< "in file included from " << PLoc
.getFilename() << ':'
605 << PLoc
.getLine() << ":";
606 emitNote(Loc
, Message
.str());
609 void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc
,
611 StringRef ModuleName
) {
612 // Generate a note indicating the include location.
613 SmallString
<200> MessageStorage
;
614 llvm::raw_svector_ostream
Message(MessageStorage
);
615 Message
<< "in module '" << ModuleName
;
617 Message
<< "' imported from " << PLoc
.getFilename() << ':'
620 emitNote(Loc
, Message
.str());
623 void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc
,
625 StringRef ModuleName
) {
626 // Generate a note indicating the include location.
627 SmallString
<200> MessageStorage
;
628 llvm::raw_svector_ostream
Message(MessageStorage
);
630 Message
<< "while building module '" << ModuleName
<< "' imported from "
631 << PLoc
.getFilename() << ':' << PLoc
.getLine() << ":";
633 Message
<< "while building module '" << ModuleName
<< "':";
634 emitNote(Loc
, Message
.str());