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