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