clang 19.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.begin(),
102 Ranges.end());
103
104 SmallVector<FixItHint, 8> MergedFixits;
105 if (!FixItHints.empty()) {
106 mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits);
107 FixItHints = MergedFixits;
108 }
109
110 for (const auto &Hint : FixItHints)
111 if (Hint.RemoveRange.isValid())
112 MutableRanges.push_back(Hint.RemoveRange);
113
114 FullSourceLoc UnexpandedLoc = Loc;
115
116 // Find the ultimate expansion location for the diagnostic.
117 Loc = Loc.getFileLoc();
118
119 PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
120
121 // First, if this diagnostic is not in the main file, print out the
122 // "included from" lines.
123 emitIncludeStack(Loc, PLoc, Level);
124
125 // Next, emit the actual diagnostic message and caret.
126 emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D);
127 emitCaret(Loc, Level, MutableRanges, FixItHints);
128
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);
133 }
134 }
135
136 LastLoc = Loc;
137 LastLevel = Level;
138
139 endDiagnostic(D, Level);
140}
141
143 emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
144 Diag.getRanges(), Diag.getFixIts(),
145 &Diag);
146}
147
148void DiagnosticRenderer::emitBasicNote(StringRef Message) {
150 Message, std::nullopt, DiagOrStoredDiag());
151}
152
153/// Prints an include stack when appropriate for a particular
154/// diagnostic level and location.
155///
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.
160///
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.
164void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
166 FullSourceLoc IncludeLoc =
167 PLoc.isInvalid() ? FullSourceLoc()
168 : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager());
169
170 // Skip redundant include stacks altogether.
171 if (LastIncludeLoc == IncludeLoc)
172 return;
173
174 LastIncludeLoc = IncludeLoc;
175
176 if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
177 return;
178
179 if (IncludeLoc.isValid())
180 emitIncludeStackRecursively(IncludeLoc);
181 else {
182 emitModuleBuildStack(Loc.getManager());
183 emitImportStack(Loc);
184 }
185}
186
187/// Helper to recursively walk up the include stack and print each layer
188/// on the way back down.
189void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {
190 if (Loc.isInvalid()) {
191 emitModuleBuildStack(Loc.getManager());
192 return;
193 }
194
195 PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
196 if (PLoc.isInvalid())
197 return;
198
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);
206 return;
207 }
208
209 // Emit the other include frames first.
210 emitIncludeStackRecursively(
211 FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()));
212
213 // Emit the inclusion text/note.
214 emitIncludeLocation(Loc, PLoc);
215}
216
217/// Emit the module import stack associated with the current location.
218void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) {
219 if (Loc.isInvalid()) {
220 emitModuleBuildStack(Loc.getManager());
221 return;
222 }
223
224 std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
225 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
226}
227
228/// Helper to recursively walk up the import stack and print each layer
229/// on the way back down.
230void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
231 StringRef ModuleName) {
232 if (ModuleName.empty()) {
233 return;
234 }
235
236 PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
237
238 // Emit the other import frames first.
239 std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
240 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
241
242 // Emit the inclusion text/note.
243 emitImportLocation(Loc, PLoc, ModuleName);
244}
245
246/// Emit the module build stack, for cases where a module is (re-)built
247/// on demand.
248void 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),
253 I.first);
254 }
255}
256
257/// A recursive function to trace all possible backtrace locations
258/// to match the \p CaretLocFileID.
259static SourceLocation
261 FileID CaretFileID,
262 const SmallVectorImpl<FileID> &CommonArgExpansions,
263 bool IsBegin, const SourceManager *SM,
264 bool &IsTokenRange) {
265 assert(SM->getFileID(Loc) == MacroFileID);
266 if (MacroFileID == CaretFileID)
267 return Loc;
268 if (!Loc.isMacroID())
269 return {};
270
271 CharSourceRange MacroRange, MacroArgRange;
272
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))
278 MacroRange =
279 CharSourceRange(SM->getImmediateSpellingLoc(Loc), IsTokenRange);
280 MacroArgRange = SM->getImmediateExpansionRange(Loc);
281 } else {
282 MacroRange = SM->getImmediateExpansionRange(Loc);
283 MacroArgRange =
284 CharSourceRange(SM->getImmediateSpellingLoc(Loc), IsTokenRange);
285 }
286
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();
292 MacroLocation =
293 retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID,
294 CommonArgExpansions, IsBegin, SM, TokenRange);
295 if (MacroLocation.isValid()) {
296 IsTokenRange = TokenRange;
297 return MacroLocation;
298 }
299 }
300
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.
303 if (!IsBegin)
304 IsTokenRange = MacroArgRange.isTokenRange();
305
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);
311}
312
313/// Walk up the chain of macro expansions and collect the FileIDs identifying the
314/// expansions.
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);
322 } else {
323 auto ExpRange = SM->getImmediateExpansionRange(Loc);
324 Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd();
325 }
326 }
327}
328
329/// Collect the expansions of the begin and end locations and compute the set
330/// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions.
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));
343}
344
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.
348//
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.
355static void
357 SmallVectorImpl<CharSourceRange> &SpellingRanges) {
358 FileID CaretLocFileID = CaretLoc.getFileID();
359
360 const SourceManager *SM = &CaretLoc.getManager();
361
362 for (const auto &Range : Ranges) {
363 if (Range.isInvalid())
364 continue;
365
366 SourceLocation Begin = Range.getBegin(), End = Range.getEnd();
367 bool IsTokenRange = Range.isTokenRange();
368
369 FileID BeginFileID = SM->getFileID(Begin);
370 FileID EndFileID = SM->getFileID(End);
371
372 // Find the common parent for the beginning and end of the range.
373
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);
380 }
381
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();
387 End = Exp.getEnd();
388 EndFileID = SM->getFileID(End);
389 }
390 if (End.isMacroID()) {
391 Begin = BeginLocsMap[EndFileID];
392 BeginFileID = EndFileID;
393 }
394 }
395
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)
401 continue;
402
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,
408 IsTokenRange);
409 End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID,
410 CommonArgExpansions, /*IsBegin=*/false, SM,
411 IsTokenRange);
412 if (Begin.isInvalid() || End.isInvalid()) continue;
413
414 // Return the spelling location of the beginning and end of the range.
415 Begin = SM->getSpellingLoc(Begin);
416 End = SM->getSpellingLoc(End);
417
418 SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End),
419 IsTokenRange));
420 }
421}
422
423void DiagnosticRenderer::emitCaret(FullSourceLoc Loc,
426 ArrayRef<FixItHint> Hints) {
427 SmallVector<CharSourceRange, 4> SpellingRanges;
428 mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
429 emitCodeContext(Loc, Level, SpellingRanges, Hints);
430}
431
432/// A helper function for emitMacroExpansion to print the
433/// macro expansion message
434void DiagnosticRenderer::emitSingleMacroExpansion(
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();
440
441 // Map the ranges into the FileID of the diagnostic location.
442 SmallVector<CharSourceRange, 4> SpellingRanges;
443 mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
444
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";
451 else
452 Message << "expanded from macro '" << MacroName << "'";
453
454 emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(),
455 SpellingRanges, std::nullopt);
456}
457
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.
462 const SourceManager &SM,
463 SourceLocation ArgumentLoc) {
464 SourceLocation MacroLoc;
465 if (SM.isMacroArgExpansion(Loc, &MacroLoc)) {
466 if (ArgumentLoc == MacroLoc) return true;
467 }
468
469 return false;
470}
471
472/// Check if all the locations in the range have the same macro argument
473/// expansion, and that the expansion starts with ArgumentLoc.
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))
480 return false;
481 BegLoc.getLocWithOffset(1);
482 }
483
484 return checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc);
485}
486
487/// A helper function to check if the current ranges are all inside the same
488/// macro argument expansion as Loc.
491 assert(Loc.isMacroID() && "Must be a macro expansion!");
492
493 SmallVector<CharSourceRange, 4> SpellingRanges;
494 mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
495
496 // Count all valid ranges.
497 unsigned ValidCount =
498 llvm::count_if(Ranges, [](const auto &R) { return R.isValid(); });
499
500 if (ValidCount > SpellingRanges.size())
501 return false;
502
503 // To store the source location of the argument location.
504 FullSourceLoc ArgumentLoc;
505
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))
509 return false;
510
511 for (const auto &Range : SpellingRanges)
512 if (!checkRangeForMacroArgExpansion(Range, Loc.getManager(), ArgumentLoc))
513 return false;
514
515 return true;
516}
517
518/// Recursively emit notes for each macro expansion and caret
519/// diagnostics where appropriate.
520///
521/// Walks up the macro expansion stack printing expansion notes, the code
522/// snippet, caret, underlines and FixItHint display as appropriate at each
523/// level.
524///
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.
529void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,
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;
536
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());
545 else
546 LocationStack.push_back(L);
547
549 IgnoredEnd = LocationStack.size();
550
551 L = SM.getImmediateMacroCallerLoc(L);
552
553 // Once the location no longer points into a macro, try stepping through
554 // the last found location. This sometimes produces additional useful
555 // backtraces.
556 if (L.isFileID())
557 L = SM.getImmediateMacroCallerLoc(LocationStack.back());
558 assert(L.isValid() && "must have a valid source location here");
559 }
560
561 LocationStack.erase(LocationStack.begin(),
562 LocationStack.begin() + IgnoredEnd);
563
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();
568 I != E; ++I)
569 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);
570 return;
571 }
572
573 unsigned MacroStartMessages = MacroLimit / 2;
574 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
575
576 for (auto I = LocationStack.rbegin(),
577 E = LocationStack.rbegin() + MacroStartMessages;
578 I != E; ++I)
579 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);
580
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 "
585 "see all)";
586 emitBasicNote(Message.str());
587
588 for (auto I = LocationStack.rend() - MacroEndMessages,
589 E = LocationStack.rend();
590 I != E; ++I)
591 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);
592}
593
595
597 PresumedLoc PLoc) {
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());
604}
605
607 PresumedLoc PLoc,
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;
613 if (PLoc.isValid())
614 Message << "' imported from " << PLoc.getFilename() << ':'
615 << PLoc.getLine();
616 Message << ":";
617 emitNote(Loc, Message.str());
618}
619
621 PresumedLoc PLoc,
622 StringRef ModuleName) {
623 // Generate a note indicating the include location.
624 SmallString<200> MessageStorage;
625 llvm::raw_svector_ostream Message(MessageStorage);
626 if (PLoc.isValid())
627 Message << "while building module '" << ModuleName << "' imported from "
628 << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
629 else
630 Message << "while building module '" << ModuleName << "':";
631 emitNote(Loc, Message.str());
632}
#define SM(sm)
Definition: Cuda.cpp:82
Defines the Diagnostic-related interfaces.
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.
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.
FullSourceLoc getFileLoc() const
FullSourceLoc getSpellingLoc() const
std::pair< FullSourceLoc, StringRef > getModuleImportLoc() const
FileID getFileID() const
PresumedLoc getPresumedLoc(bool UseLineDirectives=true) const
bool hasManager() const
Checks whether the SourceManager is present.
bool isMacroArgExpansion(FullSourceLoc *StartLoc=nullptr) 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:461
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.
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