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/DiagnosticDriver.h"
16 #include "clang/Basic/DiagnosticError.h"
17 #include "clang/Basic/DiagnosticFrontend.h"
18 #include "clang/Basic/DiagnosticIDs.h"
19 #include "clang/Basic/DiagnosticOptions.h"
20 #include "clang/Basic/IdentifierTable.h"
21 #include "clang/Basic/PartialDiagnostic.h"
22 #include "clang/Basic/SourceLocation.h"
23 #include "clang/Basic/SourceManager.h"
24 #include "clang/Basic/Specifiers.h"
25 #include "clang/Basic/TokenKinds.h"
26 #include "llvm/ADT/IntrusiveRefCntPtr.h"
27 #include "llvm/ADT/SmallString.h"
28 #include "llvm/ADT/SmallVector.h"
29 #include "llvm/ADT/StringExtras.h"
30 #include "llvm/ADT/StringMap.h"
31 #include "llvm/ADT/StringRef.h"
32 #include "llvm/Support/ConvertUTF.h"
33 #include "llvm/Support/CrashRecoveryContext.h"
34 #include "llvm/Support/Error.h"
35 #include "llvm/Support/MemoryBuffer.h"
36 #include "llvm/Support/SpecialCaseList.h"
37 #include "llvm/Support/Unicode.h"
38 #include "llvm/Support/VirtualFileSystem.h"
39 #include "llvm/Support/raw_ostream.h"
51 using namespace clang
;
53 const StreamingDiagnostic
&clang::operator<<(const StreamingDiagnostic
&DB
,
54 DiagNullabilityKind nullability
) {
57 getNullabilitySpelling(nullability
.first
,
58 /*isContextSensitive=*/nullability
.second
) +
64 const StreamingDiagnostic
&clang::operator<<(const StreamingDiagnostic
&DB
,
66 DB
.AddString(toString(std::move(E
)));
70 static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK
, intptr_t QT
,
71 StringRef Modifier
, StringRef Argument
,
72 ArrayRef
<DiagnosticsEngine::ArgumentValue
> PrevArgs
,
73 SmallVectorImpl
<char> &Output
,
75 ArrayRef
<intptr_t> QualTypeVals
) {
76 StringRef Str
= "<can't format argument>";
77 Output
.append(Str
.begin(), Str
.end());
80 DiagnosticsEngine::DiagnosticsEngine(
81 IntrusiveRefCntPtr
<DiagnosticIDs
> diags
,
82 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
, DiagnosticConsumer
*client
,
84 : Diags(std::move(diags
)), DiagOpts(std::move(DiagOpts
)) {
85 setClient(client
, ShouldOwnClient
);
86 ArgToStringFn
= DummyArgToStringFn
;
91 DiagnosticsEngine::~DiagnosticsEngine() {
92 // If we own the diagnostic client, destroy it first so that it can access the
93 // engine from its destructor.
97 void DiagnosticsEngine::dump() const {
98 DiagStatesByLoc
.dump(*SourceMgr
);
101 void DiagnosticsEngine::dump(StringRef DiagName
) const {
102 DiagStatesByLoc
.dump(*SourceMgr
, DiagName
);
105 void DiagnosticsEngine::setClient(DiagnosticConsumer
*client
,
106 bool ShouldOwnClient
) {
107 Owner
.reset(ShouldOwnClient
? client
: nullptr);
111 void DiagnosticsEngine::pushMappings(SourceLocation Loc
) {
112 DiagStateOnPushStack
.push_back(GetCurDiagState());
115 bool DiagnosticsEngine::popMappings(SourceLocation Loc
) {
116 if (DiagStateOnPushStack
.empty())
119 if (DiagStateOnPushStack
.back() != GetCurDiagState()) {
120 // State changed at some point between push/pop.
121 PushDiagStatePoint(DiagStateOnPushStack
.back(), Loc
);
123 DiagStateOnPushStack
.pop_back();
127 void DiagnosticsEngine::Reset(bool soft
/*=false*/) {
128 ErrorOccurred
= false;
129 UncompilableErrorOccurred
= false;
130 FatalErrorOccurred
= false;
131 UnrecoverableErrorOccurred
= false;
135 TrapNumErrorsOccurred
= 0;
136 TrapNumUnrecoverableErrorsOccurred
= 0;
138 LastDiagLevel
= DiagnosticIDs::Ignored
;
141 // Clear state related to #pragma diagnostic.
143 DiagStatesByLoc
.clear();
144 DiagStateOnPushStack
.clear();
146 // Create a DiagState and DiagStatePoint representing diagnostic changes
147 // through command-line.
148 DiagStates
.emplace_back();
149 DiagStatesByLoc
.appendFirst(&DiagStates
.back());
154 DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag
) {
155 std::pair
<iterator
, bool> Result
=
156 DiagMap
.insert(std::make_pair(Diag
, DiagnosticMapping()));
158 // Initialize the entry if we added it.
160 Result
.first
->second
= DiagnosticIDs::getDefaultMapping(Diag
);
162 return Result
.first
->second
;
165 void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState
*State
) {
166 assert(Files
.empty() && "not first");
167 FirstDiagState
= CurDiagState
= State
;
168 CurDiagStateLoc
= SourceLocation();
171 void DiagnosticsEngine::DiagStateMap::append(SourceManager
&SrcMgr
,
174 CurDiagState
= State
;
175 CurDiagStateLoc
= Loc
;
177 std::pair
<FileID
, unsigned> Decomp
= SrcMgr
.getDecomposedLoc(Loc
);
178 unsigned Offset
= Decomp
.second
;
179 for (File
*F
= getFile(SrcMgr
, Decomp
.first
); F
;
180 Offset
= F
->ParentOffset
, F
= F
->Parent
) {
181 F
->HasLocalTransitions
= true;
182 auto &Last
= F
->StateTransitions
.back();
183 assert(Last
.Offset
<= Offset
&& "state transitions added out of order");
185 if (Last
.Offset
== Offset
) {
186 if (Last
.State
== State
)
192 F
->StateTransitions
.push_back({State
, Offset
});
196 DiagnosticsEngine::DiagState
*
197 DiagnosticsEngine::DiagStateMap::lookup(SourceManager
&SrcMgr
,
198 SourceLocation Loc
) const {
199 // Common case: we have not seen any diagnostic pragmas.
201 return FirstDiagState
;
203 std::pair
<FileID
, unsigned> Decomp
= SrcMgr
.getDecomposedLoc(Loc
);
204 const File
*F
= getFile(SrcMgr
, Decomp
.first
);
205 return F
->lookup(Decomp
.second
);
208 DiagnosticsEngine::DiagState
*
209 DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset
) const {
211 llvm::partition_point(StateTransitions
, [=](const DiagStatePoint
&P
) {
212 return P
.Offset
<= Offset
;
214 assert(OnePastIt
!= StateTransitions
.begin() && "missing initial state");
215 return OnePastIt
[-1].State
;
218 DiagnosticsEngine::DiagStateMap::File
*
219 DiagnosticsEngine::DiagStateMap::getFile(SourceManager
&SrcMgr
,
221 // Get or insert the File for this ID.
222 auto Range
= Files
.equal_range(ID
);
223 if (Range
.first
!= Range
.second
)
224 return &Range
.first
->second
;
225 auto &F
= Files
.insert(Range
.first
, std::make_pair(ID
, File()))->second
;
227 // We created a new File; look up the diagnostic state at the start of it and
230 std::pair
<FileID
, unsigned> Decomp
= SrcMgr
.getDecomposedIncludedLoc(ID
);
231 F
.Parent
= getFile(SrcMgr
, Decomp
.first
);
232 F
.ParentOffset
= Decomp
.second
;
233 F
.StateTransitions
.push_back({F
.Parent
->lookup(Decomp
.second
), 0});
235 // This is the (imaginary) root file into which we pretend all top-level
236 // files are included; it descends from the initial state.
238 // FIXME: This doesn't guarantee that we use the same ordering as
239 // isBeforeInTranslationUnit in the cases where someone invented another
240 // top-level file and added diagnostic pragmas to it. See the code at the
241 // end of isBeforeInTranslationUnit for the quirks it deals with.
242 F
.StateTransitions
.push_back({FirstDiagState
, 0});
247 void DiagnosticsEngine::DiagStateMap::dump(SourceManager
&SrcMgr
,
248 StringRef DiagName
) const {
249 llvm::errs() << "diagnostic state at ";
250 CurDiagStateLoc
.print(llvm::errs(), SrcMgr
);
251 llvm::errs() << ": " << CurDiagState
<< "\n";
253 for (auto &F
: Files
) {
255 File
&File
= F
.second
;
257 bool PrintedOuterHeading
= false;
258 auto PrintOuterHeading
= [&] {
259 if (PrintedOuterHeading
) return;
260 PrintedOuterHeading
= true;
262 llvm::errs() << "File " << &File
<< " <FileID " << ID
.getHashValue()
263 << ">: " << SrcMgr
.getBufferOrFake(ID
).getBufferIdentifier();
265 if (F
.second
.Parent
) {
266 std::pair
<FileID
, unsigned> Decomp
=
267 SrcMgr
.getDecomposedIncludedLoc(ID
);
268 assert(File
.ParentOffset
== Decomp
.second
);
269 llvm::errs() << " parent " << File
.Parent
<< " <FileID "
270 << Decomp
.first
.getHashValue() << "> ";
271 SrcMgr
.getLocForStartOfFile(Decomp
.first
)
272 .getLocWithOffset(Decomp
.second
)
273 .print(llvm::errs(), SrcMgr
);
275 if (File
.HasLocalTransitions
)
276 llvm::errs() << " has_local_transitions";
277 llvm::errs() << "\n";
280 if (DiagName
.empty())
283 for (DiagStatePoint
&Transition
: File
.StateTransitions
) {
284 bool PrintedInnerHeading
= false;
285 auto PrintInnerHeading
= [&] {
286 if (PrintedInnerHeading
) return;
287 PrintedInnerHeading
= true;
291 SrcMgr
.getLocForStartOfFile(ID
)
292 .getLocWithOffset(Transition
.Offset
)
293 .print(llvm::errs(), SrcMgr
);
294 llvm::errs() << ": state " << Transition
.State
<< ":\n";
297 if (DiagName
.empty())
300 for (auto &Mapping
: *Transition
.State
) {
302 DiagnosticIDs::getWarningOptionForDiag(Mapping
.first
);
303 if (!DiagName
.empty() && DiagName
!= Option
)
309 llvm::errs() << "<unknown " << Mapping
.first
<< ">";
311 llvm::errs() << Option
;
312 llvm::errs() << ": ";
314 switch (Mapping
.second
.getSeverity()) {
315 case diag::Severity::Ignored
: llvm::errs() << "ignored"; break;
316 case diag::Severity::Remark
: llvm::errs() << "remark"; break;
317 case diag::Severity::Warning
: llvm::errs() << "warning"; break;
318 case diag::Severity::Error
: llvm::errs() << "error"; break;
319 case diag::Severity::Fatal
: llvm::errs() << "fatal"; break;
322 if (!Mapping
.second
.isUser())
323 llvm::errs() << " default";
324 if (Mapping
.second
.isPragma())
325 llvm::errs() << " pragma";
326 if (Mapping
.second
.hasNoWarningAsError())
327 llvm::errs() << " no-error";
328 if (Mapping
.second
.hasNoErrorAsFatal())
329 llvm::errs() << " no-fatal";
330 if (Mapping
.second
.wasUpgradedFromWarning())
331 llvm::errs() << " overruled";
332 llvm::errs() << "\n";
338 void DiagnosticsEngine::PushDiagStatePoint(DiagState
*State
,
339 SourceLocation Loc
) {
340 assert(Loc
.isValid() && "Adding invalid loc point");
341 DiagStatesByLoc
.append(*SourceMgr
, Loc
, State
);
344 void DiagnosticsEngine::setSeverity(diag::kind Diag
, diag::Severity Map
,
346 assert(Diag
< diag::DIAG_UPPER_LIMIT
&&
347 "Can only map builtin diagnostics");
348 assert((Diags
->isBuiltinWarningOrExtension(Diag
) ||
349 (Map
== diag::Severity::Fatal
|| Map
== diag::Severity::Error
)) &&
350 "Cannot map errors into warnings!");
351 assert((L
.isInvalid() || SourceMgr
) && "No SourceMgr for valid location");
353 // A command line -Wfoo has an invalid L and cannot override error/fatal
354 // mapping, while a warning pragma can.
355 bool WasUpgradedFromWarning
= false;
356 if (Map
== diag::Severity::Warning
&& L
.isInvalid()) {
357 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
358 if (Info
.getSeverity() == diag::Severity::Error
||
359 Info
.getSeverity() == diag::Severity::Fatal
) {
360 Map
= Info
.getSeverity();
361 WasUpgradedFromWarning
= true;
364 DiagnosticMapping Mapping
= makeUserMapping(Map
, L
);
365 Mapping
.setUpgradedFromWarning(WasUpgradedFromWarning
);
367 // Make sure we propagate the NoWarningAsError flag from an existing
368 // mapping (which may be the default mapping).
369 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
370 Mapping
.setNoWarningAsError(Info
.hasNoWarningAsError() ||
371 Mapping
.hasNoWarningAsError());
373 // Common case; setting all the diagnostics of a group in one place.
374 if ((L
.isInvalid() || L
== DiagStatesByLoc
.getCurDiagStateLoc()) &&
375 DiagStatesByLoc
.getCurDiagState()) {
376 // FIXME: This is theoretically wrong: if the current state is shared with
377 // some other location (via push/pop) we will change the state for that
378 // other location as well. This cannot currently happen, as we can't update
379 // the diagnostic state at the same location at which we pop.
380 DiagStatesByLoc
.getCurDiagState()->setMapping(Diag
, Mapping
);
384 // A diagnostic pragma occurred, create a new DiagState initialized with
385 // the current one and a new DiagStatePoint to record at which location
386 // the new state became active.
387 DiagStates
.push_back(*GetCurDiagState());
388 DiagStates
.back().setMapping(Diag
, Mapping
);
389 PushDiagStatePoint(&DiagStates
.back(), L
);
392 bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor
,
393 StringRef Group
, diag::Severity Map
,
394 SourceLocation Loc
) {
395 // Get the diagnostics in this group.
396 SmallVector
<diag::kind
, 256> GroupDiags
;
397 if (Diags
->getDiagnosticsInGroup(Flavor
, Group
, GroupDiags
))
401 for (diag::kind Diag
: GroupDiags
)
402 setSeverity(Diag
, Map
, Loc
);
407 bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor
,
410 SourceLocation Loc
) {
411 return setSeverityForGroup(Flavor
, Diags
->getWarningOptionForGroup(Group
),
415 bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group
,
417 // If we are enabling this feature, just set the diagnostic mappings to map to
420 return setSeverityForGroup(diag::Flavor::WarningOrError
, Group
,
421 diag::Severity::Error
);
423 // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
424 // potentially downgrade anything already mapped to be a warning.
426 // Get the diagnostics in this group.
427 SmallVector
<diag::kind
, 8> GroupDiags
;
428 if (Diags
->getDiagnosticsInGroup(diag::Flavor::WarningOrError
, Group
,
432 // Perform the mapping change.
433 for (diag::kind Diag
: GroupDiags
) {
434 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
436 if (Info
.getSeverity() == diag::Severity::Error
||
437 Info
.getSeverity() == diag::Severity::Fatal
)
438 Info
.setSeverity(diag::Severity::Warning
);
440 Info
.setNoWarningAsError(true);
446 bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group
,
448 // If we are enabling this feature, just set the diagnostic mappings to map to
451 return setSeverityForGroup(diag::Flavor::WarningOrError
, Group
,
452 diag::Severity::Fatal
);
454 // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
455 // and potentially downgrade anything already mapped to be a fatal error.
457 // Get the diagnostics in this group.
458 SmallVector
<diag::kind
, 8> GroupDiags
;
459 if (Diags
->getDiagnosticsInGroup(diag::Flavor::WarningOrError
, Group
,
463 // Perform the mapping change.
464 for (diag::kind Diag
: GroupDiags
) {
465 DiagnosticMapping
&Info
= GetCurDiagState()->getOrAddMapping(Diag
);
467 if (Info
.getSeverity() == diag::Severity::Fatal
)
468 Info
.setSeverity(diag::Severity::Error
);
470 Info
.setNoErrorAsFatal(true);
476 void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor
,
478 SourceLocation Loc
) {
479 // Get all the diagnostics.
480 std::vector
<diag::kind
> AllDiags
;
481 DiagnosticIDs::getAllDiagnostics(Flavor
, AllDiags
);
484 for (diag::kind Diag
: AllDiags
)
485 if (Diags
->isBuiltinWarningOrExtension(Diag
))
486 setSeverity(Diag
, Map
, Loc
);
490 // FIXME: We should isolate the parser from SpecialCaseList and just use it
492 class WarningsSpecialCaseList
: public llvm::SpecialCaseList
{
494 static std::unique_ptr
<WarningsSpecialCaseList
>
495 create(const llvm::MemoryBuffer
&Input
, std::string
&Err
);
497 // Section names refer to diagnostic groups, which cover multiple individual
498 // diagnostics. Expand diagnostic groups here to individual diagnostics.
499 // A diagnostic can have multiple diagnostic groups associated with it, we let
500 // the last section take precedence in such cases.
501 void processSections(DiagnosticsEngine
&Diags
);
503 bool isDiagSuppressed(diag::kind DiagId
, StringRef FilePath
) const;
506 // Find the longest glob pattern that matches FilePath amongst
507 // CategoriesToMatchers, return true iff the match exists and belongs to a
508 // positive category.
509 bool globsMatches(const llvm::StringMap
<Matcher
> &CategoriesToMatchers
,
510 StringRef FilePath
) const;
512 llvm::DenseMap
<diag::kind
, const Section
*> DiagToSection
;
516 std::unique_ptr
<WarningsSpecialCaseList
>
517 WarningsSpecialCaseList::create(const llvm::MemoryBuffer
&Input
,
519 auto WarningSuppressionList
= std::make_unique
<WarningsSpecialCaseList
>();
520 if (!WarningSuppressionList
->createInternal(&Input
, Err
))
522 return WarningSuppressionList
;
525 void WarningsSpecialCaseList::processSections(DiagnosticsEngine
&Diags
) {
526 // Drop the default section introduced by special case list, we only support
527 // exact diagnostic group names.
528 // FIXME: We should make this configurable in the parser instead.
530 // Make sure we iterate sections by their line numbers.
531 std::vector
<std::pair
<unsigned, const llvm::StringMapEntry
<Section
> *>>
533 LineAndSectionEntry
.reserve(Sections
.size());
534 for (const auto &Entry
: Sections
) {
535 StringRef DiagName
= Entry
.getKey();
536 // Each section has a matcher with that section's name, attached to that
538 const auto &DiagSectionMatcher
= Entry
.getValue().SectionMatcher
;
539 unsigned DiagLine
= DiagSectionMatcher
->Globs
.at(DiagName
).second
;
540 LineAndSectionEntry
.emplace_back(DiagLine
, &Entry
);
542 llvm::sort(LineAndSectionEntry
);
543 static constexpr auto WarningFlavor
= clang::diag::Flavor::WarningOrError
;
544 for (const auto &[_
, SectionEntry
] : LineAndSectionEntry
) {
545 SmallVector
<diag::kind
> GroupDiags
;
546 StringRef DiagGroup
= SectionEntry
->getKey();
547 if (Diags
.getDiagnosticIDs()->getDiagnosticsInGroup(
548 WarningFlavor
, DiagGroup
, GroupDiags
)) {
549 StringRef Suggestion
=
550 DiagnosticIDs::getNearestOption(WarningFlavor
, DiagGroup
);
551 Diags
.Report(diag::warn_unknown_diag_option
)
552 << static_cast<unsigned>(WarningFlavor
) << DiagGroup
553 << !Suggestion
.empty() << Suggestion
;
556 for (diag::kind Diag
: GroupDiags
)
557 // We're intentionally overwriting any previous mappings here to make sure
558 // latest one takes precedence.
559 DiagToSection
[Diag
] = &SectionEntry
->getValue();
563 void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer
&Input
) {
565 auto WarningSuppressionList
= WarningsSpecialCaseList::create(Input
, Error
);
566 if (!WarningSuppressionList
) {
567 // FIXME: Use a `%select` statement instead of printing `Error` as-is. This
568 // should help localization.
569 Report(diag::err_drv_malformed_warning_suppression_mapping
)
570 << Input
.getBufferIdentifier() << Error
;
573 WarningSuppressionList
->processSections(*this);
574 DiagSuppressionMapping
=
575 [WarningSuppressionList(std::move(WarningSuppressionList
))](
576 diag::kind DiagId
, StringRef Path
) {
577 return WarningSuppressionList
->isDiagSuppressed(DiagId
, Path
);
581 bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId
,
582 StringRef FilePath
) const {
583 const Section
*DiagSection
= DiagToSection
.lookup(DiagId
);
586 const SectionEntries
&EntityTypeToCategories
= DiagSection
->Entries
;
587 auto SrcEntriesIt
= EntityTypeToCategories
.find("src");
588 if (SrcEntriesIt
== EntityTypeToCategories
.end())
590 const llvm::StringMap
<llvm::SpecialCaseList::Matcher
> &CategoriesToMatchers
=
591 SrcEntriesIt
->getValue();
592 return globsMatches(CategoriesToMatchers
, FilePath
);
595 bool WarningsSpecialCaseList::globsMatches(
596 const llvm::StringMap
<Matcher
> &CategoriesToMatchers
,
597 StringRef FilePath
) const {
598 StringRef LongestMatch
;
599 bool LongestIsPositive
= false;
600 for (const auto &Entry
: CategoriesToMatchers
) {
601 StringRef Category
= Entry
.getKey();
602 const llvm::SpecialCaseList::Matcher
&Matcher
= Entry
.getValue();
603 bool IsPositive
= Category
!= "emit";
604 for (const auto &[Pattern
, Glob
] : Matcher
.Globs
) {
605 if (Pattern
.size() < LongestMatch
.size())
607 if (!Glob
.first
.match(FilePath
))
609 LongestMatch
= Pattern
;
610 LongestIsPositive
= IsPositive
;
613 return LongestIsPositive
;
616 bool DiagnosticsEngine::isSuppressedViaMapping(diag::kind DiagId
,
617 StringRef FilePath
) const {
618 return DiagSuppressionMapping
&& DiagSuppressionMapping(DiagId
, FilePath
);
621 void DiagnosticsEngine::Report(const StoredDiagnostic
&storedDiag
) {
622 DiagnosticStorage DiagStorage
;
623 DiagStorage
.DiagRanges
.append(storedDiag
.range_begin(),
624 storedDiag
.range_end());
626 DiagStorage
.FixItHints
.append(storedDiag
.fixit_begin(),
627 storedDiag
.fixit_end());
629 assert(Client
&& "DiagnosticConsumer not set!");
630 Level DiagLevel
= storedDiag
.getLevel();
631 Diagnostic
Info(this, storedDiag
.getLocation(), storedDiag
.getID(),
632 DiagStorage
, storedDiag
.getMessage());
633 Client
->HandleDiagnostic(DiagLevel
, Info
);
634 if (Client
->IncludeInDiagnosticCounts()) {
635 if (DiagLevel
== DiagnosticsEngine::Warning
)
640 bool DiagnosticsEngine::EmitDiagnostic(const DiagnosticBuilder
&DB
,
642 assert(getClient() && "DiagnosticClient not set!");
646 Diagnostic
Info(this, DB
);
648 // Figure out the diagnostic level of this message.
649 DiagnosticIDs::Level DiagLevel
650 = Diags
->getDiagnosticLevel(Info
.getID(), Info
.getLocation(), *this);
652 Emitted
= (DiagLevel
!= DiagnosticIDs::Ignored
);
654 // Emit the diagnostic regardless of suppression level.
655 Diags
->EmitDiag(*this, DB
, DiagLevel
);
658 // Process the diagnostic, sending the accumulated information to the
659 // DiagnosticConsumer.
660 Emitted
= ProcessDiag(DB
);
666 DiagnosticBuilder::DiagnosticBuilder(DiagnosticsEngine
*DiagObj
,
667 SourceLocation DiagLoc
, unsigned DiagID
)
668 : StreamingDiagnostic(DiagObj
->DiagAllocator
), DiagObj(DiagObj
),
669 DiagLoc(DiagLoc
), DiagID(DiagID
), IsActive(true) {
670 assert(DiagObj
&& "DiagnosticBuilder requires a valid DiagnosticsEngine!");
673 DiagnosticBuilder::DiagnosticBuilder(const DiagnosticBuilder
&D
)
674 : StreamingDiagnostic() {
677 FlagValue
= D
.FlagValue
;
679 DiagStorage
= D
.DiagStorage
;
680 D
.DiagStorage
= nullptr;
681 Allocator
= D
.Allocator
;
682 IsActive
= D
.IsActive
;
683 IsForceEmit
= D
.IsForceEmit
;
687 Diagnostic::Diagnostic(const DiagnosticsEngine
*DO
,
688 const DiagnosticBuilder
&DiagBuilder
)
689 : DiagObj(DO
), DiagLoc(DiagBuilder
.DiagLoc
), DiagID(DiagBuilder
.DiagID
),
690 FlagValue(DiagBuilder
.FlagValue
), DiagStorage(*DiagBuilder
.getStorage()) {
693 Diagnostic::Diagnostic(const DiagnosticsEngine
*DO
, SourceLocation DiagLoc
,
694 unsigned DiagID
, const DiagnosticStorage
&DiagStorage
,
695 StringRef StoredDiagMessage
)
696 : DiagObj(DO
), DiagLoc(DiagLoc
), DiagID(DiagID
), DiagStorage(DiagStorage
),
697 StoredDiagMessage(StoredDiagMessage
) {}
699 DiagnosticConsumer::~DiagnosticConsumer() = default;
701 void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel
,
702 const Diagnostic
&Info
) {
703 if (!IncludeInDiagnosticCounts())
706 if (DiagLevel
== DiagnosticsEngine::Warning
)
708 else if (DiagLevel
>= DiagnosticsEngine::Error
)
712 /// ModifierIs - Return true if the specified modifier matches specified string.
713 template <std::size_t StrLen
>
714 static bool ModifierIs(const char *Modifier
, unsigned ModifierLen
,
715 const char (&Str
)[StrLen
]) {
716 return StrLen
-1 == ModifierLen
&& memcmp(Modifier
, Str
, StrLen
-1) == 0;
719 /// ScanForward - Scans forward, looking for the given character, skipping
720 /// nested clauses and escaped characters.
721 static const char *ScanFormat(const char *I
, const char *E
, char Target
) {
724 for ( ; I
!= E
; ++I
) {
725 if (Depth
== 0 && *I
== Target
) return I
;
726 if (Depth
!= 0 && *I
== '}') Depth
--;
732 // Escaped characters get implicitly skipped here.
735 if (!isDigit(*I
) && !isPunctuation(*I
)) {
736 for (I
++; I
!= E
&& !isDigit(*I
) && *I
!= '{'; I
++) ;
746 /// HandleSelectModifier - Handle the integer 'select' modifier. This is used
747 /// like this: %select{foo|bar|baz}2. This means that the integer argument
748 /// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
749 /// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
750 /// This is very useful for certain classes of variant diagnostics.
751 static void HandleSelectModifier(const Diagnostic
&DInfo
, unsigned ValNo
,
752 const char *Argument
, unsigned ArgumentLen
,
753 SmallVectorImpl
<char> &OutStr
) {
754 const char *ArgumentEnd
= Argument
+ArgumentLen
;
756 // Skip over 'ValNo' |'s.
758 const char *NextVal
= ScanFormat(Argument
, ArgumentEnd
, '|');
759 assert(NextVal
!= ArgumentEnd
&& "Value for integer select modifier was"
760 " larger than the number of options in the diagnostic string!");
761 Argument
= NextVal
+1; // Skip this string.
765 // Get the end of the value. This is either the } or the |.
766 const char *EndPtr
= ScanFormat(Argument
, ArgumentEnd
, '|');
768 // Recursively format the result of the select clause into the output string.
769 DInfo
.FormatDiagnostic(Argument
, EndPtr
, OutStr
);
772 /// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
773 /// letter 's' to the string if the value is not 1. This is used in cases like
774 /// this: "you idiot, you have %4 parameter%s4!".
775 static void HandleIntegerSModifier(unsigned ValNo
,
776 SmallVectorImpl
<char> &OutStr
) {
778 OutStr
.push_back('s');
781 /// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
782 /// prints the ordinal form of the given integer, with 1 corresponding
783 /// to the first ordinal. Currently this is hard-coded to use the
785 static void HandleOrdinalModifier(unsigned ValNo
,
786 SmallVectorImpl
<char> &OutStr
) {
787 assert(ValNo
!= 0 && "ValNo must be strictly positive!");
789 llvm::raw_svector_ostream
Out(OutStr
);
791 // We could use text forms for the first N ordinals, but the numeric
792 // forms are actually nicer in diagnostics because they stand out.
793 Out
<< ValNo
<< llvm::getOrdinalSuffix(ValNo
);
798 // 123456 -> "123.46k".
799 // 1234567 -> "1.23M".
800 // 1234567890 -> "1.23G".
801 // 1234567890123 -> "1.23T".
802 static void HandleIntegerHumanModifier(int64_t ValNo
,
803 SmallVectorImpl
<char> &OutStr
) {
804 static constexpr std::array
<std::pair
<int64_t, char>, 4> Units
= {
805 {{1'000'000'000'000L, 'T'},
806 {1'000'000'000L, 'G'},
810 llvm::raw_svector_ostream
Out(OutStr
);
815 for (const auto &[UnitSize
, UnitSign
] : Units
) {
816 if (ValNo
>= UnitSize
) {
817 Out
<< llvm::format("%0.2f%c", ValNo
/ static_cast<double>(UnitSize
),
825 /// PluralNumber - Parse an unsigned integer and advance Start.
826 static unsigned PluralNumber(const char *&Start
, const char *End
) {
827 // Programming 101: Parse a decimal number :-)
829 while (Start
!= End
&& *Start
>= '0' && *Start
<= '9') {
837 /// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
838 static bool TestPluralRange(unsigned Val
, const char *&Start
, const char *End
) {
840 unsigned Ref
= PluralNumber(Start
, End
);
845 unsigned Low
= PluralNumber(Start
, End
);
846 assert(*Start
== ',' && "Bad plural expression syntax: expected ,");
848 unsigned High
= PluralNumber(Start
, End
);
849 assert(*Start
== ']' && "Bad plural expression syntax: expected )");
851 return Low
<= Val
&& Val
<= High
;
854 /// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
855 static bool EvalPluralExpr(unsigned ValNo
, const char *Start
, const char *End
) {
865 unsigned Arg
= PluralNumber(Start
, End
);
866 assert(*Start
== '=' && "Bad plural expression syntax: expected =");
868 unsigned ValMod
= ValNo
% Arg
;
869 if (TestPluralRange(ValMod
, Start
, End
))
872 assert((C
== '[' || (C
>= '0' && C
<= '9')) &&
873 "Bad plural expression syntax: unexpected character");
875 if (TestPluralRange(ValNo
, Start
, End
))
879 // Scan for next or-expr part.
880 Start
= std::find(Start
, End
, ',');
888 /// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
889 /// for complex plural forms, or in languages where all plurals are complex.
890 /// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
891 /// conditions that are tested in order, the form corresponding to the first
892 /// that applies being emitted. The empty condition is always true, making the
893 /// last form a default case.
894 /// Conditions are simple boolean expressions, where n is the number argument.
895 /// Here are the rules.
896 /// condition := expression | empty
897 /// empty := -> always true
898 /// expression := numeric [',' expression] -> logical or
899 /// numeric := range -> true if n in range
900 /// | '%' number '=' range -> true if n % number in range
902 /// | '[' number ',' number ']' -> ranges are inclusive both ends
904 /// Here are some examples from the GNU gettext manual written in this form:
908 /// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
910 /// {1:form0|2:form1|:form2}
912 /// {1:form0|0,%100=[1,19]:form1|:form2}
914 /// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
915 /// Russian (requires repeated form):
916 /// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
918 /// {1:form0|[2,4]:form1|:form2}
919 /// Polish (requires repeated form):
920 /// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
921 static void HandlePluralModifier(const Diagnostic
&DInfo
, unsigned ValNo
,
922 const char *Argument
, unsigned ArgumentLen
,
923 SmallVectorImpl
<char> &OutStr
) {
924 const char *ArgumentEnd
= Argument
+ ArgumentLen
;
926 assert(Argument
< ArgumentEnd
&& "Plural expression didn't match.");
927 const char *ExprEnd
= Argument
;
928 while (*ExprEnd
!= ':') {
929 assert(ExprEnd
!= ArgumentEnd
&& "Plural missing expression end");
932 if (EvalPluralExpr(ValNo
, Argument
, ExprEnd
)) {
933 Argument
= ExprEnd
+ 1;
934 ExprEnd
= ScanFormat(Argument
, ArgumentEnd
, '|');
936 // Recursively format the result of the plural clause into the
938 DInfo
.FormatDiagnostic(Argument
, ExprEnd
, OutStr
);
941 Argument
= ScanFormat(Argument
, ArgumentEnd
- 1, '|') + 1;
945 /// Returns the friendly description for a token kind that will appear
946 /// without quotes in diagnostic messages. These strings may be translatable in
948 static const char *getTokenDescForDiagnostic(tok::TokenKind Kind
) {
950 case tok::identifier
:
957 /// FormatDiagnostic - Format this diagnostic into a string, substituting the
958 /// formal arguments into the %0 slots. The result is appended onto the Str
961 FormatDiagnostic(SmallVectorImpl
<char> &OutStr
) const {
962 if (StoredDiagMessage
.has_value()) {
963 OutStr
.append(StoredDiagMessage
->begin(), StoredDiagMessage
->end());
968 getDiags()->getDiagnosticIDs()->getDescription(getID());
970 FormatDiagnostic(Diag
.begin(), Diag
.end(), OutStr
);
973 /// EscapeStringForDiagnostic - Append Str to the diagnostic buffer,
974 /// escaping non-printable characters and ill-formed code unit sequences.
975 void clang::EscapeStringForDiagnostic(StringRef Str
,
976 SmallVectorImpl
<char> &OutStr
) {
977 OutStr
.reserve(OutStr
.size() + Str
.size());
978 auto *Begin
= reinterpret_cast<const unsigned char *>(Str
.data());
979 llvm::raw_svector_ostream
OutStream(OutStr
);
980 const unsigned char *End
= Begin
+ Str
.size();
981 while (Begin
!= End
) {
983 if (isPrintable(*Begin
) || isWhitespace(*Begin
)) {
988 if (llvm::isLegalUTF8Sequence(Begin
, End
)) {
989 llvm::UTF32 CodepointValue
;
990 llvm::UTF32
*CpPtr
= &CodepointValue
;
991 const unsigned char *CodepointBegin
= Begin
;
992 const unsigned char *CodepointEnd
=
993 Begin
+ llvm::getNumBytesForUTF8(*Begin
);
994 llvm::ConversionResult Res
= llvm::ConvertUTF8toUTF32(
995 &Begin
, CodepointEnd
, &CpPtr
, CpPtr
+ 1, llvm::strictConversion
);
998 llvm::conversionOK
== Res
&&
999 "the sequence is legal UTF-8 but we couldn't convert it to UTF-32");
1000 assert(Begin
== CodepointEnd
&&
1001 "we must be further along in the string now");
1002 if (llvm::sys::unicode::isPrintable(CodepointValue
) ||
1003 llvm::sys::unicode::isFormatting(CodepointValue
)) {
1004 OutStr
.append(CodepointBegin
, CodepointEnd
);
1007 // Unprintable code point.
1008 OutStream
<< "<U+" << llvm::format_hex_no_prefix(CodepointValue
, 4, true)
1012 // Invalid code unit.
1013 OutStream
<< "<" << llvm::format_hex_no_prefix(*Begin
, 2, true) << ">";
1019 FormatDiagnostic(const char *DiagStr
, const char *DiagEnd
,
1020 SmallVectorImpl
<char> &OutStr
) const {
1021 // When the diagnostic string is only "%0", the entire string is being given
1022 // by an outside source. Remove unprintable characters from this string
1023 // and skip all the other string processing.
1024 if (DiagEnd
- DiagStr
== 2 && StringRef(DiagStr
, DiagEnd
- DiagStr
) == "%0" &&
1025 getArgKind(0) == DiagnosticsEngine::ak_std_string
) {
1026 const std::string
&S
= getArgStdStr(0);
1027 EscapeStringForDiagnostic(S
, OutStr
);
1031 /// FormattedArgs - Keep track of all of the arguments formatted by
1032 /// ConvertArgToString and pass them into subsequent calls to
1033 /// ConvertArgToString, allowing the implementation to avoid redundancies in
1035 SmallVector
<DiagnosticsEngine::ArgumentValue
, 8> FormattedArgs
;
1037 /// QualTypeVals - Pass a vector of arrays so that QualType names can be
1038 /// compared to see if more information is needed to be printed.
1039 SmallVector
<intptr_t, 2> QualTypeVals
;
1040 SmallString
<64> Tree
;
1042 for (unsigned i
= 0, e
= getNumArgs(); i
< e
; ++i
)
1043 if (getArgKind(i
) == DiagnosticsEngine::ak_qualtype
)
1044 QualTypeVals
.push_back(getRawArg(i
));
1046 while (DiagStr
!= DiagEnd
) {
1047 if (DiagStr
[0] != '%') {
1048 // Append non-%0 substrings to Str if we have one.
1049 const char *StrEnd
= std::find(DiagStr
, DiagEnd
, '%');
1050 OutStr
.append(DiagStr
, StrEnd
);
1053 } else if (isPunctuation(DiagStr
[1])) {
1054 OutStr
.push_back(DiagStr
[1]); // %% -> %.
1062 // This must be a placeholder for a diagnostic argument. The format for a
1063 // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
1064 // The digit is a number from 0-9 indicating which argument this comes from.
1065 // The modifier is a string of digits from the set [-a-z]+, arguments is a
1066 // brace enclosed string.
1067 const char *Modifier
= nullptr, *Argument
= nullptr;
1068 unsigned ModifierLen
= 0, ArgumentLen
= 0;
1070 // Check to see if we have a modifier. If so eat it.
1071 if (!isDigit(DiagStr
[0])) {
1073 while (DiagStr
[0] == '-' ||
1074 (DiagStr
[0] >= 'a' && DiagStr
[0] <= 'z'))
1076 ModifierLen
= DiagStr
-Modifier
;
1078 // If we have an argument, get it next.
1079 if (DiagStr
[0] == '{') {
1080 ++DiagStr
; // Skip {.
1083 DiagStr
= ScanFormat(DiagStr
, DiagEnd
, '}');
1084 assert(DiagStr
!= DiagEnd
&& "Mismatched {}'s in diagnostic string!");
1085 ArgumentLen
= DiagStr
-Argument
;
1086 ++DiagStr
; // Skip }.
1090 assert(isDigit(*DiagStr
) && "Invalid format for argument in diagnostic");
1091 unsigned ArgNo
= *DiagStr
++ - '0';
1093 // Only used for type diffing.
1094 unsigned ArgNo2
= ArgNo
;
1096 DiagnosticsEngine::ArgumentKind Kind
= getArgKind(ArgNo
);
1097 if (ModifierIs(Modifier
, ModifierLen
, "diff")) {
1098 assert(*DiagStr
== ',' && isDigit(*(DiagStr
+ 1)) &&
1099 "Invalid format for diff modifier");
1100 ++DiagStr
; // Comma.
1101 ArgNo2
= *DiagStr
++ - '0';
1102 DiagnosticsEngine::ArgumentKind Kind2
= getArgKind(ArgNo2
);
1103 if (Kind
== DiagnosticsEngine::ak_qualtype
&&
1104 Kind2
== DiagnosticsEngine::ak_qualtype
)
1105 Kind
= DiagnosticsEngine::ak_qualtype_pair
;
1107 // %diff only supports QualTypes. For other kinds of arguments,
1108 // use the default printing. For example, if the modifier is:
1109 // "%diff{compare $ to $|other text}1,2"
1111 // "compare %1 to %2"
1112 const char *ArgumentEnd
= Argument
+ ArgumentLen
;
1113 const char *Pipe
= ScanFormat(Argument
, ArgumentEnd
, '|');
1114 assert(ScanFormat(Pipe
+ 1, ArgumentEnd
, '|') == ArgumentEnd
&&
1115 "Found too many '|'s in a %diff modifier!");
1116 const char *FirstDollar
= ScanFormat(Argument
, Pipe
, '$');
1117 const char *SecondDollar
= ScanFormat(FirstDollar
+ 1, Pipe
, '$');
1118 const char ArgStr1
[] = { '%', static_cast<char>('0' + ArgNo
) };
1119 const char ArgStr2
[] = { '%', static_cast<char>('0' + ArgNo2
) };
1120 FormatDiagnostic(Argument
, FirstDollar
, OutStr
);
1121 FormatDiagnostic(ArgStr1
, ArgStr1
+ 2, OutStr
);
1122 FormatDiagnostic(FirstDollar
+ 1, SecondDollar
, OutStr
);
1123 FormatDiagnostic(ArgStr2
, ArgStr2
+ 2, OutStr
);
1124 FormatDiagnostic(SecondDollar
+ 1, Pipe
, OutStr
);
1130 // ---- STRINGS ----
1131 case DiagnosticsEngine::ak_std_string
: {
1132 const std::string
&S
= getArgStdStr(ArgNo
);
1133 assert(ModifierLen
== 0 && "No modifiers for strings yet");
1134 EscapeStringForDiagnostic(S
, OutStr
);
1137 case DiagnosticsEngine::ak_c_string
: {
1138 const char *S
= getArgCStr(ArgNo
);
1139 assert(ModifierLen
== 0 && "No modifiers for strings yet");
1141 // Don't crash if get passed a null pointer by accident.
1144 EscapeStringForDiagnostic(S
, OutStr
);
1147 // ---- INTEGERS ----
1148 case DiagnosticsEngine::ak_sint
: {
1149 int64_t Val
= getArgSInt(ArgNo
);
1151 if (ModifierIs(Modifier
, ModifierLen
, "select")) {
1152 HandleSelectModifier(*this, (unsigned)Val
, Argument
, ArgumentLen
,
1154 } else if (ModifierIs(Modifier
, ModifierLen
, "s")) {
1155 HandleIntegerSModifier(Val
, OutStr
);
1156 } else if (ModifierIs(Modifier
, ModifierLen
, "plural")) {
1157 HandlePluralModifier(*this, (unsigned)Val
, Argument
, ArgumentLen
,
1159 } else if (ModifierIs(Modifier
, ModifierLen
, "ordinal")) {
1160 HandleOrdinalModifier((unsigned)Val
, OutStr
);
1161 } else if (ModifierIs(Modifier
, ModifierLen
, "human")) {
1162 HandleIntegerHumanModifier(Val
, OutStr
);
1164 assert(ModifierLen
== 0 && "Unknown integer modifier");
1165 llvm::raw_svector_ostream(OutStr
) << Val
;
1169 case DiagnosticsEngine::ak_uint
: {
1170 uint64_t Val
= getArgUInt(ArgNo
);
1172 if (ModifierIs(Modifier
, ModifierLen
, "select")) {
1173 HandleSelectModifier(*this, Val
, Argument
, ArgumentLen
, OutStr
);
1174 } else if (ModifierIs(Modifier
, ModifierLen
, "s")) {
1175 HandleIntegerSModifier(Val
, OutStr
);
1176 } else if (ModifierIs(Modifier
, ModifierLen
, "plural")) {
1177 HandlePluralModifier(*this, (unsigned)Val
, Argument
, ArgumentLen
,
1179 } else if (ModifierIs(Modifier
, ModifierLen
, "ordinal")) {
1180 HandleOrdinalModifier(Val
, OutStr
);
1181 } else if (ModifierIs(Modifier
, ModifierLen
, "human")) {
1182 HandleIntegerHumanModifier(Val
, OutStr
);
1184 assert(ModifierLen
== 0 && "Unknown integer modifier");
1185 llvm::raw_svector_ostream(OutStr
) << Val
;
1189 // ---- TOKEN SPELLINGS ----
1190 case DiagnosticsEngine::ak_tokenkind
: {
1191 tok::TokenKind Kind
= static_cast<tok::TokenKind
>(getRawArg(ArgNo
));
1192 assert(ModifierLen
== 0 && "No modifiers for token kinds yet");
1194 llvm::raw_svector_ostream
Out(OutStr
);
1195 if (const char *S
= tok::getPunctuatorSpelling(Kind
))
1196 // Quoted token spelling for punctuators.
1197 Out
<< '\'' << S
<< '\'';
1198 else if ((S
= tok::getKeywordSpelling(Kind
)))
1199 // Unquoted token spelling for keywords.
1201 else if ((S
= getTokenDescForDiagnostic(Kind
)))
1202 // Unquoted translatable token name.
1204 else if ((S
= tok::getTokenName(Kind
)))
1205 // Debug name, shouldn't appear in user-facing diagnostics.
1206 Out
<< '<' << S
<< '>';
1211 // ---- NAMES and TYPES ----
1212 case DiagnosticsEngine::ak_identifierinfo
: {
1213 const IdentifierInfo
*II
= getArgIdentifier(ArgNo
);
1214 assert(ModifierLen
== 0 && "No modifiers for strings yet");
1216 // Don't crash if get passed a null pointer by accident.
1218 const char *S
= "(null)";
1219 OutStr
.append(S
, S
+ strlen(S
));
1223 llvm::raw_svector_ostream(OutStr
) << '\'' << II
->getName() << '\'';
1226 case DiagnosticsEngine::ak_addrspace
:
1227 case DiagnosticsEngine::ak_qual
:
1228 case DiagnosticsEngine::ak_qualtype
:
1229 case DiagnosticsEngine::ak_declarationname
:
1230 case DiagnosticsEngine::ak_nameddecl
:
1231 case DiagnosticsEngine::ak_nestednamespec
:
1232 case DiagnosticsEngine::ak_declcontext
:
1233 case DiagnosticsEngine::ak_attr
:
1234 getDiags()->ConvertArgToString(Kind
, getRawArg(ArgNo
),
1235 StringRef(Modifier
, ModifierLen
),
1236 StringRef(Argument
, ArgumentLen
),
1238 OutStr
, QualTypeVals
);
1240 case DiagnosticsEngine::ak_qualtype_pair
: {
1241 // Create a struct with all the info needed for printing.
1242 TemplateDiffTypes TDT
;
1243 TDT
.FromType
= getRawArg(ArgNo
);
1244 TDT
.ToType
= getRawArg(ArgNo2
);
1245 TDT
.ElideType
= getDiags()->ElideType
;
1246 TDT
.ShowColors
= getDiags()->ShowColors
;
1247 TDT
.TemplateDiffUsed
= false;
1248 intptr_t val
= reinterpret_cast<intptr_t>(&TDT
);
1250 const char *ArgumentEnd
= Argument
+ ArgumentLen
;
1251 const char *Pipe
= ScanFormat(Argument
, ArgumentEnd
, '|');
1253 // Print the tree. If this diagnostic already has a tree, skip the
1255 if (getDiags()->PrintTemplateTree
&& Tree
.empty()) {
1256 TDT
.PrintFromType
= true;
1257 TDT
.PrintTree
= true;
1258 getDiags()->ConvertArgToString(Kind
, val
,
1259 StringRef(Modifier
, ModifierLen
),
1260 StringRef(Argument
, ArgumentLen
),
1262 Tree
, QualTypeVals
);
1263 // If there is no tree information, fall back to regular printing.
1264 if (!Tree
.empty()) {
1265 FormatDiagnostic(Pipe
+ 1, ArgumentEnd
, OutStr
);
1270 // Non-tree printing, also the fall-back when tree printing fails.
1271 // The fall-back is triggered when the types compared are not templates.
1272 const char *FirstDollar
= ScanFormat(Argument
, ArgumentEnd
, '$');
1273 const char *SecondDollar
= ScanFormat(FirstDollar
+ 1, ArgumentEnd
, '$');
1275 // Append before text
1276 FormatDiagnostic(Argument
, FirstDollar
, OutStr
);
1278 // Append first type
1279 TDT
.PrintTree
= false;
1280 TDT
.PrintFromType
= true;
1281 getDiags()->ConvertArgToString(Kind
, val
,
1282 StringRef(Modifier
, ModifierLen
),
1283 StringRef(Argument
, ArgumentLen
),
1285 OutStr
, QualTypeVals
);
1286 if (!TDT
.TemplateDiffUsed
)
1287 FormattedArgs
.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype
,
1290 // Append middle text
1291 FormatDiagnostic(FirstDollar
+ 1, SecondDollar
, OutStr
);
1293 // Append second type
1294 TDT
.PrintFromType
= false;
1295 getDiags()->ConvertArgToString(Kind
, val
,
1296 StringRef(Modifier
, ModifierLen
),
1297 StringRef(Argument
, ArgumentLen
),
1299 OutStr
, QualTypeVals
);
1300 if (!TDT
.TemplateDiffUsed
)
1301 FormattedArgs
.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype
,
1305 FormatDiagnostic(SecondDollar
+ 1, Pipe
, OutStr
);
1310 // Remember this argument info for subsequent formatting operations. Turn
1311 // std::strings into a null terminated string to make it be the same case as
1312 // all the other ones.
1313 if (Kind
== DiagnosticsEngine::ak_qualtype_pair
)
1315 else if (Kind
!= DiagnosticsEngine::ak_std_string
)
1316 FormattedArgs
.push_back(std::make_pair(Kind
, getRawArg(ArgNo
)));
1318 FormattedArgs
.push_back(std::make_pair(DiagnosticsEngine::ak_c_string
,
1319 (intptr_t)getArgStdStr(ArgNo
).c_str()));
1322 // Append the type tree to the end of the diagnostics.
1323 OutStr
.append(Tree
.begin(), Tree
.end());
1326 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level
, unsigned ID
,
1328 : ID(ID
), Level(Level
), Message(Message
) {}
1330 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level
,
1331 const Diagnostic
&Info
)
1332 : ID(Info
.getID()), Level(Level
) {
1333 assert((Info
.getLocation().isInvalid() || Info
.hasSourceManager()) &&
1334 "Valid source location without setting a source manager for diagnostic");
1335 if (Info
.getLocation().isValid())
1336 Loc
= FullSourceLoc(Info
.getLocation(), Info
.getSourceManager());
1337 SmallString
<64> Message
;
1338 Info
.FormatDiagnostic(Message
);
1339 this->Message
.assign(Message
.begin(), Message
.end());
1340 this->Ranges
.assign(Info
.getRanges().begin(), Info
.getRanges().end());
1341 this->FixIts
.assign(Info
.getFixItHints().begin(), Info
.getFixItHints().end());
1344 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level
, unsigned ID
,
1345 StringRef Message
, FullSourceLoc Loc
,
1346 ArrayRef
<CharSourceRange
> Ranges
,
1347 ArrayRef
<FixItHint
> FixIts
)
1348 : ID(ID
), Level(Level
), Loc(Loc
), Message(Message
),
1349 Ranges(Ranges
.begin(), Ranges
.end()), FixIts(FixIts
.begin(), FixIts
.end())
1353 llvm::raw_ostream
&clang::operator<<(llvm::raw_ostream
&OS
,
1354 const StoredDiagnostic
&SD
) {
1355 if (SD
.getLocation().hasManager())
1356 OS
<< SD
.getLocation().printToString(SD
.getLocation().getManager()) << ": ";
1357 OS
<< SD
.getMessage();
1361 /// IncludeInDiagnosticCounts - This method (whose default implementation
1362 /// returns true) indicates whether the diagnostics handled by this
1363 /// DiagnosticConsumer should be included in the number of diagnostics
1364 /// reported by DiagnosticsEngine.
1365 bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; }
1367 void IgnoringDiagConsumer::anchor() {}
1369 ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() = default;
1371 void ForwardingDiagnosticConsumer::HandleDiagnostic(
1372 DiagnosticsEngine::Level DiagLevel
,
1373 const Diagnostic
&Info
) {
1374 Target
.HandleDiagnostic(DiagLevel
, Info
);
1377 void ForwardingDiagnosticConsumer::clear() {
1378 DiagnosticConsumer::clear();
1382 bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const {
1383 return Target
.IncludeInDiagnosticCounts();
1386 DiagStorageAllocator::DiagStorageAllocator() {
1387 for (unsigned I
= 0; I
!= NumCached
; ++I
)
1388 FreeList
[I
] = Cached
+ I
;
1389 NumFreeListEntries
= NumCached
;
1392 DiagStorageAllocator::~DiagStorageAllocator() {
1393 // Don't assert if we are in a CrashRecovery context, as this invariant may
1394 // be invalidated during a crash.
1395 assert((NumFreeListEntries
== NumCached
||
1396 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1397 "A partial is on the lam");
1400 char DiagnosticError::ID
;