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 
10 #include "clang/Basic/Diagnostic.h"
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 
30 using namespace clang;
31 
33  DiagnosticOptions *DiagOpts)
34  : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
35 
37 
38 namespace {
39 
40 class FixitReceiver : public edit::EditsReceiver {
41  SmallVectorImpl<FixItHint> &MergedFixits;
42 
43 public:
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 
58 static void mergeFixits(ArrayRef<FixItHint> FixItHints,
59  const SourceManager &SM, const LangOptions &LangOpts,
60  SmallVectorImpl<FixItHint> &MergedFixits) {
61  edit::Commit commit(SM, LangOpts);
62  for (const auto &Hint : FixItHints)
63  if (Hint.CodeToInsert.empty()) {
64  if (Hint.InsertFromRange.isValid())
65  commit.insertFromRange(Hint.RemoveRange.getBegin(),
66  Hint.InsertFromRange, /*afterToken=*/false,
67  Hint.BeforePreviousInsertions);
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,
91  DiagOrStoredDiag D) {
92  assert(Loc.hasManager() || Loc.isInvalid());
93 
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 
148 void 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.
164 void 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.
189 void 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.
218 void 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.
230 void 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.
248 void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
249  ModuleBuildStack Stack = SM.getModuleBuildStack();
250  for (const auto &I : Stack) {
251  emitBuildingModuleLocation(I.second, I.second.getPresumedLoc(
252  DiagOpts->ShowPresumedLoc),
253  I.first);
254  }
255 }
256 
257 /// A recursive function to trace all possible backtrace locations
258 /// to match the \p CaretLocFileID.
259 static 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.
355 static 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 
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 
423 void 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
434 void DiagnosticRenderer::emitSingleMacroExpansion(
436  ArrayRef<CharSourceRange> Ranges) {
437  // Find the spelling location for the macro definition. We must use the
438  // spelling location here to avoid emitting a macro backtrace for the note.
439  FullSourceLoc SpellingLoc = Loc.getSpellingLoc();
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.
490  ArrayRef<CharSourceRange> Ranges) {
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.
529 void 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:83
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.
SourceRange Range
Definition: SemaObjC.cpp:754
SourceLocation Loc
Definition: SemaObjC.cpp:755
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
SourceLocation End
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:196
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:135
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:98
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:482
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.
bool isValid() const
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.
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:1701
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)
RangeSelector range(RangeSelector Begin, RangeSelector End)
DEPRECATED. Use enclose.
Definition: RangeSelector.h:41
The JSON file list parser is used to communicate input to InstallAPI.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag