clang 24.0.0git
DiagnosticRenderer.cpp
Go to the documentation of this file.
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
12#include "clang/Basic/LLVM.h"
16#include "clang/Lex/Lexer.h"
17#include "llvm/ADT/ArrayRef.h"
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Support/raw_ostream.h"
22#include <algorithm>
23#include <cassert>
24#include <iterator>
25#include <utility>
26
27using namespace clang;
28
32
34
35std::optional<CharSourceRange>
37 const SourceManager &SM) {
38 if (Range.isInvalid())
39 return std::nullopt;
40
41 CharSourceRange Expansion = SM.getExpansionRange(Range);
42 if (SM.getFileID(Expansion.getBegin()) != FID ||
43 SM.getFileID(Expansion.getEnd()) != FID) {
44 return std::nullopt;
45 }
46
47 // Both endpoints are in FID, so comparing their offsets is meaningful.
48 if (SM.getFileOffset(Expansion.getBegin()) >
49 SM.getFileOffset(Expansion.getEnd())) {
50 return std::nullopt;
51 }
52
53 return Expansion;
54}
55
58 StringRef Message,
60 ArrayRef<FixItHint> FixItHints,
62 assert(Loc.hasManager() || Loc.isInvalid());
63
64 beginDiagnostic(D, Level);
65
66 if (!Loc.isValid())
67 // If we have no source location, just emit the diagnostic message.
68 emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, D);
69 else {
70 // Get the ranges into a local array we can hack on.
71 SmallVector<CharSourceRange, 20> MutableRanges(Ranges);
72
73 SmallVector<FixItHint, 8> MergedFixits;
74 if (!FixItHints.empty()) {
75 edit::mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits);
76 FixItHints = MergedFixits;
77 }
78
79 for (const auto &Hint : FixItHints)
80 if (Hint.RemoveRange.isValid())
81 MutableRanges.push_back(Hint.RemoveRange);
82
83 FullSourceLoc UnexpandedLoc = Loc;
84
85 // Find the ultimate expansion location for the diagnostic.
86 Loc = Loc.getFileLoc();
87
88 PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
89
90 // First, if this diagnostic is not in the main file, print out the
91 // "included from" lines.
92 emitIncludeStack(Loc, PLoc, Level);
93
94 // Next, emit the actual diagnostic message and caret.
95 emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D);
96 emitCaret(Loc, Level, MutableRanges, FixItHints);
97
98 // If this location is within a macro, walk from UnexpandedLoc up to Loc
99 // and produce a macro backtrace.
100 if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
101 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
102 }
103 }
104
105 LastLoc = Loc;
106 LastLevel = Level;
107
108 endDiagnostic(D, Level);
109}
110
112 emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
113 Diag.getRanges(), Diag.getFixIts(),
114 &Diag);
115}
116
117void DiagnosticRenderer::emitBasicNote(StringRef Message) {
119 Message, {}, DiagOrStoredDiag());
120}
121
122/// Prints an include stack when appropriate for a particular
123/// diagnostic level and location.
124///
125/// This routine handles all the logic of suppressing particular include
126/// stacks (such as those for notes) and duplicate include stacks when
127/// repeated warnings occur within the same file. It also handles the logic
128/// of customizing the formatting and display of the include stack.
129///
130/// \param Loc The diagnostic location.
131/// \param PLoc The presumed location of the diagnostic location.
132/// \param Level The diagnostic level of the message this stack pertains to.
133void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
135 FullSourceLoc IncludeLoc =
136 PLoc.isInvalid() ? FullSourceLoc()
137 : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager());
138
139 // Skip redundant include stacks altogether.
140 if (LastIncludeLoc == IncludeLoc)
141 return;
142
143 LastIncludeLoc = IncludeLoc;
144
145 if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
146 return;
147
148 if (IncludeLoc.isValid())
149 emitIncludeStackRecursively(IncludeLoc);
150 else {
151 emitModuleBuildStack(Loc.getManager());
152 emitImportStack(Loc);
153 }
154}
155
156/// Helper to recursively walk up the include stack and print each layer
157/// on the way back down.
158void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {
159 if (Loc.isInvalid()) {
160 emitModuleBuildStack(Loc.getManager());
161 return;
162 }
163
164 PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
165 if (PLoc.isInvalid())
166 return;
167
168 // If this source location was imported from a module, print the module
169 // import stack rather than the
170 // FIXME: We want submodule granularity here.
171 std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc();
172 if (!Imported.second.empty()) {
173 // This location was imported by a module. Emit the module import stack.
174 emitImportStackRecursively(Imported.first, Imported.second);
175 return;
176 }
177
178 // Emit the other include frames first.
179 emitIncludeStackRecursively(
180 FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()));
181
182 // Emit the inclusion text/note.
183 emitIncludeLocation(Loc, PLoc);
184}
185
186/// Emit the module import stack associated with the current location.
187void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) {
188 if (Loc.isInvalid()) {
189 emitModuleBuildStack(Loc.getManager());
190 return;
191 }
192
193 std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
194 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
195}
196
197/// Helper to recursively walk up the import stack and print each layer
198/// on the way back down.
199void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
200 StringRef ModuleName) {
201 if (ModuleName.empty()) {
202 return;
203 }
204
205 PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
206
207 // Emit the other import frames first.
208 std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
209 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
210
211 // Emit the inclusion text/note.
212 emitImportLocation(Loc, PLoc, ModuleName);
213}
214
215/// Emit the module build stack, for cases where a module is (re-)built
216/// on demand.
217void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
219 for (const auto &I : Stack) {
221 I.second, I.second.getPresumedLoc(DiagOpts.ShowPresumedLoc), I.first);
222 }
223}
224
225/// A recursive function to trace all possible backtrace locations
226/// to match the \p CaretLocFileID.
227static SourceLocation
229 FileID CaretFileID,
230 const SmallVectorImpl<FileID> &CommonArgExpansions,
231 bool IsBegin, const SourceManager *SM,
232 bool &IsTokenRange) {
233 assert(SM->getFileID(Loc) == MacroFileID);
234 if (MacroFileID == CaretFileID)
235 return Loc;
236 if (!Loc.isMacroID())
237 return {};
238
239 CharSourceRange MacroRange, MacroArgRange;
240
241 if (SM->isMacroArgExpansion(Loc)) {
242 // Only look at the immediate spelling location of this macro argument if
243 // the other location in the source range is also present in that expansion.
244 if (llvm::binary_search(CommonArgExpansions, MacroFileID))
245 MacroRange =
246 CharSourceRange(SM->getImmediateSpellingLoc(Loc), IsTokenRange);
247 MacroArgRange = SM->getImmediateExpansionRange(Loc);
248 } else {
249 MacroRange = SM->getImmediateExpansionRange(Loc);
250 MacroArgRange =
251 CharSourceRange(SM->getImmediateSpellingLoc(Loc), IsTokenRange);
252 }
253
254 SourceLocation MacroLocation =
255 IsBegin ? MacroRange.getBegin() : MacroRange.getEnd();
256 if (MacroLocation.isValid()) {
257 MacroFileID = SM->getFileID(MacroLocation);
258 bool TokenRange = IsBegin ? IsTokenRange : MacroRange.isTokenRange();
259 MacroLocation =
260 retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID,
261 CommonArgExpansions, IsBegin, SM, TokenRange);
262 if (MacroLocation.isValid()) {
263 IsTokenRange = TokenRange;
264 return MacroLocation;
265 }
266 }
267
268 // If we moved the end of the range to an expansion location, we now have
269 // a range of the same kind as the expansion range.
270 if (!IsBegin)
271 IsTokenRange = MacroArgRange.isTokenRange();
272
273 SourceLocation MacroArgLocation =
274 IsBegin ? MacroArgRange.getBegin() : MacroArgRange.getEnd();
275 MacroFileID = SM->getFileID(MacroArgLocation);
276 return retrieveMacroLocation(MacroArgLocation, MacroFileID, CaretFileID,
277 CommonArgExpansions, IsBegin, SM, IsTokenRange);
278}
279
280/// Walk up the chain of macro expansions and collect the FileIDs identifying the
281/// expansions.
284 bool IsBegin, const SourceManager *SM) {
285 while (Loc.isMacroID()) {
286 if (SM->isMacroArgExpansion(Loc)) {
287 IDs.push_back(SM->getFileID(Loc));
288 Loc = SM->getImmediateSpellingLoc(Loc);
289 } else {
290 auto ExpRange = SM->getImmediateExpansionRange(Loc);
291 Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd();
292 }
293 }
294}
295
296/// Collect the expansions of the begin and end locations and compute the set
297/// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions.
299 SourceLocation Begin, SourceLocation End, const SourceManager *SM,
300 SmallVectorImpl<FileID> &CommonArgExpansions) {
301 SmallVector<FileID, 4> BeginArgExpansions;
302 SmallVector<FileID, 4> EndArgExpansions;
303 getMacroArgExpansionFileIDs(Begin, BeginArgExpansions, /*IsBegin=*/true, SM);
304 getMacroArgExpansionFileIDs(End, EndArgExpansions, /*IsBegin=*/false, SM);
305 llvm::sort(BeginArgExpansions);
306 llvm::sort(EndArgExpansions);
307 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
308 EndArgExpansions.begin(), EndArgExpansions.end(),
309 std::back_inserter(CommonArgExpansions));
310}
311
312// Helper function to fix up source ranges. It takes in an array of ranges,
313// and outputs an array of ranges where we want to draw the range highlighting
314// around the location specified by CaretLoc.
315//
316// To find locations which correspond to the caret, we crawl the macro caller
317// chain for the beginning and end of each range. If the caret location
318// is in a macro expansion, we search each chain for a location
319// in the same expansion as the caret; otherwise, we crawl to the top of
320// each chain. Two locations are part of the same macro expansion
321// iff the FileID is the same.
322static void
324 SmallVectorImpl<CharSourceRange> &SpellingRanges) {
325 FileID CaretLocFileID = CaretLoc.getFileID();
326
327 const SourceManager *SM = &CaretLoc.getManager();
328
329 for (const auto &Range : Ranges) {
330 if (Range.isInvalid())
331 continue;
332
333 SourceLocation Begin = Range.getBegin(), End = Range.getEnd();
334 bool IsTokenRange = Range.isTokenRange();
335
336 FileID BeginFileID = SM->getFileID(Begin);
337 FileID EndFileID = SM->getFileID(End);
338
339 // Find the common parent for the beginning and end of the range.
340
341 // First, crawl the expansion chain for the beginning of the range.
342 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
343 while (Begin.isMacroID() && BeginFileID != EndFileID) {
344 BeginLocsMap[BeginFileID] = Begin;
345 Begin = SM->getImmediateExpansionRange(Begin).getBegin();
346 BeginFileID = SM->getFileID(Begin);
347 }
348
349 // Then, crawl the expansion chain for the end of the range.
350 if (BeginFileID != EndFileID) {
351 while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
352 auto Exp = SM->getImmediateExpansionRange(End);
353 IsTokenRange = Exp.isTokenRange();
354 End = Exp.getEnd();
355 EndFileID = SM->getFileID(End);
356 }
357 if (End.isMacroID()) {
358 Begin = BeginLocsMap[EndFileID];
359 BeginFileID = EndFileID;
360 }
361 }
362
363 // There is a chance that begin or end is invalid here, for example if
364 // specific compile error is reported.
365 // It is possible that the FileID's do not match, if one comes from an
366 // included file. In this case we can not produce a meaningful source range.
367 if (Begin.isInvalid() || End.isInvalid() || BeginFileID != EndFileID)
368 continue;
369
370 // Do the backtracking.
371 SmallVector<FileID, 4> CommonArgExpansions;
372 computeCommonMacroArgExpansionFileIDs(Begin, End, SM, CommonArgExpansions);
373 Begin = retrieveMacroLocation(Begin, BeginFileID, CaretLocFileID,
374 CommonArgExpansions, /*IsBegin=*/true, SM,
375 IsTokenRange);
376 End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID,
377 CommonArgExpansions, /*IsBegin=*/false, SM,
378 IsTokenRange);
379 if (Begin.isInvalid() || End.isInvalid()) continue;
380
381 // Return the spelling location of the beginning and end of the range.
382 Begin = SM->getSpellingLoc(Begin);
383 End = SM->getSpellingLoc(End);
384
385 SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End),
386 IsTokenRange));
387 }
388}
389
390void DiagnosticRenderer::emitCaret(FullSourceLoc Loc,
393 ArrayRef<FixItHint> Hints) {
394 SmallVector<CharSourceRange, 4> SpellingRanges;
395 mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
396 emitCodeContext(Loc, Level, SpellingRanges, Hints);
397}
398
399/// A helper function for emitMacroExpansion to print the
400/// macro expansion message
401void DiagnosticRenderer::emitSingleMacroExpansion(
404 // Find the spelling location for the macro definition. We must use the
405 // spelling location here to avoid emitting a macro backtrace for the note.
406 FullSourceLoc SpellingLoc = Loc.getSpellingLoc();
407
408 // Map the ranges into the FileID of the diagnostic location.
409 SmallVector<CharSourceRange, 4> SpellingRanges;
410 mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
411
412 SmallString<100> MessageStorage;
413 llvm::raw_svector_ostream Message(MessageStorage);
414 StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
415 Loc, Loc.getManager(), LangOpts);
416 if (MacroName.empty())
417 Message << "expanded from here";
418 else
419 Message << "expanded from macro '" << MacroName << "'";
420
422 SpellingRanges, {});
423}
424
425/// A helper function to check if the current ranges are all inside the same
426/// macro argument expansion as Loc.
427static bool
430 assert(Loc.isMacroID() && "Must be a macro expansion!");
431
432 SmallVector<CharSourceRange> SpellingRanges;
433 mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
434
435 unsigned ValidCount =
436 llvm::count_if(Ranges, [](const auto &R) { return R.isValid(); });
437 if (ValidCount > SpellingRanges.size())
438 return false;
439
440 const SourceManager &SM = Loc.getManager();
441 for (const auto &R : Ranges) {
442 // All positions in the range need to point to Loc.
443 SourceLocation Begin = R.getBegin();
444 if (Begin == R.getEnd()) {
445 if (!SM.isMacroArgExpansion(Begin))
446 return false;
447 continue;
448 }
449
450 while (Begin != R.getEnd()) {
451 SourceLocation MacroLoc;
452 if (!SM.isMacroArgExpansion(Begin, &MacroLoc))
453 return false;
454 if (MacroLoc != Loc)
455 return false;
456
457 Begin = Begin.getLocWithOffset(1);
458 }
459 }
460
461 return true;
462}
463
464/// Recursively emit notes for each macro expansion and caret
465/// diagnostics where appropriate.
466///
467/// Walks up the macro expansion stack printing expansion notes, the code
468/// snippet, caret, underlines and FixItHint display as appropriate at each
469/// level.
470///
471/// \param Loc The location for this caret.
472/// \param Level The diagnostic level currently being emitted.
473/// \param Ranges The underlined ranges for this code snippet.
474/// \param Hints The FixIt hints active for this diagnostic.
475void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,
478 ArrayRef<FixItHint> Hints) {
479 assert(Loc.isValid() && "must have a valid source location here");
480 const SourceManager &SM = Loc.getManager();
481 SourceLocation L = Loc;
482
483 // Produce a stack of macro backtraces.
484 SmallVector<SourceLocation, 8> LocationStack;
485 unsigned IgnoredEnd = 0;
486 while (L.isMacroID()) {
487 // If this is the expansion of a macro argument, point the caret at the
488 // use of the argument in the definition of the macro, not the expansion.
489 if (SM.isMacroArgExpansion(L)) {
490 LocationStack.push_back(SM.getImmediateExpansionRange(L).getBegin());
491
492 if (rangesInsideSameMacroArgExpansion(FullSourceLoc(L, SM), Ranges))
493 IgnoredEnd = LocationStack.size();
494 } else
495 LocationStack.push_back(L);
496
498
499 // Once the location no longer points into a macro, try stepping through
500 // the last found location. This sometimes produces additional useful
501 // backtraces.
502 if (L.isFileID())
503 L = SM.getImmediateMacroCallerLoc(LocationStack.back());
504 assert(L.isValid() && "must have a valid source location here");
505 }
506
507 LocationStack.erase(LocationStack.begin(),
508 LocationStack.begin() + IgnoredEnd);
509
510 unsigned MacroDepth = LocationStack.size();
511 unsigned MacroLimit = DiagOpts.MacroBacktraceLimit;
512 if (MacroDepth <= MacroLimit || MacroLimit == 0) {
513 for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
514 I != E; ++I)
515 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);
516 return;
517 }
518
519 unsigned MacroStartMessages = MacroLimit / 2;
520 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
521
522 for (auto I = LocationStack.rbegin(),
523 E = LocationStack.rbegin() + MacroStartMessages;
524 I != E; ++I)
525 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);
526
527 SmallString<200> MessageStorage;
528 llvm::raw_svector_ostream Message(MessageStorage);
529 Message << "(skipping " << (MacroDepth - MacroLimit)
530 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
531 "see all)";
532 emitBasicNote(Message.str());
533
534 for (auto I = LocationStack.rend() - MacroEndMessages,
535 E = LocationStack.rend();
536 I != E; ++I)
537 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);
538}
539
541
543 PresumedLoc PLoc) {
544 // Generate a note indicating the include location.
545 SmallString<200> MessageStorage;
546 llvm::raw_svector_ostream Message(MessageStorage);
547 Message << "in file included from " << PLoc.getFilename() << ':'
548 << PLoc.getLine() << ":";
549 emitNote(Loc, Message.str());
550}
551
553 PresumedLoc PLoc,
554 StringRef ModuleName) {
555 // Generate a note indicating the include location.
556 SmallString<200> MessageStorage;
557 llvm::raw_svector_ostream Message(MessageStorage);
558 Message << "in module '" << ModuleName;
559 if (PLoc.isValid())
560 Message << "' imported from " << PLoc.getFilename() << ':'
561 << PLoc.getLine();
562 Message << ":";
563 emitNote(Loc, Message.str());
564}
565
567 PresumedLoc PLoc,
568 StringRef ModuleName) {
569 // Generate a note indicating the include location.
570 SmallString<200> MessageStorage;
571 llvm::raw_svector_ostream Message(MessageStorage);
572 if (PLoc.isValid())
573 Message << "while building module '" << ModuleName << "' imported from "
574 << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
575 else
576 Message << "while building module '" << ModuleName << "':";
577 emitNote(Loc, Message.str());
578}
Defines the Diagnostic-related interfaces.
static void getMacroArgExpansionFileIDs(SourceLocation Loc, SmallVectorImpl< FileID > &IDs, bool IsBegin, const SourceManager *SM)
Walk up the chain of macro expansions and collect the FileIDs identifying the expansions.
static SourceLocation retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID, FileID CaretFileID, const SmallVectorImpl< FileID > &CommonArgExpansions, bool IsBegin, const SourceManager *SM, bool &IsTokenRange)
A recursive function to trace all possible backtrace locations to match the CaretLocFileID.
static void computeCommonMacroArgExpansionFileIDs(SourceLocation Begin, SourceLocation End, const SourceManager *SM, SmallVectorImpl< FileID > &CommonArgExpansions)
Collect the expansions of the begin and end locations and compute the set intersection.
static void mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef< CharSourceRange > Ranges, SmallVectorImpl< CharSourceRange > &SpellingRanges)
static bool rangesInsideSameMacroArgExpansion(FullSourceLoc Loc, ArrayRef< CharSourceRange > Ranges)
A helper function to check if the current ranges are all inside the same macro argument expansion as ...
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Represents a byte-granular source range.
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
SourceLocation getEnd() const
SourceLocation getBegin() const
virtual void emitNote(FullSourceLoc Loc, StringRef Message)=0
void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override
void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
Options for controlling the compiler diagnostics engine.
virtual void endDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)
virtual void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc)=0
const LangOptions & LangOpts
void emitStoredDiagnostic(StoredDiagnostic &Diag)
SourceLocation LastLoc
The location of the previous diagnostic if known.
DiagnosticOptions & DiagOpts
DiagnosticsEngine::Level LastLevel
The level of the last diagnostic emitted.
virtual void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName)=0
virtual void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, DiagOrStoredDiag Info)=0
SourceLocation LastIncludeLoc
The location of the last include whose stack was printed if known.
virtual void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName)=0
void emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, ArrayRef< FixItHint > FixItHints, DiagOrStoredDiag D=(Diagnostic *) nullptr)
Emit a diagnostic.
virtual void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, SmallVectorImpl< CharSourceRange > &Ranges, ArrayRef< FixItHint > Hints)=0
DiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts)
virtual void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)
Level
The level of the diagnostic, after it has been through mapping.
Definition Diagnostic.h:239
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
A SourceLocation and its associated SourceManager.
FullSourceLoc getFileLoc() const
FullSourceLoc getSpellingLoc() const
std::pair< FullSourceLoc, StringRef > getModuleImportLoc() const
PresumedLoc getPresumedLoc(bool UseLineDirectives=true) const
bool hasManager() const
Checks whether the SourceManager is present.
const SourceManager & getManager() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static StringRef getImmediateMacroNameForDiagnostics(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
Definition Lexer.cpp:1158
Represents an unpacked "presumed" location which can be presented to the user.
const char * getFilename() const
Return the presumed filename of this location.
unsigned getLine() const
Return the presumed line number of this location.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
SourceLocation getIncludeLoc() const
Return the presumed include location of this location.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID.
ModuleBuildStack getModuleBuildStack() const
Retrieve the module build stack.
SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const
Gets the location of the immediate macro caller, one level up the stack toward the initial macro type...
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID.
A trivial tuple used to represent a source range.
Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...
void mergeFixits(ArrayRef< FixItHint > FixItHints, const SourceManager &SM, const LangOptions &LangOpts, SmallVectorImpl< FixItHint > &MergedFixits)
Merges FixItHints into a normalized set of file edits.
Top level wrappers for InstallAPI frontend operations.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
ArrayRef< std::pair< std::string, FullSourceLoc > > ModuleBuildStack
The stack used when building modules on demand, which is used to provide a link between the source ma...
std::optional< CharSourceRange > getExpansionRangeInFile(CharSourceRange Range, FileID FID, const SourceManager &SM)
Maps both endpoints of Range to their macro expansion, so that the range can be shown to a user.