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
) {
47 switch (nullability
.first
) {
48 case NullabilityKind::NonNull
:
49 string
= nullability
.second
? "'nonnull'" : "'_Nonnull'";
52 case NullabilityKind::Nullable
:
53 string
= nullability
.second
? "'nullable'" : "'_Nullable'";
56 case NullabilityKind::Unspecified
:
57 string
= nullability
.second
? "'null_unspecified'" : "'_Null_unspecified'";
60 case NullabilityKind::NullableResult
:
61 assert(!nullability
.second
&&
62 "_Nullable_result isn't supported as context-sensitive keyword");
63 string
= "_Nullable_result";
71 const StreamingDiagnostic
&clang::operator<<(const StreamingDiagnostic
&DB
,
73 DB
.AddString(toString(std::move(E
)));
77 static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK
, intptr_t QT
,
78 StringRef Modifier
, StringRef Argument
,
79 ArrayRef
<DiagnosticsEngine::ArgumentValue
> PrevArgs
,
80 SmallVectorImpl
<char> &Output
,
82 ArrayRef
<intptr_t> QualTypeVals
) {
83 StringRef Str
= "<can't format argument>";
84 Output
.append(Str
.begin(), Str
.end());
87 DiagnosticsEngine::DiagnosticsEngine(
88 IntrusiveRefCntPtr
<DiagnosticIDs
> diags
,
89 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
, DiagnosticConsumer
*client
,
91 : Diags(std::move(diags
)), DiagOpts(std::move(DiagOpts
)) {
92 setClient(client
, ShouldOwnClient
);
93 ArgToStringFn
= DummyArgToStringFn
;
98 DiagnosticsEngine::~DiagnosticsEngine() {
99 // If we own the diagnostic client, destroy it first so that it can access the
100 // engine from its destructor.
104 void DiagnosticsEngine::dump() const {
105 DiagStatesByLoc
.dump(*SourceMgr
);
108 void DiagnosticsEngine::dump(StringRef DiagName
) const {
109 DiagStatesByLoc
.dump(*SourceMgr
, DiagName
);
112 void DiagnosticsEngine::setClient(DiagnosticConsumer
*client
,
113 bool ShouldOwnClient
) {
114 Owner
.reset(ShouldOwnClient
? client
: nullptr);
118 void DiagnosticsEngine::pushMappings(SourceLocation Loc
) {
119 DiagStateOnPushStack
.push_back(GetCurDiagState());
122 bool DiagnosticsEngine::popMappings(SourceLocation Loc
) {
123 if (DiagStateOnPushStack
.empty())
126 if (DiagStateOnPushStack
.back() != GetCurDiagState()) {
127 // State changed at some point between push/pop.
128 PushDiagStatePoint(DiagStateOnPushStack
.back(), Loc
);
130 DiagStateOnPushStack
.pop_back();
134 void DiagnosticsEngine::Reset(bool soft
/*=false*/) {
135 ErrorOccurred
= false;
136 UncompilableErrorOccurred
= false;
137 FatalErrorOccurred
= false;
138 UnrecoverableErrorOccurred
= false;
142 TrapNumErrorsOccurred
= 0;
143 TrapNumUnrecoverableErrorsOccurred
= 0;
145 CurDiagID
= std::numeric_limits
<unsigned>::max();
146 LastDiagLevel
= DiagnosticIDs::Ignored
;
150 // Clear state related to #pragma diagnostic.
152 DiagStatesByLoc
.clear();
153 DiagStateOnPushStack
.clear();
155 // Create a DiagState and DiagStatePoint representing diagnostic changes
156 // through command-line.
157 DiagStates
.emplace_back();
158 DiagStatesByLoc
.appendFirst(&DiagStates
.back());
162 void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID
, StringRef Arg1
,
163 StringRef Arg2
, StringRef Arg3
) {
167 DelayedDiagID
= DiagID
;
168 DelayedDiagArg1
= Arg1
.str();
169 DelayedDiagArg2
= Arg2
.str();
170 DelayedDiagArg3
= Arg3
.str();
173 void DiagnosticsEngine::ReportDelayed() {
174 unsigned ID
= DelayedDiagID
;
176 Report(ID
) << DelayedDiagArg1
<< DelayedDiagArg2
<< DelayedDiagArg3
;
179 void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState
*State
) {
180 assert(Files
.empty() && "not first");
181 FirstDiagState
= CurDiagState
= State
;
182 CurDiagStateLoc
= SourceLocation();
185 void DiagnosticsEngine::DiagStateMap::append(SourceManager
&SrcMgr
,
188 CurDiagState
= State
;
189 CurDiagStateLoc
= Loc
;
191 std::pair
<FileID
, unsigned> Decomp
= SrcMgr
.getDecomposedLoc(Loc
);
192 unsigned Offset
= Decomp
.second
;
193 for (File
*F
= getFile(SrcMgr
, Decomp
.first
); F
;
194 Offset
= F
->ParentOffset
, F
= F
->Parent
) {
195 F
->HasLocalTransitions
= true;
196 auto &Last
= F
->StateTransitions
.back();
197 assert(Last
.Offset
<= Offset
&& "state transitions added out of order");
199 if (Last
.Offset
== Offset
) {
200 if (Last
.State
== State
)
206 F
->StateTransitions
.push_back({State
, Offset
});
210 DiagnosticsEngine::DiagState
*
211 DiagnosticsEngine::DiagStateMap::lookup(SourceManager
&SrcMgr
,
212 SourceLocation Loc
) const {
213 // Common case: we have not seen any diagnostic pragmas.
215 return FirstDiagState
;
217 std::pair
<FileID
, unsigned> Decomp
= SrcMgr
.getDecomposedLoc(Loc
);
218 const File
*F
= getFile(SrcMgr
, Decomp
.first
);
219 return F
->lookup(Decomp
.second
);
222 DiagnosticsEngine::DiagState
*
223 DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset
) const {
225 llvm::partition_point(StateTransitions
, [=](const DiagStatePoint
&P
) {
226 return P
.Offset
<= Offset
;
228 assert(OnePastIt
!= StateTransitions
.begin() && "missing initial state");
229 return OnePastIt
[-1].State
;
232 DiagnosticsEngine::DiagStateMap::File
*
233 DiagnosticsEngine::DiagStateMap::getFile(SourceManager
&SrcMgr
,
235 // Get or insert the File for this ID.
236 auto Range
= Files
.equal_range(ID
);
237 if (Range
.first
!= Range
.second
)
238 return &Range
.first
->second
;
239 auto &F
= Files
.insert(Range
.first
, std::make_pair(ID
, File()))->second
;
241 // We created a new File; look up the diagnostic state at the start of it and
244 std::pair
<FileID
, unsigned> Decomp
= SrcMgr
.getDecomposedIncludedLoc(ID
);
245 F
.Parent
= getFile(SrcMgr
, Decomp
.first
);
246 F
.ParentOffset
= Decomp
.second
;
247 F
.StateTransitions
.push_back({F
.Parent
->lookup(Decomp
.second
), 0});
249 // This is the (imaginary) root file into which we pretend all top-level
250 // files are included; it descends from the initial state.
252 // FIXME: This doesn't guarantee that we use the same ordering as
253 // isBeforeInTranslationUnit in the cases where someone invented another
254 // top-level file and added diagnostic pragmas to it. See the code at the
255 // end of isBeforeInTranslationUnit for the quirks it deals with.
256 F
.StateTransitions
.push_back({FirstDiagState
, 0});
261 void DiagnosticsEngine::DiagStateMap::dump(SourceManager
&SrcMgr
,
262 StringRef DiagName
) const {
263 llvm::errs() << "diagnostic state at ";
264 CurDiagStateLoc
.print(llvm::errs(), SrcMgr
);
265 llvm::errs() << ": " << CurDiagState
<< "\n";
267 for (auto &F
: Files
) {
269 File
&File
= F
.second
;
271 bool PrintedOuterHeading
= false;
272 auto PrintOuterHeading
= [&] {
273 if (PrintedOuterHeading
) return;
274 PrintedOuterHeading
= true;
276 llvm::errs() << "File " << &File
<< " <FileID " << ID
.getHashValue()
277 << ">: " << SrcMgr
.getBufferOrFake(ID
).getBufferIdentifier();
279 if (F
.second
.Parent
) {
280 std::pair
<FileID
, unsigned> Decomp
=
281 SrcMgr
.getDecomposedIncludedLoc(ID
);
282 assert(File
.ParentOffset
== Decomp
.second
);
283 llvm::errs() << " parent " << File
.Parent
<< " <FileID "
284 << Decomp
.first
.getHashValue() << "> ";
285 SrcMgr
.getLocForStartOfFile(Decomp
.first
)
286 .getLocWithOffset(Decomp
.second
)
287 .print(llvm::errs(), SrcMgr
);
289 if (File
.HasLocalTransitions
)
290 llvm::errs() << " has_local_transitions";
291 llvm::errs() << "\n";
294 if (DiagName
.empty())
297 for (DiagStatePoint
&Transition
: File
.StateTransitions
) {
298 bool PrintedInnerHeading
= false;
299 auto PrintInnerHeading
= [&] {
300 if (PrintedInnerHeading
) return;
301 PrintedInnerHeading
= true;
305 SrcMgr
.getLocForStartOfFile(ID
)
306 .getLocWithOffset(Transition
.Offset
)
307 .print(llvm::errs(), SrcMgr
);
308 llvm::errs() << ": state " << Transition
.State
<< ":\n";
311 if (DiagName
.empty())
314 for (auto &Mapping
: *Transition
.State
) {
316 DiagnosticIDs::getWarningOptionForDiag(Mapping
.first
);
317 if (!DiagName
.empty() && DiagName
!= Option
)
323 llvm::errs() << "<unknown " << Mapping
.first
<< ">";
325 llvm::errs() << Option
;
326 llvm::errs() << ": ";
328 switch (Mapping
.second
.getSeverity()) {
329 case diag::Severity::Ignored
: llvm::errs() << "ignored"; break;
330 case diag::Severity::Remark
: llvm::errs() << "remark"; break;
331 case diag::Severity::Warning
: llvm::errs() << "warning"; break;
332 case diag::Severity::Error
: llvm::errs() << "error"; break;
333 case diag::Severity::Fatal
: llvm::errs() << "fatal"; break;
336 if (!Mapping
.second
.isUser())
337 llvm::errs() << " default";
338 if (Mapping
.second
.isPragma())
339 llvm::errs() << " pragma";
340 if (Mapping
.second
.hasNoWarningAsError())
341 llvm::errs() << " no-error";
342 if (Mapping
.second
.hasNoErrorAsFatal())
343 llvm::errs() << " no-fatal";
344 if (Mapping
.second
.wasUpgradedFromWarning())
345 llvm::errs() << " overruled";
346 llvm::errs() << "\n";
352 void DiagnosticsEngine::PushDiagStatePoint(DiagState
*State
,
353 SourceLocation Loc
) {
354 assert(Loc
.isValid() && "Adding invalid loc point");
355 DiagStatesByLoc
.append(*SourceMgr
, Loc
, State
);
358 void DiagnosticsEngine::setSeverity(diag::kind Diag
, diag::Severity Map
,
360 assert(Diag
< diag::DIAG_UPPER_LIMIT
&&
361 "Can only map builtin diagnostics");
362 assert((Diags
->isBuiltinWarningOrExtension(Diag
) ||
363 (Map
== diag::Severity::Fatal
|| Map
== diag::Severity::Error
)) &&
364 "Cannot map errors into warnings!");
365 assert((L
.isInvalid() || SourceMgr
) && "No SourceMgr for valid location");
367 // Don't allow a mapping to a warning override an error/fatal mapping.
368 bool WasUpgradedFromWarning
= false;
369 if (Map
== diag::Severity::Warning
) {
370 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
371 if (Info
.getSeverity() == diag::Severity::Error
||
372 Info
.getSeverity() == diag::Severity::Fatal
) {
373 Map
= Info
.getSeverity();
374 WasUpgradedFromWarning
= true;
377 DiagnosticMapping Mapping
= makeUserMapping(Map
, L
);
378 Mapping
.setUpgradedFromWarning(WasUpgradedFromWarning
);
380 // Make sure we propagate the NoWarningAsError flag from an existing
381 // mapping (which may be the default mapping).
382 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
383 Mapping
.setNoWarningAsError(Info
.hasNoWarningAsError() ||
384 Mapping
.hasNoWarningAsError());
386 // Common case; setting all the diagnostics of a group in one place.
387 if ((L
.isInvalid() || L
== DiagStatesByLoc
.getCurDiagStateLoc()) &&
388 DiagStatesByLoc
.getCurDiagState()) {
389 // FIXME: This is theoretically wrong: if the current state is shared with
390 // some other location (via push/pop) we will change the state for that
391 // other location as well. This cannot currently happen, as we can't update
392 // the diagnostic state at the same location at which we pop.
393 DiagStatesByLoc
.getCurDiagState()->setMapping(Diag
, Mapping
);
397 // A diagnostic pragma occurred, create a new DiagState initialized with
398 // the current one and a new DiagStatePoint to record at which location
399 // the new state became active.
400 DiagStates
.push_back(*GetCurDiagState());
401 DiagStates
.back().setMapping(Diag
, Mapping
);
402 PushDiagStatePoint(&DiagStates
.back(), L
);
405 bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor
,
406 StringRef Group
, diag::Severity Map
,
407 SourceLocation Loc
) {
408 // Get the diagnostics in this group.
409 SmallVector
<diag::kind
, 256> GroupDiags
;
410 if (Diags
->getDiagnosticsInGroup(Flavor
, Group
, GroupDiags
))
414 for (diag::kind Diag
: GroupDiags
)
415 setSeverity(Diag
, Map
, Loc
);
420 bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor
,
423 SourceLocation Loc
) {
424 return setSeverityForGroup(Flavor
, Diags
->getWarningOptionForGroup(Group
),
428 bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group
,
430 // If we are enabling this feature, just set the diagnostic mappings to map to
433 return setSeverityForGroup(diag::Flavor::WarningOrError
, Group
,
434 diag::Severity::Error
);
436 // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
437 // potentially downgrade anything already mapped to be a warning.
439 // Get the diagnostics in this group.
440 SmallVector
<diag::kind
, 8> GroupDiags
;
441 if (Diags
->getDiagnosticsInGroup(diag::Flavor::WarningOrError
, Group
,
445 // Perform the mapping change.
446 for (diag::kind Diag
: GroupDiags
) {
447 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
449 if (Info
.getSeverity() == diag::Severity::Error
||
450 Info
.getSeverity() == diag::Severity::Fatal
)
451 Info
.setSeverity(diag::Severity::Warning
);
453 Info
.setNoWarningAsError(true);
459 bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group
,
461 // If we are enabling this feature, just set the diagnostic mappings to map to
464 return setSeverityForGroup(diag::Flavor::WarningOrError
, Group
,
465 diag::Severity::Fatal
);
467 // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
468 // and potentially downgrade anything already mapped to be a fatal error.
470 // Get the diagnostics in this group.
471 SmallVector
<diag::kind
, 8> GroupDiags
;
472 if (Diags
->getDiagnosticsInGroup(diag::Flavor::WarningOrError
, Group
,
476 // Perform the mapping change.
477 for (diag::kind Diag
: GroupDiags
) {
478 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
480 if (Info
.getSeverity() == diag::Severity::Fatal
)
481 Info
.setSeverity(diag::Severity::Error
);
483 Info
.setNoErrorAsFatal(true);
489 void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor
,
491 SourceLocation Loc
) {
492 // Get all the diagnostics.
493 std::vector
<diag::kind
> AllDiags
;
494 DiagnosticIDs::getAllDiagnostics(Flavor
, AllDiags
);
497 for (diag::kind Diag
: AllDiags
)
498 if (Diags
->isBuiltinWarningOrExtension(Diag
))
499 setSeverity(Diag
, Map
, Loc
);
502 void DiagnosticsEngine::Report(const StoredDiagnostic
&storedDiag
) {
503 assert(CurDiagID
== std::numeric_limits
<unsigned>::max() &&
504 "Multiple diagnostics in flight at once!");
506 CurDiagLoc
= storedDiag
.getLocation();
507 CurDiagID
= storedDiag
.getID();
508 DiagStorage
.NumDiagArgs
= 0;
510 DiagStorage
.DiagRanges
.clear();
511 DiagStorage
.DiagRanges
.append(storedDiag
.range_begin(),
512 storedDiag
.range_end());
514 DiagStorage
.FixItHints
.clear();
515 DiagStorage
.FixItHints
.append(storedDiag
.fixit_begin(),
516 storedDiag
.fixit_end());
518 assert(Client
&& "DiagnosticConsumer not set!");
519 Level DiagLevel
= storedDiag
.getLevel();
520 Diagnostic
Info(this, storedDiag
.getMessage());
521 Client
->HandleDiagnostic(DiagLevel
, Info
);
522 if (Client
->IncludeInDiagnosticCounts()) {
523 if (DiagLevel
== DiagnosticsEngine::Warning
)
527 CurDiagID
= std::numeric_limits
<unsigned>::max();
530 bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force
) {
531 assert(getClient() && "DiagnosticClient not set!");
535 Diagnostic
Info(this);
537 // Figure out the diagnostic level of this message.
538 DiagnosticIDs::Level DiagLevel
539 = Diags
->getDiagnosticLevel(Info
.getID(), Info
.getLocation(), *this);
541 Emitted
= (DiagLevel
!= DiagnosticIDs::Ignored
);
543 // Emit the diagnostic regardless of suppression level.
544 Diags
->EmitDiag(*this, DiagLevel
);
547 // Process the diagnostic, sending the accumulated information to the
548 // DiagnosticConsumer.
549 Emitted
= ProcessDiag();
552 // Clear out the current diagnostic object.
555 // If there was a delayed diagnostic, emit it now.
556 if (!Force
&& DelayedDiagID
)
562 DiagnosticConsumer::~DiagnosticConsumer() = default;
564 void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel
,
565 const Diagnostic
&Info
) {
566 if (!IncludeInDiagnosticCounts())
569 if (DiagLevel
== DiagnosticsEngine::Warning
)
571 else if (DiagLevel
>= DiagnosticsEngine::Error
)
575 /// ModifierIs - Return true if the specified modifier matches specified string.
576 template <std::size_t StrLen
>
577 static bool ModifierIs(const char *Modifier
, unsigned ModifierLen
,
578 const char (&Str
)[StrLen
]) {
579 return StrLen
-1 == ModifierLen
&& memcmp(Modifier
, Str
, StrLen
-1) == 0;
582 /// ScanForward - Scans forward, looking for the given character, skipping
583 /// nested clauses and escaped characters.
584 static const char *ScanFormat(const char *I
, const char *E
, char Target
) {
587 for ( ; I
!= E
; ++I
) {
588 if (Depth
== 0 && *I
== Target
) return I
;
589 if (Depth
!= 0 && *I
== '}') Depth
--;
595 // Escaped characters get implicitly skipped here.
598 if (!isDigit(*I
) && !isPunctuation(*I
)) {
599 for (I
++; I
!= E
&& !isDigit(*I
) && *I
!= '{'; I
++) ;
609 /// HandleSelectModifier - Handle the integer 'select' modifier. This is used
610 /// like this: %select{foo|bar|baz}2. This means that the integer argument
611 /// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
612 /// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
613 /// This is very useful for certain classes of variant diagnostics.
614 static void HandleSelectModifier(const Diagnostic
&DInfo
, unsigned ValNo
,
615 const char *Argument
, unsigned ArgumentLen
,
616 SmallVectorImpl
<char> &OutStr
) {
617 const char *ArgumentEnd
= Argument
+ArgumentLen
;
619 // Skip over 'ValNo' |'s.
621 const char *NextVal
= ScanFormat(Argument
, ArgumentEnd
, '|');
622 assert(NextVal
!= ArgumentEnd
&& "Value for integer select modifier was"
623 " larger than the number of options in the diagnostic string!");
624 Argument
= NextVal
+1; // Skip this string.
628 // Get the end of the value. This is either the } or the |.
629 const char *EndPtr
= ScanFormat(Argument
, ArgumentEnd
, '|');
631 // Recursively format the result of the select clause into the output string.
632 DInfo
.FormatDiagnostic(Argument
, EndPtr
, OutStr
);
635 /// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
636 /// letter 's' to the string if the value is not 1. This is used in cases like
637 /// this: "you idiot, you have %4 parameter%s4!".
638 static void HandleIntegerSModifier(unsigned ValNo
,
639 SmallVectorImpl
<char> &OutStr
) {
641 OutStr
.push_back('s');
644 /// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
645 /// prints the ordinal form of the given integer, with 1 corresponding
646 /// to the first ordinal. Currently this is hard-coded to use the
648 static void HandleOrdinalModifier(unsigned ValNo
,
649 SmallVectorImpl
<char> &OutStr
) {
650 assert(ValNo
!= 0 && "ValNo must be strictly positive!");
652 llvm::raw_svector_ostream
Out(OutStr
);
654 // We could use text forms for the first N ordinals, but the numeric
655 // forms are actually nicer in diagnostics because they stand out.
656 Out
<< ValNo
<< llvm::getOrdinalSuffix(ValNo
);
659 /// PluralNumber - Parse an unsigned integer and advance Start.
660 static unsigned PluralNumber(const char *&Start
, const char *End
) {
661 // Programming 101: Parse a decimal number :-)
663 while (Start
!= End
&& *Start
>= '0' && *Start
<= '9') {
671 /// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
672 static bool TestPluralRange(unsigned Val
, const char *&Start
, const char *End
) {
674 unsigned Ref
= PluralNumber(Start
, End
);
679 unsigned Low
= PluralNumber(Start
, End
);
680 assert(*Start
== ',' && "Bad plural expression syntax: expected ,");
682 unsigned High
= PluralNumber(Start
, End
);
683 assert(*Start
== ']' && "Bad plural expression syntax: expected )");
685 return Low
<= Val
&& Val
<= High
;
688 /// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
689 static bool EvalPluralExpr(unsigned ValNo
, const char *Start
, const char *End
) {
699 unsigned Arg
= PluralNumber(Start
, End
);
700 assert(*Start
== '=' && "Bad plural expression syntax: expected =");
702 unsigned ValMod
= ValNo
% Arg
;
703 if (TestPluralRange(ValMod
, Start
, End
))
706 assert((C
== '[' || (C
>= '0' && C
<= '9')) &&
707 "Bad plural expression syntax: unexpected character");
709 if (TestPluralRange(ValNo
, Start
, End
))
713 // Scan for next or-expr part.
714 Start
= std::find(Start
, End
, ',');
722 /// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
723 /// for complex plural forms, or in languages where all plurals are complex.
724 /// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
725 /// conditions that are tested in order, the form corresponding to the first
726 /// that applies being emitted. The empty condition is always true, making the
727 /// last form a default case.
728 /// Conditions are simple boolean expressions, where n is the number argument.
729 /// Here are the rules.
730 /// condition := expression | empty
731 /// empty := -> always true
732 /// expression := numeric [',' expression] -> logical or
733 /// numeric := range -> true if n in range
734 /// | '%' number '=' range -> true if n % number in range
736 /// | '[' number ',' number ']' -> ranges are inclusive both ends
738 /// Here are some examples from the GNU gettext manual written in this form:
742 /// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
744 /// {1:form0|2:form1|:form2}
746 /// {1:form0|0,%100=[1,19]:form1|:form2}
748 /// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
749 /// Russian (requires repeated form):
750 /// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
752 /// {1:form0|[2,4]:form1|:form2}
753 /// Polish (requires repeated form):
754 /// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
755 static void HandlePluralModifier(const Diagnostic
&DInfo
, unsigned ValNo
,
756 const char *Argument
, unsigned ArgumentLen
,
757 SmallVectorImpl
<char> &OutStr
) {
758 const char *ArgumentEnd
= Argument
+ ArgumentLen
;
760 assert(Argument
< ArgumentEnd
&& "Plural expression didn't match.");
761 const char *ExprEnd
= Argument
;
762 while (*ExprEnd
!= ':') {
763 assert(ExprEnd
!= ArgumentEnd
&& "Plural missing expression end");
766 if (EvalPluralExpr(ValNo
, Argument
, ExprEnd
)) {
767 Argument
= ExprEnd
+ 1;
768 ExprEnd
= ScanFormat(Argument
, ArgumentEnd
, '|');
770 // Recursively format the result of the plural clause into the
772 DInfo
.FormatDiagnostic(Argument
, ExprEnd
, OutStr
);
775 Argument
= ScanFormat(Argument
, ArgumentEnd
- 1, '|') + 1;
779 /// Returns the friendly description for a token kind that will appear
780 /// without quotes in diagnostic messages. These strings may be translatable in
782 static const char *getTokenDescForDiagnostic(tok::TokenKind Kind
) {
784 case tok::identifier
:
791 /// FormatDiagnostic - Format this diagnostic into a string, substituting the
792 /// formal arguments into the %0 slots. The result is appended onto the Str
795 FormatDiagnostic(SmallVectorImpl
<char> &OutStr
) const {
796 if (!StoredDiagMessage
.empty()) {
797 OutStr
.append(StoredDiagMessage
.begin(), StoredDiagMessage
.end());
802 getDiags()->getDiagnosticIDs()->getDescription(getID());
804 FormatDiagnostic(Diag
.begin(), Diag
.end(), OutStr
);
807 /// pushEscapedString - Append Str to the diagnostic buffer,
808 /// escaping non-printable characters and ill-formed code unit sequences.
809 static void pushEscapedString(StringRef Str
, SmallVectorImpl
<char> &OutStr
) {
810 OutStr
.reserve(OutStr
.size() + Str
.size());
811 auto *Begin
= reinterpret_cast<const unsigned char *>(Str
.data());
812 llvm::raw_svector_ostream
OutStream(OutStr
);
813 const unsigned char *End
= Begin
+ Str
.size();
814 while (Begin
!= End
) {
816 if (isPrintable(*Begin
) || isWhitespace(*Begin
)) {
821 if (llvm::isLegalUTF8Sequence(Begin
, End
)) {
822 llvm::UTF32 CodepointValue
;
823 llvm::UTF32
*CpPtr
= &CodepointValue
;
824 const unsigned char *CodepointBegin
= Begin
;
825 const unsigned char *CodepointEnd
=
826 Begin
+ llvm::getNumBytesForUTF8(*Begin
);
827 llvm::ConversionResult Res
= llvm::ConvertUTF8toUTF32(
828 &Begin
, CodepointEnd
, &CpPtr
, CpPtr
+ 1, llvm::strictConversion
);
831 llvm::conversionOK
== Res
&&
832 "the sequence is legal UTF-8 but we couldn't convert it to UTF-32");
833 assert(Begin
== CodepointEnd
&&
834 "we must be further along in the string now");
835 if (llvm::sys::unicode::isPrintable(CodepointValue
) ||
836 llvm::sys::unicode::isFormatting(CodepointValue
)) {
837 OutStr
.append(CodepointBegin
, CodepointEnd
);
840 // Unprintable code point.
841 OutStream
<< "<U+" << llvm::format_hex_no_prefix(CodepointValue
, 4, true)
845 // Invalid code unit.
846 OutStream
<< "<" << llvm::format_hex_no_prefix(*Begin
, 2, true) << ">";
852 FormatDiagnostic(const char *DiagStr
, const char *DiagEnd
,
853 SmallVectorImpl
<char> &OutStr
) const {
854 // When the diagnostic string is only "%0", the entire string is being given
855 // by an outside source. Remove unprintable characters from this string
856 // and skip all the other string processing.
857 if (DiagEnd
- DiagStr
== 2 &&
858 StringRef(DiagStr
, DiagEnd
- DiagStr
).equals("%0") &&
859 getArgKind(0) == DiagnosticsEngine::ak_std_string
) {
860 const std::string
&S
= getArgStdStr(0);
861 pushEscapedString(S
, OutStr
);
865 /// FormattedArgs - Keep track of all of the arguments formatted by
866 /// ConvertArgToString and pass them into subsequent calls to
867 /// ConvertArgToString, allowing the implementation to avoid redundancies in
869 SmallVector
<DiagnosticsEngine::ArgumentValue
, 8> FormattedArgs
;
871 /// QualTypeVals - Pass a vector of arrays so that QualType names can be
872 /// compared to see if more information is needed to be printed.
873 SmallVector
<intptr_t, 2> QualTypeVals
;
874 SmallString
<64> Tree
;
876 for (unsigned i
= 0, e
= getNumArgs(); i
< e
; ++i
)
877 if (getArgKind(i
) == DiagnosticsEngine::ak_qualtype
)
878 QualTypeVals
.push_back(getRawArg(i
));
880 while (DiagStr
!= DiagEnd
) {
881 if (DiagStr
[0] != '%') {
882 // Append non-%0 substrings to Str if we have one.
883 const char *StrEnd
= std::find(DiagStr
, DiagEnd
, '%');
884 OutStr
.append(DiagStr
, StrEnd
);
887 } else if (isPunctuation(DiagStr
[1])) {
888 OutStr
.push_back(DiagStr
[1]); // %% -> %.
896 // This must be a placeholder for a diagnostic argument. The format for a
897 // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
898 // The digit is a number from 0-9 indicating which argument this comes from.
899 // The modifier is a string of digits from the set [-a-z]+, arguments is a
900 // brace enclosed string.
901 const char *Modifier
= nullptr, *Argument
= nullptr;
902 unsigned ModifierLen
= 0, ArgumentLen
= 0;
904 // Check to see if we have a modifier. If so eat it.
905 if (!isDigit(DiagStr
[0])) {
907 while (DiagStr
[0] == '-' ||
908 (DiagStr
[0] >= 'a' && DiagStr
[0] <= 'z'))
910 ModifierLen
= DiagStr
-Modifier
;
912 // If we have an argument, get it next.
913 if (DiagStr
[0] == '{') {
914 ++DiagStr
; // Skip {.
917 DiagStr
= ScanFormat(DiagStr
, DiagEnd
, '}');
918 assert(DiagStr
!= DiagEnd
&& "Mismatched {}'s in diagnostic string!");
919 ArgumentLen
= DiagStr
-Argument
;
920 ++DiagStr
; // Skip }.
924 assert(isDigit(*DiagStr
) && "Invalid format for argument in diagnostic");
925 unsigned ArgNo
= *DiagStr
++ - '0';
927 // Only used for type diffing.
928 unsigned ArgNo2
= ArgNo
;
930 DiagnosticsEngine::ArgumentKind Kind
= getArgKind(ArgNo
);
931 if (ModifierIs(Modifier
, ModifierLen
, "diff")) {
932 assert(*DiagStr
== ',' && isDigit(*(DiagStr
+ 1)) &&
933 "Invalid format for diff modifier");
935 ArgNo2
= *DiagStr
++ - '0';
936 DiagnosticsEngine::ArgumentKind Kind2
= getArgKind(ArgNo2
);
937 if (Kind
== DiagnosticsEngine::ak_qualtype
&&
938 Kind2
== DiagnosticsEngine::ak_qualtype
)
939 Kind
= DiagnosticsEngine::ak_qualtype_pair
;
941 // %diff only supports QualTypes. For other kinds of arguments,
942 // use the default printing. For example, if the modifier is:
943 // "%diff{compare $ to $|other text}1,2"
945 // "compare %1 to %2"
946 const char *ArgumentEnd
= Argument
+ ArgumentLen
;
947 const char *Pipe
= ScanFormat(Argument
, ArgumentEnd
, '|');
948 assert(ScanFormat(Pipe
+ 1, ArgumentEnd
, '|') == ArgumentEnd
&&
949 "Found too many '|'s in a %diff modifier!");
950 const char *FirstDollar
= ScanFormat(Argument
, Pipe
, '$');
951 const char *SecondDollar
= ScanFormat(FirstDollar
+ 1, Pipe
, '$');
952 const char ArgStr1
[] = { '%', static_cast<char>('0' + ArgNo
) };
953 const char ArgStr2
[] = { '%', static_cast<char>('0' + ArgNo2
) };
954 FormatDiagnostic(Argument
, FirstDollar
, OutStr
);
955 FormatDiagnostic(ArgStr1
, ArgStr1
+ 2, OutStr
);
956 FormatDiagnostic(FirstDollar
+ 1, SecondDollar
, OutStr
);
957 FormatDiagnostic(ArgStr2
, ArgStr2
+ 2, OutStr
);
958 FormatDiagnostic(SecondDollar
+ 1, Pipe
, OutStr
);
965 case DiagnosticsEngine::ak_std_string
: {
966 const std::string
&S
= getArgStdStr(ArgNo
);
967 assert(ModifierLen
== 0 && "No modifiers for strings yet");
968 pushEscapedString(S
, OutStr
);
971 case DiagnosticsEngine::ak_c_string
: {
972 const char *S
= getArgCStr(ArgNo
);
973 assert(ModifierLen
== 0 && "No modifiers for strings yet");
975 // Don't crash if get passed a null pointer by accident.
978 pushEscapedString(S
, OutStr
);
981 // ---- INTEGERS ----
982 case DiagnosticsEngine::ak_sint
: {
983 int64_t Val
= getArgSInt(ArgNo
);
985 if (ModifierIs(Modifier
, ModifierLen
, "select")) {
986 HandleSelectModifier(*this, (unsigned)Val
, Argument
, ArgumentLen
,
988 } else if (ModifierIs(Modifier
, ModifierLen
, "s")) {
989 HandleIntegerSModifier(Val
, OutStr
);
990 } else if (ModifierIs(Modifier
, ModifierLen
, "plural")) {
991 HandlePluralModifier(*this, (unsigned)Val
, Argument
, ArgumentLen
,
993 } else if (ModifierIs(Modifier
, ModifierLen
, "ordinal")) {
994 HandleOrdinalModifier((unsigned)Val
, OutStr
);
996 assert(ModifierLen
== 0 && "Unknown integer modifier");
997 llvm::raw_svector_ostream(OutStr
) << Val
;
1001 case DiagnosticsEngine::ak_uint
: {
1002 uint64_t Val
= getArgUInt(ArgNo
);
1004 if (ModifierIs(Modifier
, ModifierLen
, "select")) {
1005 HandleSelectModifier(*this, Val
, Argument
, ArgumentLen
, OutStr
);
1006 } else if (ModifierIs(Modifier
, ModifierLen
, "s")) {
1007 HandleIntegerSModifier(Val
, OutStr
);
1008 } else if (ModifierIs(Modifier
, ModifierLen
, "plural")) {
1009 HandlePluralModifier(*this, (unsigned)Val
, Argument
, ArgumentLen
,
1011 } else if (ModifierIs(Modifier
, ModifierLen
, "ordinal")) {
1012 HandleOrdinalModifier(Val
, OutStr
);
1014 assert(ModifierLen
== 0 && "Unknown integer modifier");
1015 llvm::raw_svector_ostream(OutStr
) << Val
;
1019 // ---- TOKEN SPELLINGS ----
1020 case DiagnosticsEngine::ak_tokenkind
: {
1021 tok::TokenKind Kind
= static_cast<tok::TokenKind
>(getRawArg(ArgNo
));
1022 assert(ModifierLen
== 0 && "No modifiers for token kinds yet");
1024 llvm::raw_svector_ostream
Out(OutStr
);
1025 if (const char *S
= tok::getPunctuatorSpelling(Kind
))
1026 // Quoted token spelling for punctuators.
1027 Out
<< '\'' << S
<< '\'';
1028 else if ((S
= tok::getKeywordSpelling(Kind
)))
1029 // Unquoted token spelling for keywords.
1031 else if ((S
= getTokenDescForDiagnostic(Kind
)))
1032 // Unquoted translatable token name.
1034 else if ((S
= tok::getTokenName(Kind
)))
1035 // Debug name, shouldn't appear in user-facing diagnostics.
1036 Out
<< '<' << S
<< '>';
1041 // ---- NAMES and TYPES ----
1042 case DiagnosticsEngine::ak_identifierinfo
: {
1043 const IdentifierInfo
*II
= getArgIdentifier(ArgNo
);
1044 assert(ModifierLen
== 0 && "No modifiers for strings yet");
1046 // Don't crash if get passed a null pointer by accident.
1048 const char *S
= "(null)";
1049 OutStr
.append(S
, S
+ strlen(S
));
1053 llvm::raw_svector_ostream(OutStr
) << '\'' << II
->getName() << '\'';
1056 case DiagnosticsEngine::ak_addrspace
:
1057 case DiagnosticsEngine::ak_qual
:
1058 case DiagnosticsEngine::ak_qualtype
:
1059 case DiagnosticsEngine::ak_declarationname
:
1060 case DiagnosticsEngine::ak_nameddecl
:
1061 case DiagnosticsEngine::ak_nestednamespec
:
1062 case DiagnosticsEngine::ak_declcontext
:
1063 case DiagnosticsEngine::ak_attr
:
1064 getDiags()->ConvertArgToString(Kind
, getRawArg(ArgNo
),
1065 StringRef(Modifier
, ModifierLen
),
1066 StringRef(Argument
, ArgumentLen
),
1068 OutStr
, QualTypeVals
);
1070 case DiagnosticsEngine::ak_qualtype_pair
: {
1071 // Create a struct with all the info needed for printing.
1072 TemplateDiffTypes TDT
;
1073 TDT
.FromType
= getRawArg(ArgNo
);
1074 TDT
.ToType
= getRawArg(ArgNo2
);
1075 TDT
.ElideType
= getDiags()->ElideType
;
1076 TDT
.ShowColors
= getDiags()->ShowColors
;
1077 TDT
.TemplateDiffUsed
= false;
1078 intptr_t val
= reinterpret_cast<intptr_t>(&TDT
);
1080 const char *ArgumentEnd
= Argument
+ ArgumentLen
;
1081 const char *Pipe
= ScanFormat(Argument
, ArgumentEnd
, '|');
1083 // Print the tree. If this diagnostic already has a tree, skip the
1085 if (getDiags()->PrintTemplateTree
&& Tree
.empty()) {
1086 TDT
.PrintFromType
= true;
1087 TDT
.PrintTree
= true;
1088 getDiags()->ConvertArgToString(Kind
, val
,
1089 StringRef(Modifier
, ModifierLen
),
1090 StringRef(Argument
, ArgumentLen
),
1092 Tree
, QualTypeVals
);
1093 // If there is no tree information, fall back to regular printing.
1094 if (!Tree
.empty()) {
1095 FormatDiagnostic(Pipe
+ 1, ArgumentEnd
, OutStr
);
1100 // Non-tree printing, also the fall-back when tree printing fails.
1101 // The fall-back is triggered when the types compared are not templates.
1102 const char *FirstDollar
= ScanFormat(Argument
, ArgumentEnd
, '$');
1103 const char *SecondDollar
= ScanFormat(FirstDollar
+ 1, ArgumentEnd
, '$');
1105 // Append before text
1106 FormatDiagnostic(Argument
, FirstDollar
, OutStr
);
1108 // Append first type
1109 TDT
.PrintTree
= false;
1110 TDT
.PrintFromType
= true;
1111 getDiags()->ConvertArgToString(Kind
, val
,
1112 StringRef(Modifier
, ModifierLen
),
1113 StringRef(Argument
, ArgumentLen
),
1115 OutStr
, QualTypeVals
);
1116 if (!TDT
.TemplateDiffUsed
)
1117 FormattedArgs
.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype
,
1120 // Append middle text
1121 FormatDiagnostic(FirstDollar
+ 1, SecondDollar
, OutStr
);
1123 // Append second type
1124 TDT
.PrintFromType
= false;
1125 getDiags()->ConvertArgToString(Kind
, val
,
1126 StringRef(Modifier
, ModifierLen
),
1127 StringRef(Argument
, ArgumentLen
),
1129 OutStr
, QualTypeVals
);
1130 if (!TDT
.TemplateDiffUsed
)
1131 FormattedArgs
.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype
,
1135 FormatDiagnostic(SecondDollar
+ 1, Pipe
, OutStr
);
1140 // Remember this argument info for subsequent formatting operations. Turn
1141 // std::strings into a null terminated string to make it be the same case as
1142 // all the other ones.
1143 if (Kind
== DiagnosticsEngine::ak_qualtype_pair
)
1145 else if (Kind
!= DiagnosticsEngine::ak_std_string
)
1146 FormattedArgs
.push_back(std::make_pair(Kind
, getRawArg(ArgNo
)));
1148 FormattedArgs
.push_back(std::make_pair(DiagnosticsEngine::ak_c_string
,
1149 (intptr_t)getArgStdStr(ArgNo
).c_str()));
1152 // Append the type tree to the end of the diagnostics.
1153 OutStr
.append(Tree
.begin(), Tree
.end());
1156 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level
, unsigned ID
,
1158 : ID(ID
), Level(Level
), Message(Message
) {}
1160 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level
,
1161 const Diagnostic
&Info
)
1162 : ID(Info
.getID()), Level(Level
) {
1163 assert((Info
.getLocation().isInvalid() || Info
.hasSourceManager()) &&
1164 "Valid source location without setting a source manager for diagnostic");
1165 if (Info
.getLocation().isValid())
1166 Loc
= FullSourceLoc(Info
.getLocation(), Info
.getSourceManager());
1167 SmallString
<64> Message
;
1168 Info
.FormatDiagnostic(Message
);
1169 this->Message
.assign(Message
.begin(), Message
.end());
1170 this->Ranges
.assign(Info
.getRanges().begin(), Info
.getRanges().end());
1171 this->FixIts
.assign(Info
.getFixItHints().begin(), Info
.getFixItHints().end());
1174 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level
, unsigned ID
,
1175 StringRef Message
, FullSourceLoc Loc
,
1176 ArrayRef
<CharSourceRange
> Ranges
,
1177 ArrayRef
<FixItHint
> FixIts
)
1178 : ID(ID
), Level(Level
), Loc(Loc
), Message(Message
),
1179 Ranges(Ranges
.begin(), Ranges
.end()), FixIts(FixIts
.begin(), FixIts
.end())
1183 llvm::raw_ostream
&clang::operator<<(llvm::raw_ostream
&OS
,
1184 const StoredDiagnostic
&SD
) {
1185 if (SD
.getLocation().hasManager())
1186 OS
<< SD
.getLocation().printToString(SD
.getLocation().getManager()) << ": ";
1187 OS
<< SD
.getMessage();
1191 /// IncludeInDiagnosticCounts - This method (whose default implementation
1192 /// returns true) indicates whether the diagnostics handled by this
1193 /// DiagnosticConsumer should be included in the number of diagnostics
1194 /// reported by DiagnosticsEngine.
1195 bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; }
1197 void IgnoringDiagConsumer::anchor() {}
1199 ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() = default;
1201 void ForwardingDiagnosticConsumer::HandleDiagnostic(
1202 DiagnosticsEngine::Level DiagLevel
,
1203 const Diagnostic
&Info
) {
1204 Target
.HandleDiagnostic(DiagLevel
, Info
);
1207 void ForwardingDiagnosticConsumer::clear() {
1208 DiagnosticConsumer::clear();
1212 bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const {
1213 return Target
.IncludeInDiagnosticCounts();
1216 PartialDiagnostic::DiagStorageAllocator::DiagStorageAllocator() {
1217 for (unsigned I
= 0; I
!= NumCached
; ++I
)
1218 FreeList
[I
] = Cached
+ I
;
1219 NumFreeListEntries
= NumCached
;
1222 PartialDiagnostic::DiagStorageAllocator::~DiagStorageAllocator() {
1223 // Don't assert if we are in a CrashRecovery context, as this invariant may
1224 // be invalidated during a crash.
1225 assert((NumFreeListEntries
== NumCached
||
1226 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1227 "A partial is on the lam");
1230 char DiagnosticError::ID
;