Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Basic/Diagnostic.cpp
35234 views
1
//===- Diagnostic.cpp - C Language Family Diagnostic Handling -------------===//
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
// This file implements the Diagnostic-related interfaces.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/Basic/Diagnostic.h"
14
#include "clang/Basic/CharInfo.h"
15
#include "clang/Basic/DiagnosticError.h"
16
#include "clang/Basic/DiagnosticIDs.h"
17
#include "clang/Basic/DiagnosticOptions.h"
18
#include "clang/Basic/IdentifierTable.h"
19
#include "clang/Basic/PartialDiagnostic.h"
20
#include "clang/Basic/SourceLocation.h"
21
#include "clang/Basic/SourceManager.h"
22
#include "clang/Basic/Specifiers.h"
23
#include "clang/Basic/TokenKinds.h"
24
#include "llvm/ADT/SmallString.h"
25
#include "llvm/ADT/SmallVector.h"
26
#include "llvm/ADT/StringExtras.h"
27
#include "llvm/ADT/StringRef.h"
28
#include "llvm/Support/ConvertUTF.h"
29
#include "llvm/Support/CrashRecoveryContext.h"
30
#include "llvm/Support/Unicode.h"
31
#include "llvm/Support/raw_ostream.h"
32
#include <algorithm>
33
#include <cassert>
34
#include <cstddef>
35
#include <cstdint>
36
#include <cstring>
37
#include <limits>
38
#include <string>
39
#include <utility>
40
#include <vector>
41
42
using namespace clang;
43
44
const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
45
DiagNullabilityKind nullability) {
46
DB.AddString(
47
("'" +
48
getNullabilitySpelling(nullability.first,
49
/*isContextSensitive=*/nullability.second) +
50
"'")
51
.str());
52
return DB;
53
}
54
55
const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
56
llvm::Error &&E) {
57
DB.AddString(toString(std::move(E)));
58
return DB;
59
}
60
61
static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
62
StringRef Modifier, StringRef Argument,
63
ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,
64
SmallVectorImpl<char> &Output,
65
void *Cookie,
66
ArrayRef<intptr_t> QualTypeVals) {
67
StringRef Str = "<can't format argument>";
68
Output.append(Str.begin(), Str.end());
69
}
70
71
DiagnosticsEngine::DiagnosticsEngine(
72
IntrusiveRefCntPtr<DiagnosticIDs> diags,
73
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, DiagnosticConsumer *client,
74
bool ShouldOwnClient)
75
: Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) {
76
setClient(client, ShouldOwnClient);
77
ArgToStringFn = DummyArgToStringFn;
78
79
Reset();
80
}
81
82
DiagnosticsEngine::~DiagnosticsEngine() {
83
// If we own the diagnostic client, destroy it first so that it can access the
84
// engine from its destructor.
85
setClient(nullptr);
86
}
87
88
void DiagnosticsEngine::dump() const {
89
DiagStatesByLoc.dump(*SourceMgr);
90
}
91
92
void DiagnosticsEngine::dump(StringRef DiagName) const {
93
DiagStatesByLoc.dump(*SourceMgr, DiagName);
94
}
95
96
void DiagnosticsEngine::setClient(DiagnosticConsumer *client,
97
bool ShouldOwnClient) {
98
Owner.reset(ShouldOwnClient ? client : nullptr);
99
Client = client;
100
}
101
102
void DiagnosticsEngine::pushMappings(SourceLocation Loc) {
103
DiagStateOnPushStack.push_back(GetCurDiagState());
104
}
105
106
bool DiagnosticsEngine::popMappings(SourceLocation Loc) {
107
if (DiagStateOnPushStack.empty())
108
return false;
109
110
if (DiagStateOnPushStack.back() != GetCurDiagState()) {
111
// State changed at some point between push/pop.
112
PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
113
}
114
DiagStateOnPushStack.pop_back();
115
return true;
116
}
117
118
void DiagnosticsEngine::Reset(bool soft /*=false*/) {
119
ErrorOccurred = false;
120
UncompilableErrorOccurred = false;
121
FatalErrorOccurred = false;
122
UnrecoverableErrorOccurred = false;
123
124
NumWarnings = 0;
125
NumErrors = 0;
126
TrapNumErrorsOccurred = 0;
127
TrapNumUnrecoverableErrorsOccurred = 0;
128
129
CurDiagID = std::numeric_limits<unsigned>::max();
130
LastDiagLevel = DiagnosticIDs::Ignored;
131
DelayedDiagID = 0;
132
133
if (!soft) {
134
// Clear state related to #pragma diagnostic.
135
DiagStates.clear();
136
DiagStatesByLoc.clear();
137
DiagStateOnPushStack.clear();
138
139
// Create a DiagState and DiagStatePoint representing diagnostic changes
140
// through command-line.
141
DiagStates.emplace_back();
142
DiagStatesByLoc.appendFirst(&DiagStates.back());
143
}
144
}
145
146
void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
147
StringRef Arg2, StringRef Arg3) {
148
if (DelayedDiagID)
149
return;
150
151
DelayedDiagID = DiagID;
152
DelayedDiagArg1 = Arg1.str();
153
DelayedDiagArg2 = Arg2.str();
154
DelayedDiagArg3 = Arg3.str();
155
}
156
157
void DiagnosticsEngine::ReportDelayed() {
158
unsigned ID = DelayedDiagID;
159
DelayedDiagID = 0;
160
Report(ID) << DelayedDiagArg1 << DelayedDiagArg2 << DelayedDiagArg3;
161
}
162
163
DiagnosticMapping &
164
DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) {
165
std::pair<iterator, bool> Result =
166
DiagMap.insert(std::make_pair(Diag, DiagnosticMapping()));
167
168
// Initialize the entry if we added it.
169
if (Result.second)
170
Result.first->second = DiagnosticIDs::getDefaultMapping(Diag);
171
172
return Result.first->second;
173
}
174
175
void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState *State) {
176
assert(Files.empty() && "not first");
177
FirstDiagState = CurDiagState = State;
178
CurDiagStateLoc = SourceLocation();
179
}
180
181
void DiagnosticsEngine::DiagStateMap::append(SourceManager &SrcMgr,
182
SourceLocation Loc,
183
DiagState *State) {
184
CurDiagState = State;
185
CurDiagStateLoc = Loc;
186
187
std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
188
unsigned Offset = Decomp.second;
189
for (File *F = getFile(SrcMgr, Decomp.first); F;
190
Offset = F->ParentOffset, F = F->Parent) {
191
F->HasLocalTransitions = true;
192
auto &Last = F->StateTransitions.back();
193
assert(Last.Offset <= Offset && "state transitions added out of order");
194
195
if (Last.Offset == Offset) {
196
if (Last.State == State)
197
break;
198
Last.State = State;
199
continue;
200
}
201
202
F->StateTransitions.push_back({State, Offset});
203
}
204
}
205
206
DiagnosticsEngine::DiagState *
207
DiagnosticsEngine::DiagStateMap::lookup(SourceManager &SrcMgr,
208
SourceLocation Loc) const {
209
// Common case: we have not seen any diagnostic pragmas.
210
if (Files.empty())
211
return FirstDiagState;
212
213
std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
214
const File *F = getFile(SrcMgr, Decomp.first);
215
return F->lookup(Decomp.second);
216
}
217
218
DiagnosticsEngine::DiagState *
219
DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const {
220
auto OnePastIt =
221
llvm::partition_point(StateTransitions, [=](const DiagStatePoint &P) {
222
return P.Offset <= Offset;
223
});
224
assert(OnePastIt != StateTransitions.begin() && "missing initial state");
225
return OnePastIt[-1].State;
226
}
227
228
DiagnosticsEngine::DiagStateMap::File *
229
DiagnosticsEngine::DiagStateMap::getFile(SourceManager &SrcMgr,
230
FileID ID) const {
231
// Get or insert the File for this ID.
232
auto Range = Files.equal_range(ID);
233
if (Range.first != Range.second)
234
return &Range.first->second;
235
auto &F = Files.insert(Range.first, std::make_pair(ID, File()))->second;
236
237
// We created a new File; look up the diagnostic state at the start of it and
238
// initialize it.
239
if (ID.isValid()) {
240
std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedIncludedLoc(ID);
241
F.Parent = getFile(SrcMgr, Decomp.first);
242
F.ParentOffset = Decomp.second;
243
F.StateTransitions.push_back({F.Parent->lookup(Decomp.second), 0});
244
} else {
245
// This is the (imaginary) root file into which we pretend all top-level
246
// files are included; it descends from the initial state.
247
//
248
// FIXME: This doesn't guarantee that we use the same ordering as
249
// isBeforeInTranslationUnit in the cases where someone invented another
250
// top-level file and added diagnostic pragmas to it. See the code at the
251
// end of isBeforeInTranslationUnit for the quirks it deals with.
252
F.StateTransitions.push_back({FirstDiagState, 0});
253
}
254
return &F;
255
}
256
257
void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr,
258
StringRef DiagName) const {
259
llvm::errs() << "diagnostic state at ";
260
CurDiagStateLoc.print(llvm::errs(), SrcMgr);
261
llvm::errs() << ": " << CurDiagState << "\n";
262
263
for (auto &F : Files) {
264
FileID ID = F.first;
265
File &File = F.second;
266
267
bool PrintedOuterHeading = false;
268
auto PrintOuterHeading = [&] {
269
if (PrintedOuterHeading) return;
270
PrintedOuterHeading = true;
271
272
llvm::errs() << "File " << &File << " <FileID " << ID.getHashValue()
273
<< ">: " << SrcMgr.getBufferOrFake(ID).getBufferIdentifier();
274
275
if (F.second.Parent) {
276
std::pair<FileID, unsigned> Decomp =
277
SrcMgr.getDecomposedIncludedLoc(ID);
278
assert(File.ParentOffset == Decomp.second);
279
llvm::errs() << " parent " << File.Parent << " <FileID "
280
<< Decomp.first.getHashValue() << "> ";
281
SrcMgr.getLocForStartOfFile(Decomp.first)
282
.getLocWithOffset(Decomp.second)
283
.print(llvm::errs(), SrcMgr);
284
}
285
if (File.HasLocalTransitions)
286
llvm::errs() << " has_local_transitions";
287
llvm::errs() << "\n";
288
};
289
290
if (DiagName.empty())
291
PrintOuterHeading();
292
293
for (DiagStatePoint &Transition : File.StateTransitions) {
294
bool PrintedInnerHeading = false;
295
auto PrintInnerHeading = [&] {
296
if (PrintedInnerHeading) return;
297
PrintedInnerHeading = true;
298
299
PrintOuterHeading();
300
llvm::errs() << " ";
301
SrcMgr.getLocForStartOfFile(ID)
302
.getLocWithOffset(Transition.Offset)
303
.print(llvm::errs(), SrcMgr);
304
llvm::errs() << ": state " << Transition.State << ":\n";
305
};
306
307
if (DiagName.empty())
308
PrintInnerHeading();
309
310
for (auto &Mapping : *Transition.State) {
311
StringRef Option =
312
DiagnosticIDs::getWarningOptionForDiag(Mapping.first);
313
if (!DiagName.empty() && DiagName != Option)
314
continue;
315
316
PrintInnerHeading();
317
llvm::errs() << " ";
318
if (Option.empty())
319
llvm::errs() << "<unknown " << Mapping.first << ">";
320
else
321
llvm::errs() << Option;
322
llvm::errs() << ": ";
323
324
switch (Mapping.second.getSeverity()) {
325
case diag::Severity::Ignored: llvm::errs() << "ignored"; break;
326
case diag::Severity::Remark: llvm::errs() << "remark"; break;
327
case diag::Severity::Warning: llvm::errs() << "warning"; break;
328
case diag::Severity::Error: llvm::errs() << "error"; break;
329
case diag::Severity::Fatal: llvm::errs() << "fatal"; break;
330
}
331
332
if (!Mapping.second.isUser())
333
llvm::errs() << " default";
334
if (Mapping.second.isPragma())
335
llvm::errs() << " pragma";
336
if (Mapping.second.hasNoWarningAsError())
337
llvm::errs() << " no-error";
338
if (Mapping.second.hasNoErrorAsFatal())
339
llvm::errs() << " no-fatal";
340
if (Mapping.second.wasUpgradedFromWarning())
341
llvm::errs() << " overruled";
342
llvm::errs() << "\n";
343
}
344
}
345
}
346
}
347
348
void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,
349
SourceLocation Loc) {
350
assert(Loc.isValid() && "Adding invalid loc point");
351
DiagStatesByLoc.append(*SourceMgr, Loc, State);
352
}
353
354
void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
355
SourceLocation L) {
356
assert(Diag < diag::DIAG_UPPER_LIMIT &&
357
"Can only map builtin diagnostics");
358
assert((Diags->isBuiltinWarningOrExtension(Diag) ||
359
(Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
360
"Cannot map errors into warnings!");
361
assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
362
363
// A command line -Wfoo has an invalid L and cannot override error/fatal
364
// mapping, while a warning pragma can.
365
bool WasUpgradedFromWarning = false;
366
if (Map == diag::Severity::Warning && L.isInvalid()) {
367
DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
368
if (Info.getSeverity() == diag::Severity::Error ||
369
Info.getSeverity() == diag::Severity::Fatal) {
370
Map = Info.getSeverity();
371
WasUpgradedFromWarning = true;
372
}
373
}
374
DiagnosticMapping Mapping = makeUserMapping(Map, L);
375
Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
376
377
// Make sure we propagate the NoWarningAsError flag from an existing
378
// mapping (which may be the default mapping).
379
DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
380
Mapping.setNoWarningAsError(Info.hasNoWarningAsError() ||
381
Mapping.hasNoWarningAsError());
382
383
// Common case; setting all the diagnostics of a group in one place.
384
if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) &&
385
DiagStatesByLoc.getCurDiagState()) {
386
// FIXME: This is theoretically wrong: if the current state is shared with
387
// some other location (via push/pop) we will change the state for that
388
// other location as well. This cannot currently happen, as we can't update
389
// the diagnostic state at the same location at which we pop.
390
DiagStatesByLoc.getCurDiagState()->setMapping(Diag, Mapping);
391
return;
392
}
393
394
// A diagnostic pragma occurred, create a new DiagState initialized with
395
// the current one and a new DiagStatePoint to record at which location
396
// the new state became active.
397
DiagStates.push_back(*GetCurDiagState());
398
DiagStates.back().setMapping(Diag, Mapping);
399
PushDiagStatePoint(&DiagStates.back(), L);
400
}
401
402
bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
403
StringRef Group, diag::Severity Map,
404
SourceLocation Loc) {
405
// Get the diagnostics in this group.
406
SmallVector<diag::kind, 256> GroupDiags;
407
if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
408
return true;
409
410
// Set the mapping.
411
for (diag::kind Diag : GroupDiags)
412
setSeverity(Diag, Map, Loc);
413
414
return false;
415
}
416
417
bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
418
diag::Group Group,
419
diag::Severity Map,
420
SourceLocation Loc) {
421
return setSeverityForGroup(Flavor, Diags->getWarningOptionForGroup(Group),
422
Map, Loc);
423
}
424
425
bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
426
bool Enabled) {
427
// If we are enabling this feature, just set the diagnostic mappings to map to
428
// errors.
429
if (Enabled)
430
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
431
diag::Severity::Error);
432
433
// Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
434
// potentially downgrade anything already mapped to be a warning.
435
436
// Get the diagnostics in this group.
437
SmallVector<diag::kind, 8> GroupDiags;
438
if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
439
GroupDiags))
440
return true;
441
442
// Perform the mapping change.
443
for (diag::kind Diag : GroupDiags) {
444
DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
445
446
if (Info.getSeverity() == diag::Severity::Error ||
447
Info.getSeverity() == diag::Severity::Fatal)
448
Info.setSeverity(diag::Severity::Warning);
449
450
Info.setNoWarningAsError(true);
451
}
452
453
return false;
454
}
455
456
bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
457
bool Enabled) {
458
// If we are enabling this feature, just set the diagnostic mappings to map to
459
// fatal errors.
460
if (Enabled)
461
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
462
diag::Severity::Fatal);
463
464
// Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
465
// and potentially downgrade anything already mapped to be a fatal error.
466
467
// Get the diagnostics in this group.
468
SmallVector<diag::kind, 8> GroupDiags;
469
if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
470
GroupDiags))
471
return true;
472
473
// Perform the mapping change.
474
for (diag::kind Diag : GroupDiags) {
475
DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
476
477
if (Info.getSeverity() == diag::Severity::Fatal)
478
Info.setSeverity(diag::Severity::Error);
479
480
Info.setNoErrorAsFatal(true);
481
}
482
483
return false;
484
}
485
486
void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor,
487
diag::Severity Map,
488
SourceLocation Loc) {
489
// Get all the diagnostics.
490
std::vector<diag::kind> AllDiags;
491
DiagnosticIDs::getAllDiagnostics(Flavor, AllDiags);
492
493
// Set the mapping.
494
for (diag::kind Diag : AllDiags)
495
if (Diags->isBuiltinWarningOrExtension(Diag))
496
setSeverity(Diag, Map, Loc);
497
}
498
499
void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
500
assert(CurDiagID == std::numeric_limits<unsigned>::max() &&
501
"Multiple diagnostics in flight at once!");
502
503
CurDiagLoc = storedDiag.getLocation();
504
CurDiagID = storedDiag.getID();
505
DiagStorage.NumDiagArgs = 0;
506
507
DiagStorage.DiagRanges.clear();
508
DiagStorage.DiagRanges.append(storedDiag.range_begin(),
509
storedDiag.range_end());
510
511
DiagStorage.FixItHints.clear();
512
DiagStorage.FixItHints.append(storedDiag.fixit_begin(),
513
storedDiag.fixit_end());
514
515
assert(Client && "DiagnosticConsumer not set!");
516
Level DiagLevel = storedDiag.getLevel();
517
Diagnostic Info(this, storedDiag.getMessage());
518
Client->HandleDiagnostic(DiagLevel, Info);
519
if (Client->IncludeInDiagnosticCounts()) {
520
if (DiagLevel == DiagnosticsEngine::Warning)
521
++NumWarnings;
522
}
523
524
CurDiagID = std::numeric_limits<unsigned>::max();
525
}
526
527
bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) {
528
assert(getClient() && "DiagnosticClient not set!");
529
530
bool Emitted;
531
if (Force) {
532
Diagnostic Info(this);
533
534
// Figure out the diagnostic level of this message.
535
DiagnosticIDs::Level DiagLevel
536
= Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this);
537
538
Emitted = (DiagLevel != DiagnosticIDs::Ignored);
539
if (Emitted) {
540
// Emit the diagnostic regardless of suppression level.
541
Diags->EmitDiag(*this, DiagLevel);
542
}
543
} else {
544
// Process the diagnostic, sending the accumulated information to the
545
// DiagnosticConsumer.
546
Emitted = ProcessDiag();
547
}
548
549
// Clear out the current diagnostic object.
550
Clear();
551
552
// If there was a delayed diagnostic, emit it now.
553
if (!Force && DelayedDiagID)
554
ReportDelayed();
555
556
return Emitted;
557
}
558
559
DiagnosticConsumer::~DiagnosticConsumer() = default;
560
561
void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
562
const Diagnostic &Info) {
563
if (!IncludeInDiagnosticCounts())
564
return;
565
566
if (DiagLevel == DiagnosticsEngine::Warning)
567
++NumWarnings;
568
else if (DiagLevel >= DiagnosticsEngine::Error)
569
++NumErrors;
570
}
571
572
/// ModifierIs - Return true if the specified modifier matches specified string.
573
template <std::size_t StrLen>
574
static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
575
const char (&Str)[StrLen]) {
576
return StrLen-1 == ModifierLen && memcmp(Modifier, Str, StrLen-1) == 0;
577
}
578
579
/// ScanForward - Scans forward, looking for the given character, skipping
580
/// nested clauses and escaped characters.
581
static const char *ScanFormat(const char *I, const char *E, char Target) {
582
unsigned Depth = 0;
583
584
for ( ; I != E; ++I) {
585
if (Depth == 0 && *I == Target) return I;
586
if (Depth != 0 && *I == '}') Depth--;
587
588
if (*I == '%') {
589
I++;
590
if (I == E) break;
591
592
// Escaped characters get implicitly skipped here.
593
594
// Format specifier.
595
if (!isDigit(*I) && !isPunctuation(*I)) {
596
for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ;
597
if (I == E) break;
598
if (*I == '{')
599
Depth++;
600
}
601
}
602
}
603
return E;
604
}
605
606
/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
607
/// like this: %select{foo|bar|baz}2. This means that the integer argument
608
/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
609
/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
610
/// This is very useful for certain classes of variant diagnostics.
611
static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
612
const char *Argument, unsigned ArgumentLen,
613
SmallVectorImpl<char> &OutStr) {
614
const char *ArgumentEnd = Argument+ArgumentLen;
615
616
// Skip over 'ValNo' |'s.
617
while (ValNo) {
618
const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
619
assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
620
" larger than the number of options in the diagnostic string!");
621
Argument = NextVal+1; // Skip this string.
622
--ValNo;
623
}
624
625
// Get the end of the value. This is either the } or the |.
626
const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
627
628
// Recursively format the result of the select clause into the output string.
629
DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
630
}
631
632
/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
633
/// letter 's' to the string if the value is not 1. This is used in cases like
634
/// this: "you idiot, you have %4 parameter%s4!".
635
static void HandleIntegerSModifier(unsigned ValNo,
636
SmallVectorImpl<char> &OutStr) {
637
if (ValNo != 1)
638
OutStr.push_back('s');
639
}
640
641
/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
642
/// prints the ordinal form of the given integer, with 1 corresponding
643
/// to the first ordinal. Currently this is hard-coded to use the
644
/// English form.
645
static void HandleOrdinalModifier(unsigned ValNo,
646
SmallVectorImpl<char> &OutStr) {
647
assert(ValNo != 0 && "ValNo must be strictly positive!");
648
649
llvm::raw_svector_ostream Out(OutStr);
650
651
// We could use text forms for the first N ordinals, but the numeric
652
// forms are actually nicer in diagnostics because they stand out.
653
Out << ValNo << llvm::getOrdinalSuffix(ValNo);
654
}
655
656
/// PluralNumber - Parse an unsigned integer and advance Start.
657
static unsigned PluralNumber(const char *&Start, const char *End) {
658
// Programming 101: Parse a decimal number :-)
659
unsigned Val = 0;
660
while (Start != End && *Start >= '0' && *Start <= '9') {
661
Val *= 10;
662
Val += *Start - '0';
663
++Start;
664
}
665
return Val;
666
}
667
668
/// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
669
static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
670
if (*Start != '[') {
671
unsigned Ref = PluralNumber(Start, End);
672
return Ref == Val;
673
}
674
675
++Start;
676
unsigned Low = PluralNumber(Start, End);
677
assert(*Start == ',' && "Bad plural expression syntax: expected ,");
678
++Start;
679
unsigned High = PluralNumber(Start, End);
680
assert(*Start == ']' && "Bad plural expression syntax: expected )");
681
++Start;
682
return Low <= Val && Val <= High;
683
}
684
685
/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
686
static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
687
// Empty condition?
688
if (*Start == ':')
689
return true;
690
691
while (true) {
692
char C = *Start;
693
if (C == '%') {
694
// Modulo expression
695
++Start;
696
unsigned Arg = PluralNumber(Start, End);
697
assert(*Start == '=' && "Bad plural expression syntax: expected =");
698
++Start;
699
unsigned ValMod = ValNo % Arg;
700
if (TestPluralRange(ValMod, Start, End))
701
return true;
702
} else {
703
assert((C == '[' || (C >= '0' && C <= '9')) &&
704
"Bad plural expression syntax: unexpected character");
705
// Range expression
706
if (TestPluralRange(ValNo, Start, End))
707
return true;
708
}
709
710
// Scan for next or-expr part.
711
Start = std::find(Start, End, ',');
712
if (Start == End)
713
break;
714
++Start;
715
}
716
return false;
717
}
718
719
/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
720
/// for complex plural forms, or in languages where all plurals are complex.
721
/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
722
/// conditions that are tested in order, the form corresponding to the first
723
/// that applies being emitted. The empty condition is always true, making the
724
/// last form a default case.
725
/// Conditions are simple boolean expressions, where n is the number argument.
726
/// Here are the rules.
727
/// condition := expression | empty
728
/// empty := -> always true
729
/// expression := numeric [',' expression] -> logical or
730
/// numeric := range -> true if n in range
731
/// | '%' number '=' range -> true if n % number in range
732
/// range := number
733
/// | '[' number ',' number ']' -> ranges are inclusive both ends
734
///
735
/// Here are some examples from the GNU gettext manual written in this form:
736
/// English:
737
/// {1:form0|:form1}
738
/// Latvian:
739
/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
740
/// Gaeilge:
741
/// {1:form0|2:form1|:form2}
742
/// Romanian:
743
/// {1:form0|0,%100=[1,19]:form1|:form2}
744
/// Lithuanian:
745
/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
746
/// Russian (requires repeated form):
747
/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
748
/// Slovak
749
/// {1:form0|[2,4]:form1|:form2}
750
/// Polish (requires repeated form):
751
/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
752
static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
753
const char *Argument, unsigned ArgumentLen,
754
SmallVectorImpl<char> &OutStr) {
755
const char *ArgumentEnd = Argument + ArgumentLen;
756
while (true) {
757
assert(Argument < ArgumentEnd && "Plural expression didn't match.");
758
const char *ExprEnd = Argument;
759
while (*ExprEnd != ':') {
760
assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
761
++ExprEnd;
762
}
763
if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
764
Argument = ExprEnd + 1;
765
ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
766
767
// Recursively format the result of the plural clause into the
768
// output string.
769
DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
770
return;
771
}
772
Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
773
}
774
}
775
776
/// Returns the friendly description for a token kind that will appear
777
/// without quotes in diagnostic messages. These strings may be translatable in
778
/// future.
779
static const char *getTokenDescForDiagnostic(tok::TokenKind Kind) {
780
switch (Kind) {
781
case tok::identifier:
782
return "identifier";
783
default:
784
return nullptr;
785
}
786
}
787
788
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
789
/// formal arguments into the %0 slots. The result is appended onto the Str
790
/// array.
791
void Diagnostic::
792
FormatDiagnostic(SmallVectorImpl<char> &OutStr) const {
793
if (StoredDiagMessage.has_value()) {
794
OutStr.append(StoredDiagMessage->begin(), StoredDiagMessage->end());
795
return;
796
}
797
798
StringRef Diag =
799
getDiags()->getDiagnosticIDs()->getDescription(getID());
800
801
FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
802
}
803
804
/// EscapeStringForDiagnostic - Append Str to the diagnostic buffer,
805
/// escaping non-printable characters and ill-formed code unit sequences.
806
void clang::EscapeStringForDiagnostic(StringRef Str,
807
SmallVectorImpl<char> &OutStr) {
808
OutStr.reserve(OutStr.size() + Str.size());
809
auto *Begin = reinterpret_cast<const unsigned char *>(Str.data());
810
llvm::raw_svector_ostream OutStream(OutStr);
811
const unsigned char *End = Begin + Str.size();
812
while (Begin != End) {
813
// ASCII case
814
if (isPrintable(*Begin) || isWhitespace(*Begin)) {
815
OutStream << *Begin;
816
++Begin;
817
continue;
818
}
819
if (llvm::isLegalUTF8Sequence(Begin, End)) {
820
llvm::UTF32 CodepointValue;
821
llvm::UTF32 *CpPtr = &CodepointValue;
822
const unsigned char *CodepointBegin = Begin;
823
const unsigned char *CodepointEnd =
824
Begin + llvm::getNumBytesForUTF8(*Begin);
825
llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(
826
&Begin, CodepointEnd, &CpPtr, CpPtr + 1, llvm::strictConversion);
827
(void)Res;
828
assert(
829
llvm::conversionOK == Res &&
830
"the sequence is legal UTF-8 but we couldn't convert it to UTF-32");
831
assert(Begin == CodepointEnd &&
832
"we must be further along in the string now");
833
if (llvm::sys::unicode::isPrintable(CodepointValue) ||
834
llvm::sys::unicode::isFormatting(CodepointValue)) {
835
OutStr.append(CodepointBegin, CodepointEnd);
836
continue;
837
}
838
// Unprintable code point.
839
OutStream << "<U+" << llvm::format_hex_no_prefix(CodepointValue, 4, true)
840
<< ">";
841
continue;
842
}
843
// Invalid code unit.
844
OutStream << "<" << llvm::format_hex_no_prefix(*Begin, 2, true) << ">";
845
++Begin;
846
}
847
}
848
849
void Diagnostic::
850
FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
851
SmallVectorImpl<char> &OutStr) const {
852
// When the diagnostic string is only "%0", the entire string is being given
853
// by an outside source. Remove unprintable characters from this string
854
// and skip all the other string processing.
855
if (DiagEnd - DiagStr == 2 && StringRef(DiagStr, DiagEnd - DiagStr) == "%0" &&
856
getArgKind(0) == DiagnosticsEngine::ak_std_string) {
857
const std::string &S = getArgStdStr(0);
858
EscapeStringForDiagnostic(S, OutStr);
859
return;
860
}
861
862
/// FormattedArgs - Keep track of all of the arguments formatted by
863
/// ConvertArgToString and pass them into subsequent calls to
864
/// ConvertArgToString, allowing the implementation to avoid redundancies in
865
/// obvious cases.
866
SmallVector<DiagnosticsEngine::ArgumentValue, 8> FormattedArgs;
867
868
/// QualTypeVals - Pass a vector of arrays so that QualType names can be
869
/// compared to see if more information is needed to be printed.
870
SmallVector<intptr_t, 2> QualTypeVals;
871
SmallString<64> Tree;
872
873
for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
874
if (getArgKind(i) == DiagnosticsEngine::ak_qualtype)
875
QualTypeVals.push_back(getRawArg(i));
876
877
while (DiagStr != DiagEnd) {
878
if (DiagStr[0] != '%') {
879
// Append non-%0 substrings to Str if we have one.
880
const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
881
OutStr.append(DiagStr, StrEnd);
882
DiagStr = StrEnd;
883
continue;
884
} else if (isPunctuation(DiagStr[1])) {
885
OutStr.push_back(DiagStr[1]); // %% -> %.
886
DiagStr += 2;
887
continue;
888
}
889
890
// Skip the %.
891
++DiagStr;
892
893
// This must be a placeholder for a diagnostic argument. The format for a
894
// placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
895
// The digit is a number from 0-9 indicating which argument this comes from.
896
// The modifier is a string of digits from the set [-a-z]+, arguments is a
897
// brace enclosed string.
898
const char *Modifier = nullptr, *Argument = nullptr;
899
unsigned ModifierLen = 0, ArgumentLen = 0;
900
901
// Check to see if we have a modifier. If so eat it.
902
if (!isDigit(DiagStr[0])) {
903
Modifier = DiagStr;
904
while (DiagStr[0] == '-' ||
905
(DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
906
++DiagStr;
907
ModifierLen = DiagStr-Modifier;
908
909
// If we have an argument, get it next.
910
if (DiagStr[0] == '{') {
911
++DiagStr; // Skip {.
912
Argument = DiagStr;
913
914
DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
915
assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
916
ArgumentLen = DiagStr-Argument;
917
++DiagStr; // Skip }.
918
}
919
}
920
921
assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
922
unsigned ArgNo = *DiagStr++ - '0';
923
924
// Only used for type diffing.
925
unsigned ArgNo2 = ArgNo;
926
927
DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo);
928
if (ModifierIs(Modifier, ModifierLen, "diff")) {
929
assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
930
"Invalid format for diff modifier");
931
++DiagStr; // Comma.
932
ArgNo2 = *DiagStr++ - '0';
933
DiagnosticsEngine::ArgumentKind Kind2 = getArgKind(ArgNo2);
934
if (Kind == DiagnosticsEngine::ak_qualtype &&
935
Kind2 == DiagnosticsEngine::ak_qualtype)
936
Kind = DiagnosticsEngine::ak_qualtype_pair;
937
else {
938
// %diff only supports QualTypes. For other kinds of arguments,
939
// use the default printing. For example, if the modifier is:
940
// "%diff{compare $ to $|other text}1,2"
941
// treat it as:
942
// "compare %1 to %2"
943
const char *ArgumentEnd = Argument + ArgumentLen;
944
const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
945
assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd &&
946
"Found too many '|'s in a %diff modifier!");
947
const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
948
const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
949
const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) };
950
const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) };
951
FormatDiagnostic(Argument, FirstDollar, OutStr);
952
FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
953
FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
954
FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
955
FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
956
continue;
957
}
958
}
959
960
switch (Kind) {
961
// ---- STRINGS ----
962
case DiagnosticsEngine::ak_std_string: {
963
const std::string &S = getArgStdStr(ArgNo);
964
assert(ModifierLen == 0 && "No modifiers for strings yet");
965
EscapeStringForDiagnostic(S, OutStr);
966
break;
967
}
968
case DiagnosticsEngine::ak_c_string: {
969
const char *S = getArgCStr(ArgNo);
970
assert(ModifierLen == 0 && "No modifiers for strings yet");
971
972
// Don't crash if get passed a null pointer by accident.
973
if (!S)
974
S = "(null)";
975
EscapeStringForDiagnostic(S, OutStr);
976
break;
977
}
978
// ---- INTEGERS ----
979
case DiagnosticsEngine::ak_sint: {
980
int64_t Val = getArgSInt(ArgNo);
981
982
if (ModifierIs(Modifier, ModifierLen, "select")) {
983
HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
984
OutStr);
985
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
986
HandleIntegerSModifier(Val, OutStr);
987
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
988
HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
989
OutStr);
990
} else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
991
HandleOrdinalModifier((unsigned)Val, OutStr);
992
} else {
993
assert(ModifierLen == 0 && "Unknown integer modifier");
994
llvm::raw_svector_ostream(OutStr) << Val;
995
}
996
break;
997
}
998
case DiagnosticsEngine::ak_uint: {
999
uint64_t Val = getArgUInt(ArgNo);
1000
1001
if (ModifierIs(Modifier, ModifierLen, "select")) {
1002
HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
1003
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
1004
HandleIntegerSModifier(Val, OutStr);
1005
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1006
HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1007
OutStr);
1008
} else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1009
HandleOrdinalModifier(Val, OutStr);
1010
} else {
1011
assert(ModifierLen == 0 && "Unknown integer modifier");
1012
llvm::raw_svector_ostream(OutStr) << Val;
1013
}
1014
break;
1015
}
1016
// ---- TOKEN SPELLINGS ----
1017
case DiagnosticsEngine::ak_tokenkind: {
1018
tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo));
1019
assert(ModifierLen == 0 && "No modifiers for token kinds yet");
1020
1021
llvm::raw_svector_ostream Out(OutStr);
1022
if (const char *S = tok::getPunctuatorSpelling(Kind))
1023
// Quoted token spelling for punctuators.
1024
Out << '\'' << S << '\'';
1025
else if ((S = tok::getKeywordSpelling(Kind)))
1026
// Unquoted token spelling for keywords.
1027
Out << S;
1028
else if ((S = getTokenDescForDiagnostic(Kind)))
1029
// Unquoted translatable token name.
1030
Out << S;
1031
else if ((S = tok::getTokenName(Kind)))
1032
// Debug name, shouldn't appear in user-facing diagnostics.
1033
Out << '<' << S << '>';
1034
else
1035
Out << "(null)";
1036
break;
1037
}
1038
// ---- NAMES and TYPES ----
1039
case DiagnosticsEngine::ak_identifierinfo: {
1040
const IdentifierInfo *II = getArgIdentifier(ArgNo);
1041
assert(ModifierLen == 0 && "No modifiers for strings yet");
1042
1043
// Don't crash if get passed a null pointer by accident.
1044
if (!II) {
1045
const char *S = "(null)";
1046
OutStr.append(S, S + strlen(S));
1047
continue;
1048
}
1049
1050
llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
1051
break;
1052
}
1053
case DiagnosticsEngine::ak_addrspace:
1054
case DiagnosticsEngine::ak_qual:
1055
case DiagnosticsEngine::ak_qualtype:
1056
case DiagnosticsEngine::ak_declarationname:
1057
case DiagnosticsEngine::ak_nameddecl:
1058
case DiagnosticsEngine::ak_nestednamespec:
1059
case DiagnosticsEngine::ak_declcontext:
1060
case DiagnosticsEngine::ak_attr:
1061
getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
1062
StringRef(Modifier, ModifierLen),
1063
StringRef(Argument, ArgumentLen),
1064
FormattedArgs,
1065
OutStr, QualTypeVals);
1066
break;
1067
case DiagnosticsEngine::ak_qualtype_pair: {
1068
// Create a struct with all the info needed for printing.
1069
TemplateDiffTypes TDT;
1070
TDT.FromType = getRawArg(ArgNo);
1071
TDT.ToType = getRawArg(ArgNo2);
1072
TDT.ElideType = getDiags()->ElideType;
1073
TDT.ShowColors = getDiags()->ShowColors;
1074
TDT.TemplateDiffUsed = false;
1075
intptr_t val = reinterpret_cast<intptr_t>(&TDT);
1076
1077
const char *ArgumentEnd = Argument + ArgumentLen;
1078
const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1079
1080
// Print the tree. If this diagnostic already has a tree, skip the
1081
// second tree.
1082
if (getDiags()->PrintTemplateTree && Tree.empty()) {
1083
TDT.PrintFromType = true;
1084
TDT.PrintTree = true;
1085
getDiags()->ConvertArgToString(Kind, val,
1086
StringRef(Modifier, ModifierLen),
1087
StringRef(Argument, ArgumentLen),
1088
FormattedArgs,
1089
Tree, QualTypeVals);
1090
// If there is no tree information, fall back to regular printing.
1091
if (!Tree.empty()) {
1092
FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr);
1093
break;
1094
}
1095
}
1096
1097
// Non-tree printing, also the fall-back when tree printing fails.
1098
// The fall-back is triggered when the types compared are not templates.
1099
const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');
1100
const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');
1101
1102
// Append before text
1103
FormatDiagnostic(Argument, FirstDollar, OutStr);
1104
1105
// Append first type
1106
TDT.PrintTree = false;
1107
TDT.PrintFromType = true;
1108
getDiags()->ConvertArgToString(Kind, val,
1109
StringRef(Modifier, ModifierLen),
1110
StringRef(Argument, ArgumentLen),
1111
FormattedArgs,
1112
OutStr, QualTypeVals);
1113
if (!TDT.TemplateDiffUsed)
1114
FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
1115
TDT.FromType));
1116
1117
// Append middle text
1118
FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1119
1120
// Append second type
1121
TDT.PrintFromType = false;
1122
getDiags()->ConvertArgToString(Kind, val,
1123
StringRef(Modifier, ModifierLen),
1124
StringRef(Argument, ArgumentLen),
1125
FormattedArgs,
1126
OutStr, QualTypeVals);
1127
if (!TDT.TemplateDiffUsed)
1128
FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
1129
TDT.ToType));
1130
1131
// Append end text
1132
FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1133
break;
1134
}
1135
}
1136
1137
// Remember this argument info for subsequent formatting operations. Turn
1138
// std::strings into a null terminated string to make it be the same case as
1139
// all the other ones.
1140
if (Kind == DiagnosticsEngine::ak_qualtype_pair)
1141
continue;
1142
else if (Kind != DiagnosticsEngine::ak_std_string)
1143
FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
1144
else
1145
FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string,
1146
(intptr_t)getArgStdStr(ArgNo).c_str()));
1147
}
1148
1149
// Append the type tree to the end of the diagnostics.
1150
OutStr.append(Tree.begin(), Tree.end());
1151
}
1152
1153
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
1154
StringRef Message)
1155
: ID(ID), Level(Level), Message(Message) {}
1156
1157
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level,
1158
const Diagnostic &Info)
1159
: ID(Info.getID()), Level(Level) {
1160
assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
1161
"Valid source location without setting a source manager for diagnostic");
1162
if (Info.getLocation().isValid())
1163
Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
1164
SmallString<64> Message;
1165
Info.FormatDiagnostic(Message);
1166
this->Message.assign(Message.begin(), Message.end());
1167
this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end());
1168
this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end());
1169
}
1170
1171
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
1172
StringRef Message, FullSourceLoc Loc,
1173
ArrayRef<CharSourceRange> Ranges,
1174
ArrayRef<FixItHint> FixIts)
1175
: ID(ID), Level(Level), Loc(Loc), Message(Message),
1176
Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())
1177
{
1178
}
1179
1180
llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
1181
const StoredDiagnostic &SD) {
1182
if (SD.getLocation().hasManager())
1183
OS << SD.getLocation().printToString(SD.getLocation().getManager()) << ": ";
1184
OS << SD.getMessage();
1185
return OS;
1186
}
1187
1188
/// IncludeInDiagnosticCounts - This method (whose default implementation
1189
/// returns true) indicates whether the diagnostics handled by this
1190
/// DiagnosticConsumer should be included in the number of diagnostics
1191
/// reported by DiagnosticsEngine.
1192
bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; }
1193
1194
void IgnoringDiagConsumer::anchor() {}
1195
1196
ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() = default;
1197
1198
void ForwardingDiagnosticConsumer::HandleDiagnostic(
1199
DiagnosticsEngine::Level DiagLevel,
1200
const Diagnostic &Info) {
1201
Target.HandleDiagnostic(DiagLevel, Info);
1202
}
1203
1204
void ForwardingDiagnosticConsumer::clear() {
1205
DiagnosticConsumer::clear();
1206
Target.clear();
1207
}
1208
1209
bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const {
1210
return Target.IncludeInDiagnosticCounts();
1211
}
1212
1213
PartialDiagnostic::DiagStorageAllocator::DiagStorageAllocator() {
1214
for (unsigned I = 0; I != NumCached; ++I)
1215
FreeList[I] = Cached + I;
1216
NumFreeListEntries = NumCached;
1217
}
1218
1219
PartialDiagnostic::DiagStorageAllocator::~DiagStorageAllocator() {
1220
// Don't assert if we are in a CrashRecovery context, as this invariant may
1221
// be invalidated during a crash.
1222
assert((NumFreeListEntries == NumCached ||
1223
llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1224
"A partial is on the lam");
1225
}
1226
1227
char DiagnosticError::ID;
1228
1229