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
.begin(),
104 SmallVector
<FixItHint
, 8> MergedFixits
;
105 if (!FixItHints
.empty()) {
106 mergeFixits(FixItHints
, Loc
.getManager(), LangOpts
, MergedFixits
);
107 FixItHints
= MergedFixits
;
110 for (const auto &Hint
: FixItHints
)
111 if (Hint
.RemoveRange
.isValid())
112 MutableRanges
.push_back(Hint
.RemoveRange
);
114 FullSourceLoc UnexpandedLoc
= Loc
;
116 // Find the ultimate expansion location for the diagnostic.
117 Loc
= Loc
.getFileLoc();
119 PresumedLoc PLoc
= Loc
.getPresumedLoc(DiagOpts
->ShowPresumedLoc
);
121 // First, if this diagnostic is not in the main file, print out the
122 // "included from" lines.
123 emitIncludeStack(Loc
, PLoc
, Level
);
125 // Next, emit the actual diagnostic message and caret.
126 emitDiagnosticMessage(Loc
, PLoc
, Level
, Message
, Ranges
, D
);
127 emitCaret(Loc
, Level
, MutableRanges
, FixItHints
);
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
);
139 endDiagnostic(D
, Level
);
142 void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic
&Diag
) {
143 emitDiagnostic(Diag
.getLocation(), Diag
.getLevel(), Diag
.getMessage(),
144 Diag
.getRanges(), Diag
.getFixIts(),
148 void DiagnosticRenderer::emitBasicNote(StringRef Message
) {
149 emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note
,
150 Message
, std::nullopt
, DiagOrStoredDiag());
153 /// Prints an include stack when appropriate for a particular
154 /// diagnostic level and location.
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.
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());
170 // Skip redundant include stacks altogether.
171 if (LastIncludeLoc
== IncludeLoc
)
174 LastIncludeLoc
= IncludeLoc
;
176 if (!DiagOpts
->ShowNoteIncludeStack
&& Level
== DiagnosticsEngine::Note
)
179 if (IncludeLoc
.isValid())
180 emitIncludeStackRecursively(IncludeLoc
);
182 emitModuleBuildStack(Loc
.getManager());
183 emitImportStack(Loc
);
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());
195 PresumedLoc PLoc
= Loc
.getPresumedLoc(DiagOpts
->ShowPresumedLoc
);
196 if (PLoc
.isInvalid())
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
);
209 // Emit the other include frames first.
210 emitIncludeStackRecursively(
211 FullSourceLoc(PLoc
.getIncludeLoc(), Loc
.getManager()));
213 // Emit the inclusion text/note.
214 emitIncludeLocation(Loc
, PLoc
);
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());
224 std::pair
<FullSourceLoc
, StringRef
> NextImportLoc
= Loc
.getModuleImportLoc();
225 emitImportStackRecursively(NextImportLoc
.first
, NextImportLoc
.second
);
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()) {
236 PresumedLoc PLoc
= Loc
.getPresumedLoc(DiagOpts
->ShowPresumedLoc
);
238 // Emit the other import frames first.
239 std::pair
<FullSourceLoc
, StringRef
> NextImportLoc
= Loc
.getModuleImportLoc();
240 emitImportStackRecursively(NextImportLoc
.first
, NextImportLoc
.second
);
242 // Emit the inclusion text/note.
243 emitImportLocation(Loc
, PLoc
, ModuleName
);
246 /// Emit the module build stack, for cases where a module is (re-)built
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
),
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
,
262 const SmallVectorImpl
<FileID
> &CommonArgExpansions
,
263 bool IsBegin
, const SourceManager
*SM
,
264 bool &IsTokenRange
) {
265 assert(SM
->getFileID(Loc
) == MacroFileID
);
266 if (MacroFileID
== CaretFileID
)
268 if (!Loc
.isMacroID())
271 CharSourceRange MacroRange
, MacroArgRange
;
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
))
279 CharSourceRange(SM
->getImmediateSpellingLoc(Loc
), IsTokenRange
);
280 MacroArgRange
= SM
->getImmediateExpansionRange(Loc
);
282 MacroRange
= SM
->getImmediateExpansionRange(Loc
);
284 CharSourceRange(SM
->getImmediateSpellingLoc(Loc
), IsTokenRange
);
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();
293 retrieveMacroLocation(MacroLocation
, MacroFileID
, CaretFileID
,
294 CommonArgExpansions
, IsBegin
, SM
, TokenRange
);
295 if (MacroLocation
.isValid()) {
296 IsTokenRange
= TokenRange
;
297 return MacroLocation
;
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.
304 IsTokenRange
= MacroArgRange
.isTokenRange();
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
);
313 /// Walk up the chain of macro expansions and collect the FileIDs identifying the
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
);
323 auto ExpRange
= SM
->getImmediateExpansionRange(Loc
);
324 Loc
= IsBegin
? ExpRange
.getBegin() : ExpRange
.getEnd();
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
));
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.
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.
356 mapDiagnosticRanges(FullSourceLoc CaretLoc
, ArrayRef
<CharSourceRange
> Ranges
,
357 SmallVectorImpl
<CharSourceRange
> &SpellingRanges
) {
358 FileID CaretLocFileID
= CaretLoc
.getFileID();
360 const SourceManager
*SM
= &CaretLoc
.getManager();
362 for (const auto &Range
: Ranges
) {
363 if (Range
.isInvalid())
366 SourceLocation Begin
= Range
.getBegin(), End
= Range
.getEnd();
367 bool IsTokenRange
= Range
.isTokenRange();
369 FileID BeginFileID
= SM
->getFileID(Begin
);
370 FileID EndFileID
= SM
->getFileID(End
);
372 // Find the common parent for the beginning and end of the range.
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
);
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();
388 EndFileID
= SM
->getFileID(End
);
390 if (End
.isMacroID()) {
391 Begin
= BeginLocsMap
[EndFileID
];
392 BeginFileID
= EndFileID
;
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
)
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
,
409 End
= retrieveMacroLocation(End
, BeginFileID
, CaretLocFileID
,
410 CommonArgExpansions
, /*IsBegin=*/false, SM
,
412 if (Begin
.isInvalid() || End
.isInvalid()) continue;
414 // Return the spelling location of the beginning and end of the range.
415 Begin
= SM
->getSpellingLoc(Begin
);
416 End
= SM
->getSpellingLoc(End
);
418 SpellingRanges
.push_back(CharSourceRange(SourceRange(Begin
, End
),
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
);
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();
441 // Map the ranges into the FileID of the diagnostic location.
442 SmallVector
<CharSourceRange
, 4> SpellingRanges
;
443 mapDiagnosticRanges(Loc
, Ranges
, SpellingRanges
);
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";
452 Message
<< "expanded from macro '" << MacroName
<< "'";
454 emitDiagnostic(SpellingLoc
, DiagnosticsEngine::Note
, Message
.str(),
455 SpellingRanges
, std::nullopt
);
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;
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
))
481 BegLoc
.getLocWithOffset(1);
484 return checkLocForMacroArgExpansion(BegLoc
, SM
, ArgumentLoc
);
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!");
493 SmallVector
<CharSourceRange
, 4> SpellingRanges
;
494 mapDiagnosticRanges(Loc
, Ranges
, SpellingRanges
);
496 // Count all valid ranges.
497 unsigned ValidCount
=
498 llvm::count_if(Ranges
, [](const auto &R
) { return R
.isValid(); });
500 if (ValidCount
> SpellingRanges
.size())
503 // To store the source location of the argument location.
504 FullSourceLoc ArgumentLoc
;
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
))
511 for (const auto &Range
: SpellingRanges
)
512 if (!checkRangeForMacroArgExpansion(Range
, Loc
.getManager(), ArgumentLoc
))
518 /// Recursively emit notes for each macro expansion and caret
519 /// diagnostics where appropriate.
521 /// Walks up the macro expansion stack printing expansion notes, the code
522 /// snippet, caret, underlines and FixItHint display as appropriate at each
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
;
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());
546 LocationStack
.push_back(L
);
548 if (checkRangesForMacroArgExpansion(FullSourceLoc(L
, SM
), Ranges
))
549 IgnoredEnd
= LocationStack
.size();
551 L
= SM
.getImmediateMacroCallerLoc(L
);
553 // Once the location no longer points into a macro, try stepping through
554 // the last found location. This sometimes produces additional useful
557 L
= SM
.getImmediateMacroCallerLoc(LocationStack
.back());
558 assert(L
.isValid() && "must have a valid source location here");
561 LocationStack
.erase(LocationStack
.begin(),
562 LocationStack
.begin() + IgnoredEnd
);
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();
569 emitSingleMacroExpansion(FullSourceLoc(*I
, SM
), Level
, Ranges
);
573 unsigned MacroStartMessages
= MacroLimit
/ 2;
574 unsigned MacroEndMessages
= MacroLimit
/ 2 + MacroLimit
% 2;
576 for (auto I
= LocationStack
.rbegin(),
577 E
= LocationStack
.rbegin() + MacroStartMessages
;
579 emitSingleMacroExpansion(FullSourceLoc(*I
, SM
), Level
, Ranges
);
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 "
586 emitBasicNote(Message
.str());
588 for (auto I
= LocationStack
.rend() - MacroEndMessages
,
589 E
= LocationStack
.rend();
591 emitSingleMacroExpansion(FullSourceLoc(*I
, SM
), Level
, Ranges
);
594 DiagnosticNoteRenderer::~DiagnosticNoteRenderer() = default;
596 void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc
,
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());
606 void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc
,
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
;
614 Message
<< "' imported from " << PLoc
.getFilename() << ':'
617 emitNote(Loc
, Message
.str());
620 void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc
,
622 StringRef ModuleName
) {
623 // Generate a note indicating the include location.
624 SmallString
<200> MessageStorage
;
625 llvm::raw_svector_ostream
Message(MessageStorage
);
627 Message
<< "while building module '" << ModuleName
<< "' imported from "
628 << PLoc
.getFilename() << ':' << PLoc
.getLine() << ":";
630 Message
<< "while building module '" << ModuleName
<< "':";
631 emitNote(Loc
, Message
.str());