Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/Frontend/DiagnosticRenderer.cpp
Line
Count
Source (jump to first uncovered line)
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
9
#include "clang/Frontend/DiagnosticRenderer.h"
10
#include "clang/Basic/Diagnostic.h"
11
#include "clang/Basic/DiagnosticOptions.h"
12
#include "clang/Basic/LLVM.h"
13
#include "clang/Basic/SourceLocation.h"
14
#include "clang/Basic/SourceManager.h"
15
#include "clang/Edit/Commit.h"
16
#include "clang/Edit/EditedSource.h"
17
#include "clang/Edit/EditsReceiver.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
32
DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts,
33
                                       DiagnosticOptions *DiagOpts)
34
0
    : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
35
36
0
DiagnosticRenderer::~DiagnosticRenderer() = default;
37
38
namespace {
39
40
class FixitReceiver : public edit::EditsReceiver {
41
  SmallVectorImpl<FixItHint> &MergedFixits;
42
43
public:
44
  FixitReceiver(SmallVectorImpl<FixItHint> &MergedFixits)
45
0
      : MergedFixits(MergedFixits) {}
46
47
0
  void insert(SourceLocation loc, StringRef text) override {
48
0
    MergedFixits.push_back(FixItHint::CreateInsertion(loc, text));
49
0
  }
50
51
0
  void replace(CharSourceRange range, StringRef text) override {
52
0
    MergedFixits.push_back(FixItHint::CreateReplacement(range, text));
53
0
  }
54
};
55
56
} // namespace
57
58
static void mergeFixits(ArrayRef<FixItHint> FixItHints,
59
                        const SourceManager &SM, const LangOptions &LangOpts,
60
0
                        SmallVectorImpl<FixItHint> &MergedFixits) {
61
0
  edit::Commit commit(SM, LangOpts);
62
0
  for (const auto &Hint : FixItHints)
63
0
    if (Hint.CodeToInsert.empty()) {
64
0
      if (Hint.InsertFromRange.isValid())
65
0
        commit.insertFromRange(Hint.RemoveRange.getBegin(),
66
0
                           Hint.InsertFromRange, /*afterToken=*/false,
67
0
                           Hint.BeforePreviousInsertions);
68
0
      else
69
0
        commit.remove(Hint.RemoveRange);
70
0
    } else {
71
0
      if (Hint.RemoveRange.isTokenRange() ||
72
0
          Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
73
0
        commit.replace(Hint.RemoveRange, Hint.CodeToInsert);
74
0
      else
75
0
        commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
76
0
                    /*afterToken=*/false, Hint.BeforePreviousInsertions);
77
0
    }
78
79
0
  edit::EditedSource Editor(SM, LangOpts);
80
0
  if (Editor.commit(commit)) {
81
0
    FixitReceiver Rec(MergedFixits);
82
0
    Editor.applyRewrites(Rec);
83
0
  }
84
0
}
85
86
void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc,
87
                                        DiagnosticsEngine::Level Level,
88
                                        StringRef Message,
89
                                        ArrayRef<CharSourceRange> Ranges,
90
                                        ArrayRef<FixItHint> FixItHints,
91
0
                                        DiagOrStoredDiag D) {
92
0
  assert(Loc.hasManager() || Loc.isInvalid());
93
94
0
  beginDiagnostic(D, Level);
95
96
0
  if (!Loc.isValid())
97
    // If we have no source location, just emit the diagnostic message.
98
0
    emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, D);
99
0
  else {
100
    // Get the ranges into a local array we can hack on.
101
0
    SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
102
0
                                                   Ranges.end());
103
104
0
    SmallVector<FixItHint, 8> MergedFixits;
105
0
    if (!FixItHints.empty()) {
106
0
      mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits);
107
0
      FixItHints = MergedFixits;
108
0
    }
109
110
0
    for (const auto &Hint : FixItHints)
111
0
      if (Hint.RemoveRange.isValid())
112
0
        MutableRanges.push_back(Hint.RemoveRange);
113
114
0
    FullSourceLoc UnexpandedLoc = Loc;
115
116
    // Find the ultimate expansion location for the diagnostic.
117
0
    Loc = Loc.getFileLoc();
118
119
0
    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
0
    emitIncludeStack(Loc, PLoc, Level);
124
125
    // Next, emit the actual diagnostic message and caret.
126
0
    emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D);
127
0
    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
0
    if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
132
0
      emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
133
0
    }
134
0
  }
135
136
0
  LastLoc = Loc;
137
0
  LastLevel = Level;
138
139
0
  endDiagnostic(D, Level);
140
0
}
141
142
0
void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
143
0
  emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
144
0
                 Diag.getRanges(), Diag.getFixIts(),
145
0
                 &Diag);
146
0
}
147
148
0
void DiagnosticRenderer::emitBasicNote(StringRef Message) {
149
0
  emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note,
150
0
                        Message, std::nullopt, DiagOrStoredDiag());
151
0
}
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,
165
0
                                          DiagnosticsEngine::Level Level) {
166
0
  FullSourceLoc IncludeLoc =
167
0
      PLoc.isInvalid() ? FullSourceLoc()
168
0
                       : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager());
169
170
  // Skip redundant include stacks altogether.
171
0
  if (LastIncludeLoc == IncludeLoc)
172
0
    return;
173
174
0
  LastIncludeLoc = IncludeLoc;
175
176
0
  if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
177
0
    return;
178
179
0
  if (IncludeLoc.isValid())
180
0
    emitIncludeStackRecursively(IncludeLoc);
181
0
  else {
182
0
    emitModuleBuildStack(Loc.getManager());
183
0
    emitImportStack(Loc);
184
0
  }
185
0
}
186
187
/// Helper to recursively walk up the include stack and print each layer
188
/// on the way back down.
189
0
void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {
190
0
  if (Loc.isInvalid()) {
191
0
    emitModuleBuildStack(Loc.getManager());
192
0
    return;
193
0
  }
194
195
0
  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
196
0
  if (PLoc.isInvalid())
197
0
    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
0
  std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc();
203
0
  if (!Imported.second.empty()) {
204
    // This location was imported by a module. Emit the module import stack.
205
0
    emitImportStackRecursively(Imported.first, Imported.second);
206
0
    return;
207
0
  }
208
209
  // Emit the other include frames first.
210
0
  emitIncludeStackRecursively(
211
0
      FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()));
212
213
  // Emit the inclusion text/note.
214
0
  emitIncludeLocation(Loc, PLoc);
215
0
}
216
217
/// Emit the module import stack associated with the current location.
218
0
void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) {
219
0
  if (Loc.isInvalid()) {
220
0
    emitModuleBuildStack(Loc.getManager());
221
0
    return;
222
0
  }
223
224
0
  std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
225
0
  emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
226
0
}
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
0
                                                    StringRef ModuleName) {
232
0
  if (ModuleName.empty()) {
233
0
    return;
234
0
  }
235
236
0
  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
237
238
  // Emit the other import frames first.
239
0
  std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
240
0
  emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
241
242
  // Emit the inclusion text/note.
243
0
  emitImportLocation(Loc, PLoc, ModuleName);
244
0
}
245
246
/// Emit the module build stack, for cases where a module is (re-)built
247
/// on demand.
248
0
void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
249
0
  ModuleBuildStack Stack = SM.getModuleBuildStack();
250
0
  for (const auto &I : Stack) {
251
0
    emitBuildingModuleLocation(I.second, I.second.getPresumedLoc(
252
0
                                              DiagOpts->ShowPresumedLoc),
253
0
                               I.first);
254
0
  }
255
0
}
256
257
/// A recursive function to trace all possible backtrace locations
258
/// to match the \p CaretLocFileID.
259
static SourceLocation
260
retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID,
261
                      FileID CaretFileID,
262
                      const SmallVectorImpl<FileID> &CommonArgExpansions,
263
                      bool IsBegin, const SourceManager *SM,
264
0
                      bool &IsTokenRange) {
265
0
  assert(SM->getFileID(Loc) == MacroFileID);
266
0
  if (MacroFileID == CaretFileID)
267
0
    return Loc;
268
0
  if (!Loc.isMacroID())
269
0
    return {};
270
271
0
  CharSourceRange MacroRange, MacroArgRange;
272
273
0
  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
0
    if (std::binary_search(CommonArgExpansions.begin(),
277
0
                           CommonArgExpansions.end(), MacroFileID))
278
0
      MacroRange =
279
0
          CharSourceRange(SM->getImmediateSpellingLoc(Loc), IsTokenRange);
280
0
    MacroArgRange = SM->getImmediateExpansionRange(Loc);
281
0
  } else {
282
0
    MacroRange = SM->getImmediateExpansionRange(Loc);
283
0
    MacroArgRange =
284
0
        CharSourceRange(SM->getImmediateSpellingLoc(Loc), IsTokenRange);
285
0
  }
286
287
0
  SourceLocation MacroLocation =
288
0
      IsBegin ? MacroRange.getBegin() : MacroRange.getEnd();
289
0
  if (MacroLocation.isValid()) {
290
0
    MacroFileID = SM->getFileID(MacroLocation);
291
0
    bool TokenRange = IsBegin ? IsTokenRange : MacroRange.isTokenRange();
292
0
    MacroLocation =
293
0
        retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID,
294
0
                              CommonArgExpansions, IsBegin, SM, TokenRange);
295
0
    if (MacroLocation.isValid()) {
296
0
      IsTokenRange = TokenRange;
297
0
      return MacroLocation;
298
0
    }
299
0
  }
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
0
  if (!IsBegin)
304
0
    IsTokenRange = MacroArgRange.isTokenRange();
305
306
0
  SourceLocation MacroArgLocation =
307
0
      IsBegin ? MacroArgRange.getBegin() : MacroArgRange.getEnd();
308
0
  MacroFileID = SM->getFileID(MacroArgLocation);
309
0
  return retrieveMacroLocation(MacroArgLocation, MacroFileID, CaretFileID,
310
0
                               CommonArgExpansions, IsBegin, SM, IsTokenRange);
311
0
}
312
313
/// Walk up the chain of macro expansions and collect the FileIDs identifying the
314
/// expansions.
315
static void getMacroArgExpansionFileIDs(SourceLocation Loc,
316
                                        SmallVectorImpl<FileID> &IDs,
317
0
                                        bool IsBegin, const SourceManager *SM) {
318
0
  while (Loc.isMacroID()) {
319
0
    if (SM->isMacroArgExpansion(Loc)) {
320
0
      IDs.push_back(SM->getFileID(Loc));
321
0
      Loc = SM->getImmediateSpellingLoc(Loc);
322
0
    } else {
323
0
      auto ExpRange = SM->getImmediateExpansionRange(Loc);
324
0
      Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd();
325
0
    }
326
0
  }
327
0
}
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.
331
static void computeCommonMacroArgExpansionFileIDs(
332
    SourceLocation Begin, SourceLocation End, const SourceManager *SM,
333
0
    SmallVectorImpl<FileID> &CommonArgExpansions) {
334
0
  SmallVector<FileID, 4> BeginArgExpansions;
335
0
  SmallVector<FileID, 4> EndArgExpansions;
336
0
  getMacroArgExpansionFileIDs(Begin, BeginArgExpansions, /*IsBegin=*/true, SM);
337
0
  getMacroArgExpansionFileIDs(End, EndArgExpansions, /*IsBegin=*/false, SM);
338
0
  llvm::sort(BeginArgExpansions);
339
0
  llvm::sort(EndArgExpansions);
340
0
  std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
341
0
                        EndArgExpansions.begin(), EndArgExpansions.end(),
342
0
                        std::back_inserter(CommonArgExpansions));
343
0
}
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
356
mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef<CharSourceRange> Ranges,
357
0
                    SmallVectorImpl<CharSourceRange> &SpellingRanges) {
358
0
  FileID CaretLocFileID = CaretLoc.getFileID();
359
360
0
  const SourceManager *SM = &CaretLoc.getManager();
361
362
0
  for (const auto &Range : Ranges) {
363
0
    if (Range.isInvalid())
364
0
      continue;
365
366
0
    SourceLocation Begin = Range.getBegin(), End = Range.getEnd();
367
0
    bool IsTokenRange = Range.isTokenRange();
368
369
0
    FileID BeginFileID = SM->getFileID(Begin);
370
0
    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
0
    llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
376
0
    while (Begin.isMacroID() && BeginFileID != EndFileID) {
377
0
      BeginLocsMap[BeginFileID] = Begin;
378
0
      Begin = SM->getImmediateExpansionRange(Begin).getBegin();
379
0
      BeginFileID = SM->getFileID(Begin);
380
0
    }
381
382
    // Then, crawl the expansion chain for the end of the range.
383
0
    if (BeginFileID != EndFileID) {
384
0
      while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
385
0
        auto Exp = SM->getImmediateExpansionRange(End);
386
0
        IsTokenRange = Exp.isTokenRange();
387
0
        End = Exp.getEnd();
388
0
        EndFileID = SM->getFileID(End);
389
0
      }
390
0
      if (End.isMacroID()) {
391
0
        Begin = BeginLocsMap[EndFileID];
392
0
        BeginFileID = EndFileID;
393
0
      }
394
0
    }
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
0
    if (Begin.isInvalid() || End.isInvalid() || BeginFileID != EndFileID)
401
0
      continue;
402
403
    // Do the backtracking.
404
0
    SmallVector<FileID, 4> CommonArgExpansions;
405
0
    computeCommonMacroArgExpansionFileIDs(Begin, End, SM, CommonArgExpansions);
406
0
    Begin = retrieveMacroLocation(Begin, BeginFileID, CaretLocFileID,
407
0
                                  CommonArgExpansions, /*IsBegin=*/true, SM,
408
0
                                  IsTokenRange);
409
0
    End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID,
410
0
                                CommonArgExpansions, /*IsBegin=*/false, SM,
411
0
                                IsTokenRange);
412
0
    if (Begin.isInvalid() || End.isInvalid()) continue;
413
414
    // Return the spelling location of the beginning and end of the range.
415
0
    Begin = SM->getSpellingLoc(Begin);
416
0
    End = SM->getSpellingLoc(End);
417
418
0
    SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End),
419
0
                                             IsTokenRange));
420
0
  }
421
0
}
422
423
void DiagnosticRenderer::emitCaret(FullSourceLoc Loc,
424
                                   DiagnosticsEngine::Level Level,
425
                                   ArrayRef<CharSourceRange> Ranges,
426
0
                                   ArrayRef<FixItHint> Hints) {
427
0
  SmallVector<CharSourceRange, 4> SpellingRanges;
428
0
  mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
429
0
  emitCodeContext(Loc, Level, SpellingRanges, Hints);
430
0
}
431
432
/// A helper function for emitMacroExpansion to print the
433
/// macro expansion message
434
void DiagnosticRenderer::emitSingleMacroExpansion(
435
    FullSourceLoc Loc, DiagnosticsEngine::Level Level,
436
0
    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
0
  FullSourceLoc SpellingLoc = Loc.getSpellingLoc();
440
441
  // Map the ranges into the FileID of the diagnostic location.
442
0
  SmallVector<CharSourceRange, 4> SpellingRanges;
443
0
  mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
444
445
0
  SmallString<100> MessageStorage;
446
0
  llvm::raw_svector_ostream Message(MessageStorage);
447
0
  StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
448
0
      Loc, Loc.getManager(), LangOpts);
449
0
  if (MacroName.empty())
450
0
    Message << "expanded from here";
451
0
  else
452
0
    Message << "expanded from macro '" << MacroName << "'";
453
454
0
  emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(),
455
0
                 SpellingRanges, std::nullopt);
456
0
}
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.
461
static bool checkLocForMacroArgExpansion(SourceLocation Loc,
462
                                         const SourceManager &SM,
463
0
                                         SourceLocation ArgumentLoc) {
464
0
  SourceLocation MacroLoc;
465
0
  if (SM.isMacroArgExpansion(Loc, &MacroLoc)) {
466
0
    if (ArgumentLoc == MacroLoc) return true;
467
0
  }
468
469
0
  return false;
470
0
}
471
472
/// Check if all the locations in the range have the same macro argument
473
/// expansion, and that the expansion starts with ArgumentLoc.
474
static bool checkRangeForMacroArgExpansion(CharSourceRange Range,
475
                                           const SourceManager &SM,
476
0
                                           SourceLocation ArgumentLoc) {
477
0
  SourceLocation BegLoc = Range.getBegin(), EndLoc = Range.getEnd();
478
0
  while (BegLoc != EndLoc) {
479
0
    if (!checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc))
480
0
      return false;
481
0
    BegLoc.getLocWithOffset(1);
482
0
  }
483
484
0
  return checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc);
485
0
}
486
487
/// A helper function to check if the current ranges are all inside the same
488
/// macro argument expansion as Loc.
489
static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc,
490
0
                                            ArrayRef<CharSourceRange> Ranges) {
491
0
  assert(Loc.isMacroID() && "Must be a macro expansion!");
492
493
0
  SmallVector<CharSourceRange, 4> SpellingRanges;
494
0
  mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
495
496
  // Count all valid ranges.
497
0
  unsigned ValidCount =
498
0
      llvm::count_if(Ranges, [](const auto &R) { return R.isValid(); });
499
500
0
  if (ValidCount > SpellingRanges.size())
501
0
    return false;
502
503
  // To store the source location of the argument location.
504
0
  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
0
  if (!Loc.isMacroArgExpansion(&ArgumentLoc))
509
0
    return false;
510
511
0
  for (const auto &Range : SpellingRanges)
512
0
    if (!checkRangeForMacroArgExpansion(Range, Loc.getManager(), ArgumentLoc))
513
0
      return false;
514
515
0
  return true;
516
0
}
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,
530
                                             DiagnosticsEngine::Level Level,
531
                                             ArrayRef<CharSourceRange> Ranges,
532
0
                                             ArrayRef<FixItHint> Hints) {
533
0
  assert(Loc.isValid() && "must have a valid source location here");
534
0
  const SourceManager &SM = Loc.getManager();
535
0
  SourceLocation L = Loc;
536
537
  // Produce a stack of macro backtraces.
538
0
  SmallVector<SourceLocation, 8> LocationStack;
539
0
  unsigned IgnoredEnd = 0;
540
0
  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
0
    if (SM.isMacroArgExpansion(L))
544
0
      LocationStack.push_back(SM.getImmediateExpansionRange(L).getBegin());
545
0
    else
546
0
      LocationStack.push_back(L);
547
548
0
    if (checkRangesForMacroArgExpansion(FullSourceLoc(L, SM), Ranges))
549
0
      IgnoredEnd = LocationStack.size();
550
551
0
    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
0
    if (L.isFileID())
557
0
      L = SM.getImmediateMacroCallerLoc(LocationStack.back());
558
0
    assert(L.isValid() && "must have a valid source location here");
559
0
  }
560
561
0
  LocationStack.erase(LocationStack.begin(),
562
0
                      LocationStack.begin() + IgnoredEnd);
563
564
0
  unsigned MacroDepth = LocationStack.size();
565
0
  unsigned MacroLimit = DiagOpts->MacroBacktraceLimit;
566
0
  if (MacroDepth <= MacroLimit || MacroLimit == 0) {
567
0
    for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
568
0
         I != E; ++I)
569
0
      emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);
570
0
    return;
571
0
  }
572
573
0
  unsigned MacroStartMessages = MacroLimit / 2;
574
0
  unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
575
576
0
  for (auto I = LocationStack.rbegin(),
577
0
            E = LocationStack.rbegin() + MacroStartMessages;
578
0
       I != E; ++I)
579
0
    emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);
580
581
0
  SmallString<200> MessageStorage;
582
0
  llvm::raw_svector_ostream Message(MessageStorage);
583
0
  Message << "(skipping " << (MacroDepth - MacroLimit)
584
0
          << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
585
0
             "see all)";
586
0
  emitBasicNote(Message.str());
587
588
0
  for (auto I = LocationStack.rend() - MacroEndMessages,
589
0
            E = LocationStack.rend();
590
0
       I != E; ++I)
591
0
    emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);
592
0
}
593
594
DiagnosticNoteRenderer::~DiagnosticNoteRenderer() = default;
595
596
void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc,
597
0
                                                 PresumedLoc PLoc) {
598
  // Generate a note indicating the include location.
599
0
  SmallString<200> MessageStorage;
600
0
  llvm::raw_svector_ostream Message(MessageStorage);
601
0
  Message << "in file included from " << PLoc.getFilename() << ':'
602
0
          << PLoc.getLine() << ":";
603
0
  emitNote(Loc, Message.str());
604
0
}
605
606
void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc,
607
                                                PresumedLoc PLoc,
608
0
                                                StringRef ModuleName) {
609
  // Generate a note indicating the include location.
610
0
  SmallString<200> MessageStorage;
611
0
  llvm::raw_svector_ostream Message(MessageStorage);
612
0
  Message << "in module '" << ModuleName;
613
0
  if (PLoc.isValid())
614
0
    Message << "' imported from " << PLoc.getFilename() << ':'
615
0
            << PLoc.getLine();
616
0
  Message << ":";
617
0
  emitNote(Loc, Message.str());
618
0
}
619
620
void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc,
621
                                                        PresumedLoc PLoc,
622
0
                                                        StringRef ModuleName) {
623
  // Generate a note indicating the include location.
624
0
  SmallString<200> MessageStorage;
625
0
  llvm::raw_svector_ostream Message(MessageStorage);
626
0
  if (PLoc.isValid())
627
0
    Message << "while building module '" << ModuleName << "' imported from "
628
0
            << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
629
0
  else
630
0
    Message << "while building module '" << ModuleName << "':";
631
0
  emitNote(Loc, Message.str());
632
0
}