1 //===- Diagnostic.cpp - C Language Family Diagnostic Handling -------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the Diagnostic-related interfaces.
11 //===----------------------------------------------------------------------===//
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"
42 using namespace clang
;
44 const StreamingDiagnostic
&clang::operator<<(const StreamingDiagnostic
&DB
,
45 DiagNullabilityKind nullability
) {
48 getNullabilitySpelling(nullability
.first
,
49 /*isContextSensitive=*/nullability
.second
) +
55 const StreamingDiagnostic
&clang::operator<<(const StreamingDiagnostic
&DB
,
57 DB
.AddString(toString(std::move(E
)));
61 static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK
, intptr_t QT
,
62 StringRef Modifier
, StringRef Argument
,
63 ArrayRef
<DiagnosticsEngine::ArgumentValue
> PrevArgs
,
64 SmallVectorImpl
<char> &Output
,
66 ArrayRef
<intptr_t> QualTypeVals
) {
67 StringRef Str
= "<can't format argument>";
68 Output
.append(Str
.begin(), Str
.end());
71 DiagnosticsEngine::DiagnosticsEngine(
72 IntrusiveRefCntPtr
<DiagnosticIDs
> diags
,
73 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
, DiagnosticConsumer
*client
,
75 : Diags(std::move(diags
)), DiagOpts(std::move(DiagOpts
)) {
76 setClient(client
, ShouldOwnClient
);
77 ArgToStringFn
= DummyArgToStringFn
;
82 DiagnosticsEngine::~DiagnosticsEngine() {
83 // If we own the diagnostic client, destroy it first so that it can access the
84 // engine from its destructor.
88 void DiagnosticsEngine::dump() const {
89 DiagStatesByLoc
.dump(*SourceMgr
);
92 void DiagnosticsEngine::dump(StringRef DiagName
) const {
93 DiagStatesByLoc
.dump(*SourceMgr
, DiagName
);
96 void DiagnosticsEngine::setClient(DiagnosticConsumer
*client
,
97 bool ShouldOwnClient
) {
98 Owner
.reset(ShouldOwnClient
? client
: nullptr);
102 void DiagnosticsEngine::pushMappings(SourceLocation Loc
) {
103 DiagStateOnPushStack
.push_back(GetCurDiagState());
106 bool DiagnosticsEngine::popMappings(SourceLocation Loc
) {
107 if (DiagStateOnPushStack
.empty())
110 if (DiagStateOnPushStack
.back() != GetCurDiagState()) {
111 // State changed at some point between push/pop.
112 PushDiagStatePoint(DiagStateOnPushStack
.back(), Loc
);
114 DiagStateOnPushStack
.pop_back();
118 void DiagnosticsEngine::Reset(bool soft
/*=false*/) {
119 ErrorOccurred
= false;
120 UncompilableErrorOccurred
= false;
121 FatalErrorOccurred
= false;
122 UnrecoverableErrorOccurred
= false;
126 TrapNumErrorsOccurred
= 0;
127 TrapNumUnrecoverableErrorsOccurred
= 0;
129 CurDiagID
= std::numeric_limits
<unsigned>::max();
130 LastDiagLevel
= DiagnosticIDs::Ignored
;
134 // Clear state related to #pragma diagnostic.
136 DiagStatesByLoc
.clear();
137 DiagStateOnPushStack
.clear();
139 // Create a DiagState and DiagStatePoint representing diagnostic changes
140 // through command-line.
141 DiagStates
.emplace_back();
142 DiagStatesByLoc
.appendFirst(&DiagStates
.back());
146 void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID
, StringRef Arg1
,
147 StringRef Arg2
, StringRef Arg3
) {
151 DelayedDiagID
= DiagID
;
152 DelayedDiagArg1
= Arg1
.str();
153 DelayedDiagArg2
= Arg2
.str();
154 DelayedDiagArg3
= Arg3
.str();
157 void DiagnosticsEngine::ReportDelayed() {
158 unsigned ID
= DelayedDiagID
;
160 Report(ID
) << DelayedDiagArg1
<< DelayedDiagArg2
<< DelayedDiagArg3
;
164 DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag
) {
165 std::pair
<iterator
, bool> Result
=
166 DiagMap
.insert(std::make_pair(Diag
, DiagnosticMapping()));
168 // Initialize the entry if we added it.
170 Result
.first
->second
= DiagnosticIDs::getDefaultMapping(Diag
);
172 return Result
.first
->second
;
175 void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState
*State
) {
176 assert(Files
.empty() && "not first");
177 FirstDiagState
= CurDiagState
= State
;
178 CurDiagStateLoc
= SourceLocation();
181 void DiagnosticsEngine::DiagStateMap::append(SourceManager
&SrcMgr
,
184 CurDiagState
= State
;
185 CurDiagStateLoc
= Loc
;
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");
195 if (Last
.Offset
== Offset
) {
196 if (Last
.State
== State
)
202 F
->StateTransitions
.push_back({State
, Offset
});
206 DiagnosticsEngine::DiagState
*
207 DiagnosticsEngine::DiagStateMap::lookup(SourceManager
&SrcMgr
,
208 SourceLocation Loc
) const {
209 // Common case: we have not seen any diagnostic pragmas.
211 return FirstDiagState
;
213 std::pair
<FileID
, unsigned> Decomp
= SrcMgr
.getDecomposedLoc(Loc
);
214 const File
*F
= getFile(SrcMgr
, Decomp
.first
);
215 return F
->lookup(Decomp
.second
);
218 DiagnosticsEngine::DiagState
*
219 DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset
) const {
221 llvm::partition_point(StateTransitions
, [=](const DiagStatePoint
&P
) {
222 return P
.Offset
<= Offset
;
224 assert(OnePastIt
!= StateTransitions
.begin() && "missing initial state");
225 return OnePastIt
[-1].State
;
228 DiagnosticsEngine::DiagStateMap::File
*
229 DiagnosticsEngine::DiagStateMap::getFile(SourceManager
&SrcMgr
,
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
;
237 // We created a new File; look up the diagnostic state at the start of it and
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});
245 // This is the (imaginary) root file into which we pretend all top-level
246 // files are included; it descends from the initial state.
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});
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";
263 for (auto &F
: Files
) {
265 File
&File
= F
.second
;
267 bool PrintedOuterHeading
= false;
268 auto PrintOuterHeading
= [&] {
269 if (PrintedOuterHeading
) return;
270 PrintedOuterHeading
= true;
272 llvm::errs() << "File " << &File
<< " <FileID " << ID
.getHashValue()
273 << ">: " << SrcMgr
.getBufferOrFake(ID
).getBufferIdentifier();
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
);
285 if (File
.HasLocalTransitions
)
286 llvm::errs() << " has_local_transitions";
287 llvm::errs() << "\n";
290 if (DiagName
.empty())
293 for (DiagStatePoint
&Transition
: File
.StateTransitions
) {
294 bool PrintedInnerHeading
= false;
295 auto PrintInnerHeading
= [&] {
296 if (PrintedInnerHeading
) return;
297 PrintedInnerHeading
= true;
301 SrcMgr
.getLocForStartOfFile(ID
)
302 .getLocWithOffset(Transition
.Offset
)
303 .print(llvm::errs(), SrcMgr
);
304 llvm::errs() << ": state " << Transition
.State
<< ":\n";
307 if (DiagName
.empty())
310 for (auto &Mapping
: *Transition
.State
) {
312 DiagnosticIDs::getWarningOptionForDiag(Mapping
.first
);
313 if (!DiagName
.empty() && DiagName
!= Option
)
319 llvm::errs() << "<unknown " << Mapping
.first
<< ">";
321 llvm::errs() << Option
;
322 llvm::errs() << ": ";
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;
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";
348 void DiagnosticsEngine::PushDiagStatePoint(DiagState
*State
,
349 SourceLocation Loc
) {
350 assert(Loc
.isValid() && "Adding invalid loc point");
351 DiagStatesByLoc
.append(*SourceMgr
, Loc
, State
);
354 void DiagnosticsEngine::setSeverity(diag::kind Diag
, diag::Severity Map
,
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");
363 // Don't allow a mapping to a warning override an error/fatal mapping.
364 bool WasUpgradedFromWarning
= false;
365 if (Map
== diag::Severity::Warning
) {
366 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
367 if (Info
.getSeverity() == diag::Severity::Error
||
368 Info
.getSeverity() == diag::Severity::Fatal
) {
369 Map
= Info
.getSeverity();
370 WasUpgradedFromWarning
= true;
373 DiagnosticMapping Mapping
= makeUserMapping(Map
, L
);
374 Mapping
.setUpgradedFromWarning(WasUpgradedFromWarning
);
376 // Make sure we propagate the NoWarningAsError flag from an existing
377 // mapping (which may be the default mapping).
378 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
379 Mapping
.setNoWarningAsError(Info
.hasNoWarningAsError() ||
380 Mapping
.hasNoWarningAsError());
382 // Common case; setting all the diagnostics of a group in one place.
383 if ((L
.isInvalid() || L
== DiagStatesByLoc
.getCurDiagStateLoc()) &&
384 DiagStatesByLoc
.getCurDiagState()) {
385 // FIXME: This is theoretically wrong: if the current state is shared with
386 // some other location (via push/pop) we will change the state for that
387 // other location as well. This cannot currently happen, as we can't update
388 // the diagnostic state at the same location at which we pop.
389 DiagStatesByLoc
.getCurDiagState()->setMapping(Diag
, Mapping
);
393 // A diagnostic pragma occurred, create a new DiagState initialized with
394 // the current one and a new DiagStatePoint to record at which location
395 // the new state became active.
396 DiagStates
.push_back(*GetCurDiagState());
397 DiagStates
.back().setMapping(Diag
, Mapping
);
398 PushDiagStatePoint(&DiagStates
.back(), L
);
401 bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor
,
402 StringRef Group
, diag::Severity Map
,
403 SourceLocation Loc
) {
404 // Get the diagnostics in this group.
405 SmallVector
<diag::kind
, 256> GroupDiags
;
406 if (Diags
->getDiagnosticsInGroup(Flavor
, Group
, GroupDiags
))
410 for (diag::kind Diag
: GroupDiags
)
411 setSeverity(Diag
, Map
, Loc
);
416 bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor
,
419 SourceLocation Loc
) {
420 return setSeverityForGroup(Flavor
, Diags
->getWarningOptionForGroup(Group
),
424 bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group
,
426 // If we are enabling this feature, just set the diagnostic mappings to map to
429 return setSeverityForGroup(diag::Flavor::WarningOrError
, Group
,
430 diag::Severity::Error
);
432 // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
433 // potentially downgrade anything already mapped to be a warning.
435 // Get the diagnostics in this group.
436 SmallVector
<diag::kind
, 8> GroupDiags
;
437 if (Diags
->getDiagnosticsInGroup(diag::Flavor::WarningOrError
, Group
,
441 // Perform the mapping change.
442 for (diag::kind Diag
: GroupDiags
) {
443 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
445 if (Info
.getSeverity() == diag::Severity::Error
||
446 Info
.getSeverity() == diag::Severity::Fatal
)
447 Info
.setSeverity(diag::Severity::Warning
);
449 Info
.setNoWarningAsError(true);
455 bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group
,
457 // If we are enabling this feature, just set the diagnostic mappings to map to
460 return setSeverityForGroup(diag::Flavor::WarningOrError
, Group
,
461 diag::Severity::Fatal
);
463 // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
464 // and potentially downgrade anything already mapped to be a fatal error.
466 // Get the diagnostics in this group.
467 SmallVector
<diag::kind
, 8> GroupDiags
;
468 if (Diags
->getDiagnosticsInGroup(diag::Flavor::WarningOrError
, Group
,
472 // Perform the mapping change.
473 for (diag::kind Diag
: GroupDiags
) {
474 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
476 if (Info
.getSeverity() == diag::Severity::Fatal
)
477 Info
.setSeverity(diag::Severity::Error
);
479 Info
.setNoErrorAsFatal(true);
485 void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor
,
487 SourceLocation Loc
) {
488 // Get all the diagnostics.
489 std::vector
<diag::kind
> AllDiags
;
490 DiagnosticIDs::getAllDiagnostics(Flavor
, AllDiags
);
493 for (diag::kind Diag
: AllDiags
)
494 if (Diags
->isBuiltinWarningOrExtension(Diag
))
495 setSeverity(Diag
, Map
, Loc
);
498 void DiagnosticsEngine::Report(const StoredDiagnostic
&storedDiag
) {
499 assert(CurDiagID
== std::numeric_limits
<unsigned>::max() &&
500 "Multiple diagnostics in flight at once!");
502 CurDiagLoc
= storedDiag
.getLocation();
503 CurDiagID
= storedDiag
.getID();
504 DiagStorage
.NumDiagArgs
= 0;
506 DiagStorage
.DiagRanges
.clear();
507 DiagStorage
.DiagRanges
.append(storedDiag
.range_begin(),
508 storedDiag
.range_end());
510 DiagStorage
.FixItHints
.clear();
511 DiagStorage
.FixItHints
.append(storedDiag
.fixit_begin(),
512 storedDiag
.fixit_end());
514 assert(Client
&& "DiagnosticConsumer not set!");
515 Level DiagLevel
= storedDiag
.getLevel();
516 Diagnostic
Info(this, storedDiag
.getMessage());
517 Client
->HandleDiagnostic(DiagLevel
, Info
);
518 if (Client
->IncludeInDiagnosticCounts()) {
519 if (DiagLevel
== DiagnosticsEngine::Warning
)
523 CurDiagID
= std::numeric_limits
<unsigned>::max();
526 bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force
) {
527 assert(getClient() && "DiagnosticClient not set!");
531 Diagnostic
Info(this);
533 // Figure out the diagnostic level of this message.
534 DiagnosticIDs::Level DiagLevel
535 = Diags
->getDiagnosticLevel(Info
.getID(), Info
.getLocation(), *this);
537 Emitted
= (DiagLevel
!= DiagnosticIDs::Ignored
);
539 // Emit the diagnostic regardless of suppression level.
540 Diags
->EmitDiag(*this, DiagLevel
);
543 // Process the diagnostic, sending the accumulated information to the
544 // DiagnosticConsumer.
545 Emitted
= ProcessDiag();
548 // Clear out the current diagnostic object.
551 // If there was a delayed diagnostic, emit it now.
552 if (!Force
&& DelayedDiagID
)
558 DiagnosticConsumer::~DiagnosticConsumer() = default;
560 void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel
,
561 const Diagnostic
&Info
) {
562 if (!IncludeInDiagnosticCounts())
565 if (DiagLevel
== DiagnosticsEngine::Warning
)
567 else if (DiagLevel
>= DiagnosticsEngine::Error
)
571 /// ModifierIs - Return true if the specified modifier matches specified string.
572 template <std::size_t StrLen
>
573 static bool ModifierIs(const char *Modifier
, unsigned ModifierLen
,
574 const char (&Str
)[StrLen
]) {
575 return StrLen
-1 == ModifierLen
&& memcmp(Modifier
, Str
, StrLen
-1) == 0;
578 /// ScanForward - Scans forward, looking for the given character, skipping
579 /// nested clauses and escaped characters.
580 static const char *ScanFormat(const char *I
, const char *E
, char Target
) {
583 for ( ; I
!= E
; ++I
) {
584 if (Depth
== 0 && *I
== Target
) return I
;
585 if (Depth
!= 0 && *I
== '}') Depth
--;
591 // Escaped characters get implicitly skipped here.
594 if (!isDigit(*I
) && !isPunctuation(*I
)) {
595 for (I
++; I
!= E
&& !isDigit(*I
) && *I
!= '{'; I
++) ;
605 /// HandleSelectModifier - Handle the integer 'select' modifier. This is used
606 /// like this: %select{foo|bar|baz}2. This means that the integer argument
607 /// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
608 /// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
609 /// This is very useful for certain classes of variant diagnostics.
610 static void HandleSelectModifier(const Diagnostic
&DInfo
, unsigned ValNo
,
611 const char *Argument
, unsigned ArgumentLen
,
612 SmallVectorImpl
<char> &OutStr
) {
613 const char *ArgumentEnd
= Argument
+ArgumentLen
;
615 // Skip over 'ValNo' |'s.
617 const char *NextVal
= ScanFormat(Argument
, ArgumentEnd
, '|');
618 assert(NextVal
!= ArgumentEnd
&& "Value for integer select modifier was"
619 " larger than the number of options in the diagnostic string!");
620 Argument
= NextVal
+1; // Skip this string.
624 // Get the end of the value. This is either the } or the |.
625 const char *EndPtr
= ScanFormat(Argument
, ArgumentEnd
, '|');
627 // Recursively format the result of the select clause into the output string.
628 DInfo
.FormatDiagnostic(Argument
, EndPtr
, OutStr
);
631 /// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
632 /// letter 's' to the string if the value is not 1. This is used in cases like
633 /// this: "you idiot, you have %4 parameter%s4!".
634 static void HandleIntegerSModifier(unsigned ValNo
,
635 SmallVectorImpl
<char> &OutStr
) {
637 OutStr
.push_back('s');
640 /// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
641 /// prints the ordinal form of the given integer, with 1 corresponding
642 /// to the first ordinal. Currently this is hard-coded to use the
644 static void HandleOrdinalModifier(unsigned ValNo
,
645 SmallVectorImpl
<char> &OutStr
) {
646 assert(ValNo
!= 0 && "ValNo must be strictly positive!");
648 llvm::raw_svector_ostream
Out(OutStr
);
650 // We could use text forms for the first N ordinals, but the numeric
651 // forms are actually nicer in diagnostics because they stand out.
652 Out
<< ValNo
<< llvm::getOrdinalSuffix(ValNo
);
655 /// PluralNumber - Parse an unsigned integer and advance Start.
656 static unsigned PluralNumber(const char *&Start
, const char *End
) {
657 // Programming 101: Parse a decimal number :-)
659 while (Start
!= End
&& *Start
>= '0' && *Start
<= '9') {
667 /// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
668 static bool TestPluralRange(unsigned Val
, const char *&Start
, const char *End
) {
670 unsigned Ref
= PluralNumber(Start
, End
);
675 unsigned Low
= PluralNumber(Start
, End
);
676 assert(*Start
== ',' && "Bad plural expression syntax: expected ,");
678 unsigned High
= PluralNumber(Start
, End
);
679 assert(*Start
== ']' && "Bad plural expression syntax: expected )");
681 return Low
<= Val
&& Val
<= High
;
684 /// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
685 static bool EvalPluralExpr(unsigned ValNo
, const char *Start
, const char *End
) {
695 unsigned Arg
= PluralNumber(Start
, End
);
696 assert(*Start
== '=' && "Bad plural expression syntax: expected =");
698 unsigned ValMod
= ValNo
% Arg
;
699 if (TestPluralRange(ValMod
, Start
, End
))
702 assert((C
== '[' || (C
>= '0' && C
<= '9')) &&
703 "Bad plural expression syntax: unexpected character");
705 if (TestPluralRange(ValNo
, Start
, End
))
709 // Scan for next or-expr part.
710 Start
= std::find(Start
, End
, ',');
718 /// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
719 /// for complex plural forms, or in languages where all plurals are complex.
720 /// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
721 /// conditions that are tested in order, the form corresponding to the first
722 /// that applies being emitted. The empty condition is always true, making the
723 /// last form a default case.
724 /// Conditions are simple boolean expressions, where n is the number argument.
725 /// Here are the rules.
726 /// condition := expression | empty
727 /// empty := -> always true
728 /// expression := numeric [',' expression] -> logical or
729 /// numeric := range -> true if n in range
730 /// | '%' number '=' range -> true if n % number in range
732 /// | '[' number ',' number ']' -> ranges are inclusive both ends
734 /// Here are some examples from the GNU gettext manual written in this form:
738 /// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
740 /// {1:form0|2:form1|:form2}
742 /// {1:form0|0,%100=[1,19]:form1|:form2}
744 /// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
745 /// Russian (requires repeated form):
746 /// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
748 /// {1:form0|[2,4]:form1|:form2}
749 /// Polish (requires repeated form):
750 /// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
751 static void HandlePluralModifier(const Diagnostic
&DInfo
, unsigned ValNo
,
752 const char *Argument
, unsigned ArgumentLen
,
753 SmallVectorImpl
<char> &OutStr
) {
754 const char *ArgumentEnd
= Argument
+ ArgumentLen
;
756 assert(Argument
< ArgumentEnd
&& "Plural expression didn't match.");
757 const char *ExprEnd
= Argument
;
758 while (*ExprEnd
!= ':') {
759 assert(ExprEnd
!= ArgumentEnd
&& "Plural missing expression end");
762 if (EvalPluralExpr(ValNo
, Argument
, ExprEnd
)) {
763 Argument
= ExprEnd
+ 1;
764 ExprEnd
= ScanFormat(Argument
, ArgumentEnd
, '|');
766 // Recursively format the result of the plural clause into the
768 DInfo
.FormatDiagnostic(Argument
, ExprEnd
, OutStr
);
771 Argument
= ScanFormat(Argument
, ArgumentEnd
- 1, '|') + 1;
775 /// Returns the friendly description for a token kind that will appear
776 /// without quotes in diagnostic messages. These strings may be translatable in
778 static const char *getTokenDescForDiagnostic(tok::TokenKind Kind
) {
780 case tok::identifier
:
787 /// FormatDiagnostic - Format this diagnostic into a string, substituting the
788 /// formal arguments into the %0 slots. The result is appended onto the Str
791 FormatDiagnostic(SmallVectorImpl
<char> &OutStr
) const {
792 if (StoredDiagMessage
.has_value()) {
793 OutStr
.append(StoredDiagMessage
->begin(), StoredDiagMessage
->end());
798 getDiags()->getDiagnosticIDs()->getDescription(getID());
800 FormatDiagnostic(Diag
.begin(), Diag
.end(), OutStr
);
803 /// EscapeStringForDiagnostic - Append Str to the diagnostic buffer,
804 /// escaping non-printable characters and ill-formed code unit sequences.
805 void clang::EscapeStringForDiagnostic(StringRef Str
,
806 SmallVectorImpl
<char> &OutStr
) {
807 OutStr
.reserve(OutStr
.size() + Str
.size());
808 auto *Begin
= reinterpret_cast<const unsigned char *>(Str
.data());
809 llvm::raw_svector_ostream
OutStream(OutStr
);
810 const unsigned char *End
= Begin
+ Str
.size();
811 while (Begin
!= End
) {
813 if (isPrintable(*Begin
) || isWhitespace(*Begin
)) {
818 if (llvm::isLegalUTF8Sequence(Begin
, End
)) {
819 llvm::UTF32 CodepointValue
;
820 llvm::UTF32
*CpPtr
= &CodepointValue
;
821 const unsigned char *CodepointBegin
= Begin
;
822 const unsigned char *CodepointEnd
=
823 Begin
+ llvm::getNumBytesForUTF8(*Begin
);
824 llvm::ConversionResult Res
= llvm::ConvertUTF8toUTF32(
825 &Begin
, CodepointEnd
, &CpPtr
, CpPtr
+ 1, llvm::strictConversion
);
828 llvm::conversionOK
== Res
&&
829 "the sequence is legal UTF-8 but we couldn't convert it to UTF-32");
830 assert(Begin
== CodepointEnd
&&
831 "we must be further along in the string now");
832 if (llvm::sys::unicode::isPrintable(CodepointValue
) ||
833 llvm::sys::unicode::isFormatting(CodepointValue
)) {
834 OutStr
.append(CodepointBegin
, CodepointEnd
);
837 // Unprintable code point.
838 OutStream
<< "<U+" << llvm::format_hex_no_prefix(CodepointValue
, 4, true)
842 // Invalid code unit.
843 OutStream
<< "<" << llvm::format_hex_no_prefix(*Begin
, 2, true) << ">";
849 FormatDiagnostic(const char *DiagStr
, const char *DiagEnd
,
850 SmallVectorImpl
<char> &OutStr
) const {
851 // When the diagnostic string is only "%0", the entire string is being given
852 // by an outside source. Remove unprintable characters from this string
853 // and skip all the other string processing.
854 if (DiagEnd
- DiagStr
== 2 &&
855 StringRef(DiagStr
, DiagEnd
- DiagStr
).equals("%0") &&
856 getArgKind(0) == DiagnosticsEngine::ak_std_string
) {
857 const std::string
&S
= getArgStdStr(0);
858 EscapeStringForDiagnostic(S
, OutStr
);
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
866 SmallVector
<DiagnosticsEngine::ArgumentValue
, 8> FormattedArgs
;
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
;
873 for (unsigned i
= 0, e
= getNumArgs(); i
< e
; ++i
)
874 if (getArgKind(i
) == DiagnosticsEngine::ak_qualtype
)
875 QualTypeVals
.push_back(getRawArg(i
));
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
);
884 } else if (isPunctuation(DiagStr
[1])) {
885 OutStr
.push_back(DiagStr
[1]); // %% -> %.
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;
901 // Check to see if we have a modifier. If so eat it.
902 if (!isDigit(DiagStr
[0])) {
904 while (DiagStr
[0] == '-' ||
905 (DiagStr
[0] >= 'a' && DiagStr
[0] <= 'z'))
907 ModifierLen
= DiagStr
-Modifier
;
909 // If we have an argument, get it next.
910 if (DiagStr
[0] == '{') {
911 ++DiagStr
; // Skip {.
914 DiagStr
= ScanFormat(DiagStr
, DiagEnd
, '}');
915 assert(DiagStr
!= DiagEnd
&& "Mismatched {}'s in diagnostic string!");
916 ArgumentLen
= DiagStr
-Argument
;
917 ++DiagStr
; // Skip }.
921 assert(isDigit(*DiagStr
) && "Invalid format for argument in diagnostic");
922 unsigned ArgNo
= *DiagStr
++ - '0';
924 // Only used for type diffing.
925 unsigned ArgNo2
= ArgNo
;
927 DiagnosticsEngine::ArgumentKind Kind
= getArgKind(ArgNo
);
928 if (ModifierIs(Modifier
, ModifierLen
, "diff")) {
929 assert(*DiagStr
== ',' && isDigit(*(DiagStr
+ 1)) &&
930 "Invalid format for diff modifier");
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
;
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"
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
);
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
);
968 case DiagnosticsEngine::ak_c_string
: {
969 const char *S
= getArgCStr(ArgNo
);
970 assert(ModifierLen
== 0 && "No modifiers for strings yet");
972 // Don't crash if get passed a null pointer by accident.
975 EscapeStringForDiagnostic(S
, OutStr
);
978 // ---- INTEGERS ----
979 case DiagnosticsEngine::ak_sint
: {
980 int64_t Val
= getArgSInt(ArgNo
);
982 if (ModifierIs(Modifier
, ModifierLen
, "select")) {
983 HandleSelectModifier(*this, (unsigned)Val
, Argument
, ArgumentLen
,
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
,
990 } else if (ModifierIs(Modifier
, ModifierLen
, "ordinal")) {
991 HandleOrdinalModifier((unsigned)Val
, OutStr
);
993 assert(ModifierLen
== 0 && "Unknown integer modifier");
994 llvm::raw_svector_ostream(OutStr
) << Val
;
998 case DiagnosticsEngine::ak_uint
: {
999 uint64_t Val
= getArgUInt(ArgNo
);
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
,
1008 } else if (ModifierIs(Modifier
, ModifierLen
, "ordinal")) {
1009 HandleOrdinalModifier(Val
, OutStr
);
1011 assert(ModifierLen
== 0 && "Unknown integer modifier");
1012 llvm::raw_svector_ostream(OutStr
) << Val
;
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");
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.
1028 else if ((S
= getTokenDescForDiagnostic(Kind
)))
1029 // Unquoted translatable token name.
1031 else if ((S
= tok::getTokenName(Kind
)))
1032 // Debug name, shouldn't appear in user-facing diagnostics.
1033 Out
<< '<' << S
<< '>';
1038 // ---- NAMES and TYPES ----
1039 case DiagnosticsEngine::ak_identifierinfo
: {
1040 const IdentifierInfo
*II
= getArgIdentifier(ArgNo
);
1041 assert(ModifierLen
== 0 && "No modifiers for strings yet");
1043 // Don't crash if get passed a null pointer by accident.
1045 const char *S
= "(null)";
1046 OutStr
.append(S
, S
+ strlen(S
));
1050 llvm::raw_svector_ostream(OutStr
) << '\'' << II
->getName() << '\'';
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
),
1065 OutStr
, QualTypeVals
);
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
);
1077 const char *ArgumentEnd
= Argument
+ ArgumentLen
;
1078 const char *Pipe
= ScanFormat(Argument
, ArgumentEnd
, '|');
1080 // Print the tree. If this diagnostic already has a tree, skip the
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
),
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
);
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
, '$');
1102 // Append before text
1103 FormatDiagnostic(Argument
, FirstDollar
, OutStr
);
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
),
1112 OutStr
, QualTypeVals
);
1113 if (!TDT
.TemplateDiffUsed
)
1114 FormattedArgs
.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype
,
1117 // Append middle text
1118 FormatDiagnostic(FirstDollar
+ 1, SecondDollar
, OutStr
);
1120 // Append second type
1121 TDT
.PrintFromType
= false;
1122 getDiags()->ConvertArgToString(Kind
, val
,
1123 StringRef(Modifier
, ModifierLen
),
1124 StringRef(Argument
, ArgumentLen
),
1126 OutStr
, QualTypeVals
);
1127 if (!TDT
.TemplateDiffUsed
)
1128 FormattedArgs
.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype
,
1132 FormatDiagnostic(SecondDollar
+ 1, Pipe
, OutStr
);
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
)
1142 else if (Kind
!= DiagnosticsEngine::ak_std_string
)
1143 FormattedArgs
.push_back(std::make_pair(Kind
, getRawArg(ArgNo
)));
1145 FormattedArgs
.push_back(std::make_pair(DiagnosticsEngine::ak_c_string
,
1146 (intptr_t)getArgStdStr(ArgNo
).c_str()));
1149 // Append the type tree to the end of the diagnostics.
1150 OutStr
.append(Tree
.begin(), Tree
.end());
1153 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level
, unsigned ID
,
1155 : ID(ID
), Level(Level
), Message(Message
) {}
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());
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())
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();
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; }
1194 void IgnoringDiagConsumer::anchor() {}
1196 ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() = default;
1198 void ForwardingDiagnosticConsumer::HandleDiagnostic(
1199 DiagnosticsEngine::Level DiagLevel
,
1200 const Diagnostic
&Info
) {
1201 Target
.HandleDiagnostic(DiagLevel
, Info
);
1204 void ForwardingDiagnosticConsumer::clear() {
1205 DiagnosticConsumer::clear();
1209 bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const {
1210 return Target
.IncludeInDiagnosticCounts();
1213 PartialDiagnostic::DiagStorageAllocator::DiagStorageAllocator() {
1214 for (unsigned I
= 0; I
!= NumCached
; ++I
)
1215 FreeList
[I
] = Cached
+ I
;
1216 NumFreeListEntries
= NumCached
;
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");
1227 char DiagnosticError::ID
;