clang 22.0.0git
Diagnostic.cpp
Go to the documentation of this file.
1//===- Diagnostic.cpp - C Language Family Diagnostic Handling -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the Diagnostic-related interfaces.
10//
11//===----------------------------------------------------------------------===//
12
25#include "llvm/ADT/IntrusiveRefCntPtr.h"
26#include "llvm/ADT/SmallVector.h"
27#include "llvm/ADT/StringExtras.h"
28#include "llvm/ADT/StringMap.h"
29#include "llvm/ADT/StringRef.h"
30#include "llvm/Support/ConvertUTF.h"
31#include "llvm/Support/CrashRecoveryContext.h"
32#include "llvm/Support/Error.h"
33#include "llvm/Support/MemoryBuffer.h"
34#include "llvm/Support/SpecialCaseList.h"
35#include "llvm/Support/Unicode.h"
36#include "llvm/Support/VirtualFileSystem.h"
37#include "llvm/Support/raw_ostream.h"
38#include <algorithm>
39#include <cassert>
40#include <cstddef>
41#include <cstdint>
42#include <cstring>
43#include <memory>
44#include <string>
45#include <utility>
46#include <vector>
47
48using namespace clang;
49
51 DiagNullabilityKind nullability) {
52 DB.AddString(
53 ("'" +
54 getNullabilitySpelling(nullability.first,
55 /*isContextSensitive=*/nullability.second) +
56 "'")
57 .str());
58 return DB;
59}
60
62 llvm::Error &&E) {
63 DB.AddString(toString(std::move(E)));
64 return DB;
65}
66
67static void
69 StringRef Modifier, StringRef Argument,
71 SmallVectorImpl<char> &Output, void *Cookie,
72 ArrayRef<intptr_t> QualTypeVals) {
73 StringRef Str = "<can't format argument>";
74 Output.append(Str.begin(), Str.end());
75}
76
78 DiagnosticOptions &DiagOpts,
79 DiagnosticConsumer *client,
80 bool ShouldOwnClient)
81 : Diags(std::move(diags)), DiagOpts(DiagOpts) {
82 setClient(client, ShouldOwnClient);
83 ArgToStringFn = DummyArgToStringFn;
84
85 Reset();
86}
87
89 // If we own the diagnostic client, destroy it first so that it can access the
90 // engine from its destructor.
91 setClient(nullptr);
92}
93
94void DiagnosticsEngine::dump() const { DiagStatesByLoc.dump(*SourceMgr); }
95
96void DiagnosticsEngine::dump(StringRef DiagName) const {
97 DiagStatesByLoc.dump(*SourceMgr, DiagName);
98}
99
101 bool ShouldOwnClient) {
102 Owner.reset(ShouldOwnClient ? client : nullptr);
103 Client = client;
104}
105
107 DiagStateOnPushStack.push_back(GetCurDiagState());
108}
109
111 if (DiagStateOnPushStack.empty())
112 return false;
113
114 if (DiagStateOnPushStack.back() != GetCurDiagState()) {
115 // State changed at some point between push/pop.
116 PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
117 }
118 DiagStateOnPushStack.pop_back();
119 return true;
120}
121
122void DiagnosticsEngine::ResetPragmas() { DiagStatesByLoc.clear(/*Soft=*/true); }
123
124void DiagnosticsEngine::Reset(bool soft /*=false*/) {
125 ErrorOccurred = false;
126 UncompilableErrorOccurred = false;
127 FatalErrorOccurred = false;
128 UnrecoverableErrorOccurred = false;
129
130 NumWarnings = 0;
131 NumErrors = 0;
132 TrapNumErrorsOccurred = 0;
133 TrapNumUnrecoverableErrorsOccurred = 0;
134
135 LastDiagLevel = Ignored;
136
137 if (!soft) {
138 // Clear state related to #pragma diagnostic.
139 DiagStates.clear();
140 DiagStatesByLoc.clear(false);
141 DiagStateOnPushStack.clear();
142
143 // Create a DiagState and DiagStatePoint representing diagnostic changes
144 // through command-line.
145 DiagStates.emplace_back(*Diags);
146 DiagStatesByLoc.appendFirst(&DiagStates.back());
147 }
148}
149
151DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) {
152 std::pair<iterator, bool> Result = DiagMap.try_emplace(Diag);
153
154 // Initialize the entry if we added it.
155 if (Result.second) {
156 Result.first->second = DiagIDs.getDefaultMapping(Diag);
158 DiagIDs.initCustomDiagMapping(Result.first->second, Diag);
159 }
160
161 return Result.first->second;
162}
163
164void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState *State) {
165 assert(Files.empty() && "not first");
166 FirstDiagState = CurDiagState = State;
167 CurDiagStateLoc = SourceLocation();
168}
169
170void DiagnosticsEngine::DiagStateMap::append(SourceManager &SrcMgr,
171 SourceLocation Loc,
172 DiagState *State) {
173 CurDiagState = State;
174 CurDiagStateLoc = Loc;
175
176 FileIDAndOffset Decomp = SrcMgr.getDecomposedLoc(Loc);
177 unsigned Offset = Decomp.second;
178 for (File *F = getFile(SrcMgr, Decomp.first); F;
179 Offset = F->ParentOffset, F = F->Parent) {
180 F->HasLocalTransitions = true;
181 auto &Last = F->StateTransitions.back();
182 assert(Last.Offset <= Offset && "state transitions added out of order");
183
184 if (Last.Offset == Offset) {
185 if (Last.State == State)
186 break;
187 Last.State = State;
188 continue;
189 }
190
191 F->StateTransitions.push_back({State, Offset});
192 }
193}
194
195DiagnosticsEngine::DiagState *
196DiagnosticsEngine::DiagStateMap::lookup(SourceManager &SrcMgr,
197 SourceLocation Loc) const {
198 // Common case: we have not seen any diagnostic pragmas.
199 if (Files.empty())
200 return FirstDiagState;
201
202 FileIDAndOffset Decomp = SrcMgr.getDecomposedLoc(Loc);
203 const File *F = getFile(SrcMgr, Decomp.first);
204 return F->lookup(Decomp.second);
205}
206
207DiagnosticsEngine::DiagState *
208DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const {
209 auto OnePastIt =
210 llvm::partition_point(StateTransitions, [=](const DiagStatePoint &P) {
211 return P.Offset <= Offset;
212 });
213 assert(OnePastIt != StateTransitions.begin() && "missing initial state");
214 return OnePastIt[-1].State;
215}
216
217DiagnosticsEngine::DiagStateMap::File *
218DiagnosticsEngine::DiagStateMap::getFile(SourceManager &SrcMgr,
219 FileID ID) const {
220 // Get or insert the File for this ID.
221 auto Range = Files.equal_range(ID);
222 if (Range.first != Range.second)
223 return &Range.first->second;
224 auto &F = Files.insert(Range.first, std::make_pair(ID, File()))->second;
225
226 // We created a new File; look up the diagnostic state at the start of it and
227 // initialize it.
228 if (ID.isValid()) {
229 FileIDAndOffset Decomp = SrcMgr.getDecomposedIncludedLoc(ID);
230 F.Parent = getFile(SrcMgr, Decomp.first);
231 F.ParentOffset = Decomp.second;
232 F.StateTransitions.push_back({F.Parent->lookup(Decomp.second), 0});
233 } else {
234 // This is the (imaginary) root file into which we pretend all top-level
235 // files are included; it descends from the initial state.
236 //
237 // FIXME: This doesn't guarantee that we use the same ordering as
238 // isBeforeInTranslationUnit in the cases where someone invented another
239 // top-level file and added diagnostic pragmas to it. See the code at the
240 // end of isBeforeInTranslationUnit for the quirks it deals with.
241 F.StateTransitions.push_back({FirstDiagState, 0});
242 }
243 return &F;
244}
245
246void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr,
247 StringRef DiagName) const {
248 llvm::errs() << "diagnostic state at ";
249 CurDiagStateLoc.print(llvm::errs(), SrcMgr);
250 llvm::errs() << ": " << CurDiagState << "\n";
251
252 for (auto &F : Files) {
253 FileID ID = F.first;
254 File &File = F.second;
255
256 bool PrintedOuterHeading = false;
257 auto PrintOuterHeading = [&] {
258 if (PrintedOuterHeading)
259 return;
260 PrintedOuterHeading = true;
261
262 llvm::errs() << "File " << &File << " <FileID " << ID.getHashValue()
263 << ">: " << SrcMgr.getBufferOrFake(ID).getBufferIdentifier();
264
265 if (F.second.Parent) {
266 FileIDAndOffset Decomp = SrcMgr.getDecomposedIncludedLoc(ID);
267 assert(File.ParentOffset == Decomp.second);
268 llvm::errs() << " parent " << File.Parent << " <FileID "
269 << Decomp.first.getHashValue() << "> ";
270 SrcMgr.getLocForStartOfFile(Decomp.first)
271 .getLocWithOffset(Decomp.second)
272 .print(llvm::errs(), SrcMgr);
273 }
274 if (File.HasLocalTransitions)
275 llvm::errs() << " has_local_transitions";
276 llvm::errs() << "\n";
277 };
278
279 if (DiagName.empty())
280 PrintOuterHeading();
281
282 for (DiagStatePoint &Transition : File.StateTransitions) {
283 bool PrintedInnerHeading = false;
284 auto PrintInnerHeading = [&] {
285 if (PrintedInnerHeading)
286 return;
287 PrintedInnerHeading = true;
288
289 PrintOuterHeading();
290 llvm::errs() << " ";
291 SrcMgr.getLocForStartOfFile(ID)
292 .getLocWithOffset(Transition.Offset)
293 .print(llvm::errs(), SrcMgr);
294 llvm::errs() << ": state " << Transition.State << ":\n";
295 };
296
297 if (DiagName.empty())
298 PrintInnerHeading();
299
300 for (auto &Mapping : *Transition.State) {
301 StringRef Option =
302 SrcMgr.getDiagnostics().Diags->getWarningOptionForDiag(
303 Mapping.first);
304 if (!DiagName.empty() && DiagName != Option)
305 continue;
306
307 PrintInnerHeading();
308 llvm::errs() << " ";
309 if (Option.empty())
310 llvm::errs() << "<unknown " << Mapping.first << ">";
311 else
312 llvm::errs() << Option;
313 llvm::errs() << ": ";
314
315 switch (Mapping.second.getSeverity()) {
317 llvm::errs() << "ignored";
318 break;
320 llvm::errs() << "remark";
321 break;
323 llvm::errs() << "warning";
324 break;
326 llvm::errs() << "error";
327 break;
329 llvm::errs() << "fatal";
330 break;
331 }
332
333 if (!Mapping.second.isUser())
334 llvm::errs() << " default";
335 if (Mapping.second.isPragma())
336 llvm::errs() << " pragma";
337 if (Mapping.second.hasNoWarningAsError())
338 llvm::errs() << " no-error";
339 if (Mapping.second.hasNoErrorAsFatal())
340 llvm::errs() << " no-fatal";
341 if (Mapping.second.wasUpgradedFromWarning())
342 llvm::errs() << " overruled";
343 llvm::errs() << "\n";
344 }
345 }
346 }
347}
348
349void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,
350 SourceLocation Loc) {
351 assert(Loc.isValid() && "Adding invalid loc point");
352 DiagStatesByLoc.append(*SourceMgr, Loc, State);
353}
354
356 SourceLocation L) {
357 assert((Diags->isWarningOrExtension(Diag) ||
358 (Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
359 "Cannot map errors into warnings!");
360 assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
361
362 // A command line -Wfoo has an invalid L and cannot override error/fatal
363 // mapping, while a warning pragma can.
364 bool WasUpgradedFromWarning = false;
365 if (Map == diag::Severity::Warning && L.isInvalid()) {
366 DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
367 if (Info.getSeverity() == diag::Severity::Error ||
369 Map = Info.getSeverity();
370 WasUpgradedFromWarning = true;
371 }
372 }
373 DiagnosticMapping Mapping = makeUserMapping(Map, L);
374 Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
375
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);
380 Mapping.hasNoWarningAsError());
381
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);
390 return;
391 }
392
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);
399}
400
402 StringRef Group, diag::Severity Map,
403 SourceLocation Loc) {
404 // Get the diagnostics in this group.
406 if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
407 return true;
408
409 Diags->setGroupSeverity(Group, Map);
410
411 // Set the mapping.
412 for (diag::kind Diag : GroupDiags)
413 setSeverity(Diag, Map, Loc);
414
415 return false;
416}
417
419 diag::Group Group,
420 diag::Severity Map,
421 SourceLocation Loc) {
422 return setSeverityForGroup(Flavor, Diags->getWarningOptionForGroup(Group),
423 Map, Loc);
424}
425
427 bool Enabled) {
428 // If we are enabling this feature, just set the diagnostic mappings to map to
429 // errors.
430 if (Enabled)
433 Diags->setGroupSeverity(Group, diag::Severity::Warning);
434
435 // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
436 // potentially downgrade anything already mapped to be a warning.
437
438 // Get the diagnostics in this group.
440 if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
441 GroupDiags))
442 return true;
443
444 // Perform the mapping change.
445 for (diag::kind Diag : GroupDiags) {
446 DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
447
448 if (Info.getSeverity() == diag::Severity::Error ||
451
452 Info.setNoWarningAsError(true);
453 }
454
455 return false;
456}
457
459 bool Enabled) {
460 // If we are enabling this feature, just set the diagnostic mappings to map to
461 // fatal errors.
462 if (Enabled)
465 Diags->setGroupSeverity(Group, diag::Severity::Error);
466
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.
469
470 // Get the diagnostics in this group.
472 if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
473 GroupDiags))
474 return true;
475
476 // Perform the mapping change.
477 for (diag::kind Diag : GroupDiags) {
478 DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
479
482
483 Info.setNoErrorAsFatal(true);
484 }
485
486 return false;
487}
488
490 diag::Severity Map,
491 SourceLocation Loc) {
492 // Get all the diagnostics.
493 std::vector<diag::kind> AllDiags;
494 DiagnosticIDs::getAllDiagnostics(Flavor, AllDiags);
495
496 // Set the mapping.
497 for (diag::kind Diag : AllDiags)
498 if (Diags->isWarningOrExtension(Diag))
499 setSeverity(Diag, Map, Loc);
500}
501
502namespace {
503// FIXME: We should isolate the parser from SpecialCaseList and just use it
504// here.
505class WarningsSpecialCaseList : public llvm::SpecialCaseList {
506public:
507 static std::unique_ptr<WarningsSpecialCaseList>
508 create(const llvm::MemoryBuffer &Input, std::string &Err);
509
510 // Section names refer to diagnostic groups, which cover multiple individual
511 // diagnostics. Expand diagnostic groups here to individual diagnostics.
512 // A diagnostic can have multiple diagnostic groups associated with it, we let
513 // the last section take precedence in such cases.
514 void processSections(DiagnosticsEngine &Diags);
515
516 bool isDiagSuppressed(diag::kind DiagId, SourceLocation DiagLoc,
517 const SourceManager &SM) const;
518
519private:
520 llvm::DenseMap<diag::kind, const Section *> DiagToSection;
521};
522} // namespace
523
524std::unique_ptr<WarningsSpecialCaseList>
525WarningsSpecialCaseList::create(const llvm::MemoryBuffer &Input,
526 std::string &Err) {
527 auto WarningSuppressionList = std::make_unique<WarningsSpecialCaseList>();
528 if (!WarningSuppressionList->createInternal(&Input, Err))
529 return nullptr;
530 return WarningSuppressionList;
531}
532
533void WarningsSpecialCaseList::processSections(DiagnosticsEngine &Diags) {
534 static constexpr auto WarningFlavor = clang::diag::Flavor::WarningOrError;
535 for (const auto &SectionEntry : sections()) {
536 StringRef DiagGroup = SectionEntry.SectionStr;
537 if (DiagGroup == "*") {
538 // Drop the default section introduced by special case list, we only
539 // support exact diagnostic group names.
540 // FIXME: We should make this configurable in the parser instead.
541 continue;
542 }
543 SmallVector<diag::kind> GroupDiags;
544 if (Diags.getDiagnosticIDs()->getDiagnosticsInGroup(
545 WarningFlavor, DiagGroup, GroupDiags)) {
546 StringRef Suggestion =
547 DiagnosticIDs::getNearestOption(WarningFlavor, DiagGroup);
548 Diags.Report(diag::warn_unknown_diag_option)
549 << static_cast<unsigned>(WarningFlavor) << DiagGroup
550 << !Suggestion.empty() << Suggestion;
551 continue;
552 }
553 for (diag::kind Diag : GroupDiags)
554 // We're intentionally overwriting any previous mappings here to make sure
555 // latest one takes precedence.
556 DiagToSection[Diag] = &SectionEntry;
557 }
558}
559
560void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &Input) {
561 std::string Error;
562 auto WarningSuppressionList = WarningsSpecialCaseList::create(Input, Error);
563 if (!WarningSuppressionList) {
564 // FIXME: Use a `%select` statement instead of printing `Error` as-is. This
565 // should help localization.
566 Report(diag::err_drv_malformed_warning_suppression_mapping)
567 << Input.getBufferIdentifier() << Error;
568 return;
569 }
570 WarningSuppressionList->processSections(*this);
571 DiagSuppressionMapping =
572 [WarningSuppressionList(std::move(WarningSuppressionList))](
573 diag::kind DiagId, SourceLocation DiagLoc, const SourceManager &SM) {
574 return WarningSuppressionList->isDiagSuppressed(DiagId, DiagLoc, SM);
575 };
576}
577
578bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
579 SourceLocation DiagLoc,
580 const SourceManager &SM) const {
581 PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc);
582 if (!PLoc.isValid())
583 return false;
584 const Section *DiagSection = DiagToSection.lookup(DiagId);
585 if (!DiagSection)
586 return false;
587
588 StringRef F = llvm::sys::path::remove_leading_dotslash(PLoc.getFilename());
589
590 StringRef LongestSup = DiagSection->getLongestMatch("src", F, "");
591 if (LongestSup.empty())
592 return false;
593
594 StringRef LongestEmit = DiagSection->getLongestMatch("src", F, "emit");
595 if (LongestEmit.empty())
596 return true;
597
598 return LongestSup.size() > LongestEmit.size();
599}
600
602 SourceLocation DiagLoc) const {
603 if (!hasSourceManager() || !DiagSuppressionMapping)
604 return false;
605 return DiagSuppressionMapping(DiagId, DiagLoc, getSourceManager());
606}
607
609 DiagnosticStorage DiagStorage;
610 DiagStorage.DiagRanges.append(storedDiag.range_begin(),
611 storedDiag.range_end());
612
613 DiagStorage.FixItHints.append(storedDiag.fixit_begin(),
614 storedDiag.fixit_end());
615
616 assert(Client && "DiagnosticConsumer not set!");
617 Level DiagLevel = storedDiag.getLevel();
618 Diagnostic Info(this, storedDiag.getLocation(), storedDiag.getID(),
619 DiagStorage, storedDiag.getMessage());
620 Report(DiagLevel, Info);
621}
622
623void DiagnosticsEngine::Report(Level DiagLevel, const Diagnostic &Info) {
624 assert(DiagLevel != Ignored && "Cannot emit ignored diagnostics!");
625 assert(!getDiagnosticIDs()->isTrapDiag(Info.getID()) &&
626 "Trap diagnostics should not be consumed by the DiagnosticsEngine");
627 Client->HandleDiagnostic(DiagLevel, Info);
628 if (Client->IncludeInDiagnosticCounts()) {
629 if (DiagLevel == Warning)
630 ++NumWarnings;
631 }
632}
633
634/// ProcessDiag - This is the method used to report a diagnostic that is
635/// finally fully formed.
636bool DiagnosticsEngine::ProcessDiag(const DiagnosticBuilder &DiagBuilder) {
637 Diagnostic Info(this, DiagBuilder);
638
639 assert(getClient() && "DiagnosticClient not set!");
640
641 // Figure out the diagnostic level of this message.
642 unsigned DiagID = Info.getID();
643 Level DiagLevel = getDiagnosticLevel(DiagID, Info.getLocation());
644
645 // Update counts for DiagnosticErrorTrap even if a fatal error occurred
646 // or diagnostics are suppressed.
647 if (DiagLevel >= Error) {
648 ++TrapNumErrorsOccurred;
649 if (Diags->isUnrecoverable(DiagID))
650 ++TrapNumUnrecoverableErrorsOccurred;
651 }
652
653 if (SuppressAllDiagnostics)
654 return false;
655
656 if (DiagLevel != Note) {
657 // Record that a fatal error occurred only when we see a second
658 // non-note diagnostic. This allows notes to be attached to the
659 // fatal error, but suppresses any diagnostics that follow those
660 // notes.
661 if (LastDiagLevel == Fatal)
662 FatalErrorOccurred = true;
663
664 LastDiagLevel = DiagLevel;
665 }
666
667 // If a fatal error has already been emitted, silence all subsequent
668 // diagnostics.
669 if (FatalErrorOccurred) {
670 if (DiagLevel >= Error && Client->IncludeInDiagnosticCounts())
671 ++NumErrors;
672
673 return false;
674 }
675
676 // If the client doesn't care about this message, don't issue it. If this is
677 // a note and the last real diagnostic was ignored, ignore it too.
678 if (DiagLevel == Ignored || (DiagLevel == Note && LastDiagLevel == Ignored))
679 return false;
680
681 if (DiagLevel >= Error) {
682 if (Diags->isUnrecoverable(DiagID))
683 UnrecoverableErrorOccurred = true;
684
685 // Warnings which have been upgraded to errors do not prevent compilation.
686 if (Diags->isDefaultMappingAsError(DiagID))
687 UncompilableErrorOccurred = true;
688
689 ErrorOccurred = true;
690 if (Client->IncludeInDiagnosticCounts())
691 ++NumErrors;
692
693 // If we've emitted a lot of errors, emit a fatal error instead of it to
694 // stop a flood of bogus errors.
695 if (ErrorLimit && NumErrors > ErrorLimit && DiagLevel == Error) {
696 Report(diag::fatal_too_many_errors);
697 return false;
698 }
699 }
700
701 // Make sure we set FatalErrorOccurred to ensure that the notes from the
702 // diagnostic that caused `fatal_too_many_errors` won't be emitted.
703 if (Info.getID() == diag::fatal_too_many_errors)
704 FatalErrorOccurred = true;
705
706 // Finally, report it.
707 Report(DiagLevel, Info);
708 return true;
709}
710
712 bool Force) {
713 assert(getClient() && "DiagnosticClient not set!");
714
715 bool Emitted;
716 if (Force) {
717 Diagnostic Info(this, DB);
718
719 // Figure out the diagnostic level of this message.
720 Level DiagLevel = getDiagnosticLevel(Info.getID(), Info.getLocation());
721
722 // Emit the diagnostic regardless of suppression level.
723 Emitted = DiagLevel != Ignored;
724 if (Emitted)
725 Report(DiagLevel, Info);
726 } else {
727 // Process the diagnostic, sending the accumulated information to the
728 // DiagnosticConsumer.
729 Emitted = ProcessDiag(DB);
730 }
731
732 return Emitted;
733}
734
735DiagnosticBuilder::DiagnosticBuilder(DiagnosticsEngine *DiagObj,
736 SourceLocation DiagLoc, unsigned DiagID)
737 : StreamingDiagnostic(DiagObj->DiagAllocator), DiagObj(DiagObj),
738 DiagLoc(DiagLoc), DiagID(DiagID), IsActive(true) {
739 assert(DiagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");
740}
741
742DiagnosticBuilder::DiagnosticBuilder(const DiagnosticBuilder &D)
744 DiagLoc = D.DiagLoc;
745 DiagID = D.DiagID;
746 FlagValue = D.FlagValue;
747 DiagObj = D.DiagObj;
749 D.DiagStorage = nullptr;
751 IsActive = D.IsActive;
752 IsForceEmit = D.IsForceEmit;
753 D.Clear();
754}
755
757 const DiagnosticBuilder &DiagBuilder)
758 : DiagObj(DO), DiagLoc(DiagBuilder.DiagLoc), DiagID(DiagBuilder.DiagID),
759 FlagValue(DiagBuilder.FlagValue), DiagStorage(*DiagBuilder.getStorage()) {
760}
761
763 unsigned DiagID, const DiagnosticStorage &DiagStorage,
764 StringRef StoredDiagMessage)
765 : DiagObj(DO), DiagLoc(DiagLoc), DiagID(DiagID), DiagStorage(DiagStorage),
766 StoredDiagMessage(StoredDiagMessage) {}
767
769
771 const Diagnostic &Info) {
773 return;
774
775 if (DiagLevel == DiagnosticsEngine::Warning)
776 ++NumWarnings;
777 else if (DiagLevel >= DiagnosticsEngine::Error)
778 ++NumErrors;
779}
780
781/// ModifierIs - Return true if the specified modifier matches specified string.
782template <std::size_t StrLen>
783static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
784 const char (&Str)[StrLen]) {
785 return StrLen - 1 == ModifierLen && memcmp(Modifier, Str, StrLen - 1) == 0;
786}
787
788/// ScanForward - Scans forward, looking for the given character, skipping
789/// nested clauses and escaped characters.
790static const char *ScanFormat(const char *I, const char *E, char Target) {
791 unsigned Depth = 0;
792
793 for (; I != E; ++I) {
794 if (Depth == 0 && *I == Target)
795 return I;
796 if (Depth != 0 && *I == '}')
797 Depth--;
798
799 if (*I == '%') {
800 I++;
801 if (I == E)
802 break;
803
804 // Escaped characters get implicitly skipped here.
805
806 // Format specifier.
807 if (!isDigit(*I) && !isPunctuation(*I)) {
808 for (I++; I != E && !isDigit(*I) && *I != '{'; I++)
809 ;
810 if (I == E)
811 break;
812 if (*I == '{')
813 Depth++;
814 }
815 }
816 }
817 return E;
818}
819
820/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
821/// like this: %select{foo|bar|baz}2. This means that the integer argument
822/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
823/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
824/// This is very useful for certain classes of variant diagnostics.
825static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
826 const char *Argument, unsigned ArgumentLen,
827 SmallVectorImpl<char> &OutStr) {
828 const char *ArgumentEnd = Argument + ArgumentLen;
829
830 // Skip over 'ValNo' |'s.
831 while (ValNo) {
832 const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
833 assert(NextVal != ArgumentEnd &&
834 "Value for integer select modifier was"
835 " larger than the number of options in the diagnostic string!");
836 Argument = NextVal + 1; // Skip this string.
837 --ValNo;
838 }
839
840 // Get the end of the value. This is either the } or the |.
841 const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
842
843 // Recursively format the result of the select clause into the output string.
844 DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
845}
846
847/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
848/// letter 's' to the string if the value is not 1. This is used in cases like
849/// this: "you idiot, you have %4 parameter%s4!".
850static void HandleIntegerSModifier(unsigned ValNo,
851 SmallVectorImpl<char> &OutStr) {
852 if (ValNo != 1)
853 OutStr.push_back('s');
854}
855
856/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
857/// prints the ordinal form of the given integer, with 1 corresponding
858/// to the first ordinal. Currently this is hard-coded to use the
859/// English form.
860static void HandleOrdinalModifier(unsigned ValNo,
861 SmallVectorImpl<char> &OutStr) {
862 assert(ValNo != 0 && "ValNo must be strictly positive!");
863
864 llvm::raw_svector_ostream Out(OutStr);
865
866 // We could use text forms for the first N ordinals, but the numeric
867 // forms are actually nicer in diagnostics because they stand out.
868 Out << ValNo << llvm::getOrdinalSuffix(ValNo);
869}
870
871// 123 -> "123".
872// 1234 -> "1.23k".
873// 123456 -> "123.46k".
874// 1234567 -> "1.23M".
875// 1234567890 -> "1.23G".
876// 1234567890123 -> "1.23T".
877static void HandleIntegerHumanModifier(int64_t ValNo,
878 SmallVectorImpl<char> &OutStr) {
879 static constexpr std::array<std::pair<int64_t, char>, 4> Units = {
880 {{1'000'000'000'000L, 'T'},
881 {1'000'000'000L, 'G'},
882 {1'000'000L, 'M'},
883 {1'000L, 'k'}}};
884
885 llvm::raw_svector_ostream Out(OutStr);
886 if (ValNo < 0) {
887 Out << "-";
888 ValNo = -ValNo;
889 }
890 for (const auto &[UnitSize, UnitSign] : Units) {
891 if (ValNo >= UnitSize) {
892 Out << llvm::format("%0.2f%c", ValNo / static_cast<double>(UnitSize),
893 UnitSign);
894 return;
895 }
896 }
897 Out << ValNo;
898}
899
900/// PluralNumber - Parse an unsigned integer and advance Start.
901static unsigned PluralNumber(const char *&Start, const char *End) {
902 // Programming 101: Parse a decimal number :-)
903 unsigned Val = 0;
904 while (Start != End && *Start >= '0' && *Start <= '9') {
905 Val *= 10;
906 Val += *Start - '0';
907 ++Start;
908 }
909 return Val;
910}
911
912/// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
913static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
914 if (*Start != '[') {
915 unsigned Ref = PluralNumber(Start, End);
916 return Ref == Val;
917 }
918
919 ++Start;
920 unsigned Low = PluralNumber(Start, End);
921 assert(*Start == ',' && "Bad plural expression syntax: expected ,");
922 ++Start;
923 unsigned High = PluralNumber(Start, End);
924 assert(*Start == ']' && "Bad plural expression syntax: expected )");
925 ++Start;
926 return Low <= Val && Val <= High;
927}
928
929/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
930static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
931 // Empty condition?
932 if (*Start == ':')
933 return true;
934
935 while (true) {
936 char C = *Start;
937 if (C == '%') {
938 // Modulo expression
939 ++Start;
940 unsigned Arg = PluralNumber(Start, End);
941 assert(*Start == '=' && "Bad plural expression syntax: expected =");
942 ++Start;
943 unsigned ValMod = ValNo % Arg;
944 if (TestPluralRange(ValMod, Start, End))
945 return true;
946 } else {
947 assert((C == '[' || (C >= '0' && C <= '9')) &&
948 "Bad plural expression syntax: unexpected character");
949 // Range expression
950 if (TestPluralRange(ValNo, Start, End))
951 return true;
952 }
953
954 // Scan for next or-expr part.
955 Start = std::find(Start, End, ',');
956 if (Start == End)
957 break;
958 ++Start;
959 }
960 return false;
961}
962
963/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
964/// for complex plural forms, or in languages where all plurals are complex.
965/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
966/// conditions that are tested in order, the form corresponding to the first
967/// that applies being emitted. The empty condition is always true, making the
968/// last form a default case.
969/// Conditions are simple boolean expressions, where n is the number argument.
970/// Here are the rules.
971/// condition := expression | empty
972/// empty := -> always true
973/// expression := numeric [',' expression] -> logical or
974/// numeric := range -> true if n in range
975/// | '%' number '=' range -> true if n % number in range
976/// range := number
977/// | '[' number ',' number ']' -> ranges are inclusive both ends
978///
979/// Here are some examples from the GNU gettext manual written in this form:
980/// English:
981/// {1:form0|:form1}
982/// Latvian:
983/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
984/// Gaeilge:
985/// {1:form0|2:form1|:form2}
986/// Romanian:
987/// {1:form0|0,%100=[1,19]:form1|:form2}
988/// Lithuanian:
989/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
990/// Russian (requires repeated form):
991/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
992/// Slovak
993/// {1:form0|[2,4]:form1|:form2}
994/// Polish (requires repeated form):
995/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
996static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
997 const char *Argument, unsigned ArgumentLen,
998 SmallVectorImpl<char> &OutStr) {
999 const char *ArgumentEnd = Argument + ArgumentLen;
1000 while (true) {
1001 assert(Argument < ArgumentEnd && "Plural expression didn't match.");
1002 const char *ExprEnd = Argument;
1003 while (*ExprEnd != ':') {
1004 assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
1005 ++ExprEnd;
1006 }
1007 if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
1008 Argument = ExprEnd + 1;
1009 ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
1010
1011 // Recursively format the result of the plural clause into the
1012 // output string.
1013 DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
1014 return;
1015 }
1016 Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
1017 }
1018}
1019
1020/// Returns the friendly description for a token kind that will appear
1021/// without quotes in diagnostic messages. These strings may be translatable in
1022/// future.
1024 switch (Kind) {
1025 case tok::identifier:
1026 return "identifier";
1027 default:
1028 return nullptr;
1029 }
1030}
1031
1032/// FormatDiagnostic - Format this diagnostic into a string, substituting the
1033/// formal arguments into the %0 slots. The result is appended onto the Str
1034/// array.
1036 if (StoredDiagMessage.has_value()) {
1037 OutStr.append(StoredDiagMessage->begin(), StoredDiagMessage->end());
1038 return;
1039 }
1040
1041 StringRef Diag = getDiags()->getDiagnosticIDs()->getDescription(getID());
1042
1043 FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
1044}
1045
1046/// EscapeStringForDiagnostic - Append Str to the diagnostic buffer,
1047/// escaping non-printable characters and ill-formed code unit sequences.
1049 SmallVectorImpl<char> &OutStr) {
1050 OutStr.reserve(OutStr.size() + Str.size());
1051 auto *Begin = reinterpret_cast<const unsigned char *>(Str.data());
1052 llvm::raw_svector_ostream OutStream(OutStr);
1053 const unsigned char *End = Begin + Str.size();
1054 while (Begin != End) {
1055 // ASCII case
1056 if (isPrintable(*Begin) || isWhitespace(*Begin)) {
1057 OutStream << *Begin;
1058 ++Begin;
1059 continue;
1060 }
1061 if (llvm::isLegalUTF8Sequence(Begin, End)) {
1062 llvm::UTF32 CodepointValue;
1063 llvm::UTF32 *CpPtr = &CodepointValue;
1064 const unsigned char *CodepointBegin = Begin;
1065 const unsigned char *CodepointEnd =
1066 Begin + llvm::getNumBytesForUTF8(*Begin);
1067 llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(
1068 &Begin, CodepointEnd, &CpPtr, CpPtr + 1, llvm::strictConversion);
1069 (void)Res;
1070 assert(
1071 llvm::conversionOK == Res &&
1072 "the sequence is legal UTF-8 but we couldn't convert it to UTF-32");
1073 assert(Begin == CodepointEnd &&
1074 "we must be further along in the string now");
1075 if (llvm::sys::unicode::isPrintable(CodepointValue) ||
1076 llvm::sys::unicode::isFormatting(CodepointValue)) {
1077 OutStr.append(CodepointBegin, CodepointEnd);
1078 continue;
1079 }
1080 // Unprintable code point.
1081 OutStream << "<U+" << llvm::format_hex_no_prefix(CodepointValue, 4, true)
1082 << ">";
1083 continue;
1084 }
1085 // Invalid code unit.
1086 OutStream << "<" << llvm::format_hex_no_prefix(*Begin, 2, true) << ">";
1087 ++Begin;
1088 }
1089}
1090
1091void Diagnostic::FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
1092 SmallVectorImpl<char> &OutStr) const {
1093 // When the diagnostic string is only "%0", the entire string is being given
1094 // by an outside source. Remove unprintable characters from this string
1095 // and skip all the other string processing.
1096 if (DiagEnd - DiagStr == 2 && StringRef(DiagStr, DiagEnd - DiagStr) == "%0" &&
1098 const std::string &S = getArgStdStr(0);
1099 EscapeStringForDiagnostic(S, OutStr);
1100 return;
1101 }
1102
1103 /// FormattedArgs - Keep track of all of the arguments formatted by
1104 /// ConvertArgToString and pass them into subsequent calls to
1105 /// ConvertArgToString, allowing the implementation to avoid redundancies in
1106 /// obvious cases.
1108
1109 /// QualTypeVals - Pass a vector of arrays so that QualType names can be
1110 /// compared to see if more information is needed to be printed.
1111 SmallVector<intptr_t, 2> QualTypeVals;
1112 SmallString<64> Tree;
1113
1114 for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
1116 QualTypeVals.push_back(getRawArg(i));
1117
1118 while (DiagStr != DiagEnd) {
1119 if (DiagStr[0] != '%') {
1120 // Append non-%0 substrings to Str if we have one.
1121 const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
1122 OutStr.append(DiagStr, StrEnd);
1123 DiagStr = StrEnd;
1124 continue;
1125 } else if (isPunctuation(DiagStr[1])) {
1126 OutStr.push_back(DiagStr[1]); // %% -> %.
1127 DiagStr += 2;
1128 continue;
1129 }
1130
1131 // Skip the %.
1132 ++DiagStr;
1133
1134 // This must be a placeholder for a diagnostic argument. The format for a
1135 // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
1136 // The digit is a number from 0-9 indicating which argument this comes from.
1137 // The modifier is a string of digits from the set [-a-z]+, arguments is a
1138 // brace enclosed string.
1139 const char *Modifier = nullptr, *Argument = nullptr;
1140 unsigned ModifierLen = 0, ArgumentLen = 0;
1141
1142 // Check to see if we have a modifier. If so eat it.
1143 if (!isDigit(DiagStr[0])) {
1144 Modifier = DiagStr;
1145 while (DiagStr[0] == '-' || (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
1146 ++DiagStr;
1147 ModifierLen = DiagStr - Modifier;
1148
1149 // If we have an argument, get it next.
1150 if (DiagStr[0] == '{') {
1151 ++DiagStr; // Skip {.
1152 Argument = DiagStr;
1153
1154 DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
1155 assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
1156 ArgumentLen = DiagStr - Argument;
1157 ++DiagStr; // Skip }.
1158 }
1159 }
1160
1161 assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
1162 unsigned ArgNo = *DiagStr++ - '0';
1163
1164 // Only used for type diffing.
1165 unsigned ArgNo2 = ArgNo;
1166
1168 if (ModifierIs(Modifier, ModifierLen, "diff")) {
1169 assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
1170 "Invalid format for diff modifier");
1171 ++DiagStr; // Comma.
1172 ArgNo2 = *DiagStr++ - '0';
1174 if (Kind == DiagnosticsEngine::ak_qualtype &&
1177 else {
1178 // %diff only supports QualTypes. For other kinds of arguments,
1179 // use the default printing. For example, if the modifier is:
1180 // "%diff{compare $ to $|other text}1,2"
1181 // treat it as:
1182 // "compare %1 to %2"
1183 const char *ArgumentEnd = Argument + ArgumentLen;
1184 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1185 assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd &&
1186 "Found too many '|'s in a %diff modifier!");
1187 const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
1188 const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
1189 const char ArgStr1[] = {'%', static_cast<char>('0' + ArgNo)};
1190 const char ArgStr2[] = {'%', static_cast<char>('0' + ArgNo2)};
1191 FormatDiagnostic(Argument, FirstDollar, OutStr);
1192 FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
1193 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1194 FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
1195 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1196 continue;
1197 }
1198 }
1199
1200 switch (Kind) {
1201 // ---- STRINGS ----
1204 StringRef S = [&]() -> StringRef {
1206 return getArgStdStr(ArgNo);
1207 const char *SZ = getArgCStr(ArgNo);
1208 // Don't crash if get passed a null pointer by accident.
1209 return SZ ? SZ : "(null)";
1210 }();
1211 bool Quoted = false;
1212 if (ModifierIs(Modifier, ModifierLen, "quoted")) {
1213 Quoted = true;
1214 OutStr.push_back('\'');
1215 } else {
1216 assert(ModifierLen == 0 && "unknown modifier for string");
1217 }
1218 EscapeStringForDiagnostic(S, OutStr);
1219 if (Quoted)
1220 OutStr.push_back('\'');
1221 break;
1222 }
1223 // ---- INTEGERS ----
1225 int64_t Val = getArgSInt(ArgNo);
1226
1227 if (ModifierIs(Modifier, ModifierLen, "select")) {
1228 HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1229 OutStr);
1230 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1231 HandleIntegerSModifier(Val, OutStr);
1232 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1233 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1234 OutStr);
1235 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1236 HandleOrdinalModifier((unsigned)Val, OutStr);
1237 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1238 HandleIntegerHumanModifier(Val, OutStr);
1239 } else {
1240 assert(ModifierLen == 0 && "Unknown integer modifier");
1241 llvm::raw_svector_ostream(OutStr) << Val;
1242 }
1243 break;
1244 }
1246 uint64_t Val = getArgUInt(ArgNo);
1247
1248 if (ModifierIs(Modifier, ModifierLen, "select")) {
1249 HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
1250 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1251 HandleIntegerSModifier(Val, OutStr);
1252 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1253 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1254 OutStr);
1255 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1256 HandleOrdinalModifier(Val, OutStr);
1257 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1258 HandleIntegerHumanModifier(Val, OutStr);
1259 } else {
1260 assert(ModifierLen == 0 && "Unknown integer modifier");
1261 llvm::raw_svector_ostream(OutStr) << Val;
1262 }
1263 break;
1264 }
1265 // ---- TOKEN SPELLINGS ----
1267 tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo));
1268 assert(ModifierLen == 0 && "No modifiers for token kinds yet");
1269
1270 llvm::raw_svector_ostream Out(OutStr);
1271 if (const char *S = tok::getPunctuatorSpelling(Kind))
1272 // Quoted token spelling for punctuators.
1273 Out << '\'' << S << '\'';
1274 else if ((S = tok::getKeywordSpelling(Kind)))
1275 // Unquoted token spelling for keywords.
1276 Out << S;
1277 else if ((S = getTokenDescForDiagnostic(Kind)))
1278 // Unquoted translatable token name.
1279 Out << S;
1280 else if ((S = tok::getTokenName(Kind)))
1281 // Debug name, shouldn't appear in user-facing diagnostics.
1282 Out << '<' << S << '>';
1283 else
1284 Out << "(null)";
1285 break;
1286 }
1287 // ---- NAMES and TYPES ----
1289 const IdentifierInfo *II = getArgIdentifier(ArgNo);
1290 assert(ModifierLen == 0 && "No modifiers for strings yet");
1291
1292 // Don't crash if get passed a null pointer by accident.
1293 if (!II) {
1294 const char *S = "(null)";
1295 OutStr.append(S, S + strlen(S));
1296 continue;
1297 }
1298
1299 llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
1300 break;
1301 }
1312 getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
1313 StringRef(Modifier, ModifierLen),
1314 StringRef(Argument, ArgumentLen),
1315 FormattedArgs, OutStr, QualTypeVals);
1316 break;
1318 // Create a struct with all the info needed for printing.
1320 TDT.FromType = getRawArg(ArgNo);
1321 TDT.ToType = getRawArg(ArgNo2);
1322 TDT.ElideType = getDiags()->ElideType;
1323 TDT.ShowColors = getDiags()->ShowColors;
1324 TDT.TemplateDiffUsed = false;
1325 intptr_t val = reinterpret_cast<intptr_t>(&TDT);
1326
1327 const char *ArgumentEnd = Argument + ArgumentLen;
1328 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1329
1330 // Print the tree. If this diagnostic already has a tree, skip the
1331 // second tree.
1332 if (getDiags()->PrintTemplateTree && Tree.empty()) {
1333 TDT.PrintFromType = true;
1334 TDT.PrintTree = true;
1335 getDiags()->ConvertArgToString(Kind, val,
1336 StringRef(Modifier, ModifierLen),
1337 StringRef(Argument, ArgumentLen),
1338 FormattedArgs, Tree, QualTypeVals);
1339 // If there is no tree information, fall back to regular printing.
1340 if (!Tree.empty()) {
1341 FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr);
1342 break;
1343 }
1344 }
1345
1346 // Non-tree printing, also the fall-back when tree printing fails.
1347 // The fall-back is triggered when the types compared are not templates.
1348 const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');
1349 const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');
1350
1351 // Append before text
1352 FormatDiagnostic(Argument, FirstDollar, OutStr);
1353
1354 // Append first type
1355 TDT.PrintTree = false;
1356 TDT.PrintFromType = true;
1357 getDiags()->ConvertArgToString(Kind, val,
1358 StringRef(Modifier, ModifierLen),
1359 StringRef(Argument, ArgumentLen),
1360 FormattedArgs, OutStr, QualTypeVals);
1361 if (!TDT.TemplateDiffUsed)
1362 FormattedArgs.push_back(
1363 std::make_pair(DiagnosticsEngine::ak_qualtype, TDT.FromType));
1364
1365 // Append middle text
1366 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1367
1368 // Append second type
1369 TDT.PrintFromType = false;
1370 getDiags()->ConvertArgToString(Kind, val,
1371 StringRef(Modifier, ModifierLen),
1372 StringRef(Argument, ArgumentLen),
1373 FormattedArgs, OutStr, QualTypeVals);
1374 if (!TDT.TemplateDiffUsed)
1375 FormattedArgs.push_back(
1376 std::make_pair(DiagnosticsEngine::ak_qualtype, TDT.ToType));
1377
1378 // Append end text
1379 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1380 break;
1381 }
1382 }
1383
1384 // Remember this argument info for subsequent formatting operations. Turn
1385 // std::strings into a null terminated string to make it be the same case as
1386 // all the other ones.
1388 continue;
1389 else if (Kind != DiagnosticsEngine::ak_std_string)
1390 FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
1391 else
1392 FormattedArgs.push_back(
1393 std::make_pair(DiagnosticsEngine::ak_c_string,
1394 (intptr_t)getArgStdStr(ArgNo).c_str()));
1395 }
1396
1397 // Append the type tree to the end of the diagnostics.
1398 OutStr.append(Tree.begin(), Tree.end());
1399}
1400
1402 StringRef Message)
1403 : ID(ID), Level(Level), Message(Message) {}
1404
1406 const Diagnostic &Info)
1407 : ID(Info.getID()), Level(Level) {
1408 assert(
1409 (Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
1410 "Valid source location without setting a source manager for diagnostic");
1411 if (Info.getLocation().isValid())
1412 Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
1413 SmallString<64> Message;
1414 Info.FormatDiagnostic(Message);
1415 this->Message.assign(Message.begin(), Message.end());
1416 this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end());
1417 this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end());
1418}
1419
1421 StringRef Message, FullSourceLoc Loc,
1423 ArrayRef<FixItHint> FixIts)
1424 : ID(ID), Level(Level), Loc(Loc), Message(Message),
1425 Ranges(Ranges.begin(), Ranges.end()),
1426 FixIts(FixIts.begin(), FixIts.end()) {}
1427
1428llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
1429 const StoredDiagnostic &SD) {
1430 if (SD.getLocation().hasManager())
1431 OS << SD.getLocation().printToString(SD.getLocation().getManager()) << ": ";
1432 OS << SD.getMessage();
1433 return OS;
1434}
1435
1436/// IncludeInDiagnosticCounts - This method (whose default implementation
1437/// returns true) indicates whether the diagnostics handled by this
1438/// DiagnosticConsumer should be included in the number of diagnostics
1439/// reported by DiagnosticsEngine.
1441
1442void IgnoringDiagConsumer::anchor() {}
1443
1445
1447 DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
1448 Target.HandleDiagnostic(DiagLevel, Info);
1449}
1450
1453 Target.clear();
1454}
1455
1457 return Target.IncludeInDiagnosticCounts();
1458}
1459
1461 for (unsigned I = 0; I != NumCached; ++I)
1462 FreeList[I] = Cached + I;
1463 NumFreeListEntries = NumCached;
1464}
1465
1467 // Don't assert if we are in a CrashRecovery context, as this invariant may
1468 // be invalidated during a crash.
1469 assert((NumFreeListEntries == NumCached ||
1470 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1471 "A partial is on the lam");
1472}
1473
static const char * ScanFormat(const char *I, const char *E, char Target)
ScanForward - Scans forward, looking for the given character, skipping nested clauses and escaped cha...
static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, SmallVectorImpl< char > &OutStr)
HandlePluralModifier - Handle the integer 'plural' modifier.
static void HandleIntegerSModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)
HandleIntegerSModifier - Handle the integer 's' modifier.
static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT, StringRef Modifier, StringRef Argument, ArrayRef< DiagnosticsEngine::ArgumentValue > PrevArgs, SmallVectorImpl< char > &Output, void *Cookie, ArrayRef< intptr_t > QualTypeVals)
static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End)
EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
static void HandleIntegerHumanModifier(int64_t ValNo, SmallVectorImpl< char > &OutStr)
static unsigned PluralNumber(const char *&Start, const char *End)
PluralNumber - Parse an unsigned integer and advance Start.
static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, SmallVectorImpl< char > &OutStr)
HandleSelectModifier - Handle the integer 'select' modifier.
static bool ModifierIs(const char *Modifier, unsigned ModifierLen, const char(&Str)[StrLen])
ModifierIs - Return true if the specified modifier matches specified string.
static bool TestPluralRange(unsigned Val, const char *&Start, const char *End)
TestPluralRange - Test if Val is in the parsed range. Modifies Start.
static void HandleOrdinalModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)
HandleOrdinalModifier - Handle the integer 'ord' modifier.
static const char * getTokenDescForDiagnostic(tok::TokenKind Kind)
Returns the friendly description for a token kind that will appear without quotes in diagnostic messa...
Defines the Diagnostic-related interfaces.
static llvm::GlobalValue::DLLStorageClassTypes getStorage(CodeGenModule &CGM, StringRef Name)
Defines the Diagnostic IDs-related interfaces.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
llvm::MachO::Target Target
Definition MachO.h:51
#define SM(sm)
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines various enumerations that describe declaration and type specifiers.
Defines the clang::TokenKind enum and support functions.
A little helper class used to produce diagnostics.
void Clear() const
Clear out the current diagnostic.
friend class DiagnosticsEngine
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info)
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
unsigned NumErrors
Number of errors reported.
unsigned NumWarnings
Number of warnings reported.
virtual bool IncludeInDiagnosticCounts() const
Indicates whether the diagnostics handled by this DiagnosticConsumer should be included in the number...
void initCustomDiagMapping(DiagnosticMapping &, unsigned DiagID)
static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group)
Get the diagnostic option with the closest edit distance to the given group name.
DiagnosticMapping getDefaultMapping(unsigned DiagID) const
Get the default mapping for this diagnostic.
static bool IsCustomDiag(diag::kind Diag)
static void getAllDiagnostics(diag::Flavor Flavor, std::vector< diag::kind > &Diags)
Get the set of all diagnostic IDs.
void setNoWarningAsError(bool Value)
void setSeverity(diag::Severity Value)
diag::Severity getSeverity() const
void setUpgradedFromWarning(bool Value)
void setNoErrorAsFatal(bool Value)
bool hasNoWarningAsError() const
Options for controlling the compiler diagnostics engine.
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...
Diagnostic(const DiagnosticsEngine *DO, const DiagnosticBuilder &DiagBuilder)
const SourceLocation & getLocation() const
const std::string & getArgStdStr(unsigned Idx) const
Return the provided argument string specified by Idx.
void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const
Format this diagnostic into a string, substituting the formal arguments into the %0 slots.
uint64_t getRawArg(unsigned Idx) const
Return the specified non-string argument in an opaque form.
const char * getArgCStr(unsigned Idx) const
Return the specified C string argument.
const IdentifierInfo * getArgIdentifier(unsigned Idx) const
Return the specified IdentifierInfo argument.
SourceManager & getSourceManager() const
ArrayRef< FixItHint > getFixItHints() const
unsigned getNumArgs() const
bool hasSourceManager() const
unsigned getID() const
DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const
Return the kind of the specified index.
int64_t getArgSInt(unsigned Idx) const
Return the specified signed integer argument.
uint64_t getArgUInt(unsigned Idx) const
Return the specified unsigned integer argument.
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic's ranges.
const DiagnosticsEngine * getDiags() const
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:232
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool hasSourceManager() const
Definition Diagnostic.h:617
bool EmitDiagnostic(const DiagnosticBuilder &DB, bool Force=false)
Emit the diagnostic.
void setDiagSuppressionMapping(llvm::MemoryBuffer &Input)
Diagnostic suppression mappings can be used to suppress specific diagnostics in specific files.
DiagnosticsEngine(IntrusiveRefCntPtr< DiagnosticIDs > Diags, DiagnosticOptions &DiagOpts, DiagnosticConsumer *client=nullptr, bool ShouldOwnClient=true)
bool isSuppressedViaMapping(diag::kind DiagId, SourceLocation DiagLoc) const
void setSeverityForAll(diag::Flavor Flavor, diag::Severity Map, SourceLocation Loc=SourceLocation())
Add the specified mapping to all diagnostics of the specified flavor.
LLVM_DUMP_METHOD void dump() const
void ResetPragmas()
We keep a cache of FileIDs for diagnostics mapped by pragmas.
void setClient(DiagnosticConsumer *client, bool ShouldOwnClient=true)
Set the diagnostic client associated with this diagnostic object.
SourceManager & getSourceManager() const
Definition Diagnostic.h:619
void pushMappings(SourceLocation Loc)
Copies the current DiagMappings and pushes the new copy onto the top of the stack.
void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc)
This allows the client to specify that certain warnings are ignored.
Level
The level of the diagnostic, after it has been through mapping.
Definition Diagnostic.h:237
friend class DiagnosticBuilder
DiagnosticConsumer * getClient()
Definition Diagnostic.h:607
@ ak_nameddecl
NamedDecl *.
Definition Diagnostic.h:278
@ ak_declcontext
DeclContext *.
Definition Diagnostic.h:284
@ ak_addrspace
address space
Definition Diagnostic.h:266
@ ak_identifierinfo
IdentifierInfo.
Definition Diagnostic.h:263
@ ak_qualtype_pair
pair<QualType, QualType>
Definition Diagnostic.h:287
@ ak_attr_info
AttributeCommonInfo *.
Definition Diagnostic.h:296
@ ak_c_string
const char *
Definition Diagnostic.h:251
@ ak_declarationname
DeclarationName.
Definition Diagnostic.h:275
@ ak_tokenkind
enum TokenKind : unsigned
Definition Diagnostic.h:260
@ ak_std_string
std::string
Definition Diagnostic.h:248
@ ak_nestednamespec
NestedNameSpecifier *.
Definition Diagnostic.h:281
Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const
Based on the way the client configured the DiagnosticsEngine object, classify the specified diagnosti...
Definition Diagnostic.h:966
bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled)
Set the error-as-fatal flag for the given diagnostic group.
bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled)
Set the warning-as-error flag for the given diagnostic group.
void ConvertArgToString(ArgumentKind Kind, intptr_t Val, StringRef Modifier, StringRef Argument, ArrayRef< ArgumentValue > PrevArgs, SmallVectorImpl< char > &Output, ArrayRef< intptr_t > QualTypeVals) const
Converts a diagnostic argument (as an intptr_t) into the string that represents it.
Definition Diagnostic.h:912
bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group, diag::Severity Map, SourceLocation Loc=SourceLocation())
Change an entire diagnostic group (e.g.
bool popMappings(SourceLocation Loc)
Pops the current DiagMappings off the top of the stack, causing the new top of the stack to be the ac...
const IntrusiveRefCntPtr< DiagnosticIDs > & getDiagnosticIDs() const
Definition Diagnostic.h:592
void Reset(bool soft=false)
Reset the state of the diagnostic object to its initial configuration.
bool IncludeInDiagnosticCounts() const override
Indicates whether the diagnostics handled by this DiagnosticConsumer should be included in the number...
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
A SourceLocation and its associated SourceManager.
bool hasManager() const
Checks whether the SourceManager is present.
const SourceManager & getManager() const
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
Represents an unpacked "presumed" location which can be presented to the user.
const char * getFilename() const
Return the presumed filename of this location.
Encodes a location in the source.
std::string printToString(const SourceManager &SM) const
bool isValid() const
Return true if this is a valid SourceLocation object.
void print(raw_ostream &OS, const SourceManager &SM) const
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
FileIDAndOffset getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
DiagnosticsEngine & getDiagnostics() const
llvm::MemoryBufferRef getBufferOrFake(FileID FID, SourceLocation Loc=SourceLocation()) const
Return the buffer for the specified FileID.
FileIDAndOffset getDecomposedIncludedLoc(FileID FID) const
Returns the "included/expanded in" decomposed location of the given FileID.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...
unsigned getID() const
range_iterator range_begin() const
DiagnosticsEngine::Level getLevel() const
fixit_iterator fixit_begin() const
const FullSourceLoc & getLocation() const
range_iterator range_end() const
StringRef getMessage() const
fixit_iterator fixit_end() const
The streaming interface shared between DiagnosticBuilder and PartialDiagnostic.
DiagStorageAllocator * Allocator
Allocator used to allocate storage for this diagnostic.
DiagnosticStorage * DiagStorage
void AddString(StringRef V) const
Flavor
Flavors of diagnostics we can emit.
@ WarningOrError
A diagnostic that indicates a problem or potential problem.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...
@ Warning
Present this diagnostic as a warning.
@ Fatal
Present this diagnostic as a fatal error.
@ Error
Present this diagnostic as an error.
@ Remark
Present this diagnostic as a remark.
@ Ignored
Do not present this diagnostic, ignore it.
const char * getTokenName(TokenKind Kind) LLVM_READNONE
Determines the name of a token as used within the front end.
const char * getKeywordSpelling(TokenKind Kind) LLVM_READNONE
Determines the spelling of simple keyword and contextual keyword tokens like 'int' and 'dynamic_cast'...
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
Definition TokenKinds.h:25
const char * getPunctuatorSpelling(TokenKind Kind) LLVM_READNONE
Determines the spelling of simple punctuation tokens like '!
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY bool isPrintable(unsigned char c)
Return true if this character is an ASCII printable character; that is, a character that should take ...
Definition CharInfo.h:160
std::pair< FileID, unsigned > FileIDAndOffset
std::pair< NullabilityKind, bool > DiagNullabilityKind
A nullability kind paired with a bit indicating whether it used a context-sensitive keyword.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
llvm::StringRef getNullabilitySpelling(NullabilityKind kind, bool isContextSensitive=false)
Retrieve the spelling of the given nullability kind.
void EscapeStringForDiagnostic(StringRef Str, SmallVectorImpl< char > &OutStr)
EscapeStringForDiagnostic - Append Str to the diagnostic buffer, escaping non-printable characters an...
LLVM_READONLY bool isDigit(unsigned char c)
Return true if this character is an ASCII digit: [0-9].
Definition CharInfo.h:114
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
Definition CharInfo.h:108
const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ConceptReference *C)
Insertion operator for diagnostics.
LLVM_READONLY bool isPunctuation(unsigned char c)
Return true if this character is an ASCII punctuation character.
Definition CharInfo.h:152
__INTPTR_TYPE__ intptr_t
A signed integer type with the property that any valid pointer to void can be converted to this type,...
#define true
Definition stdbool.h:25
SmallVector< CharSourceRange, 8 > DiagRanges
The list of ranges added to this diagnostic.
Definition Diagnostic.h:182
SmallVector< FixItHint, 6 > FixItHints
If valid, provides a hint with some code to insert, remove, or modify at a particular position.
Definition Diagnostic.h:186