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 /*OrderBySize=*/true))
530 return nullptr;
531 return WarningSuppressionList;
532}
533
534void WarningsSpecialCaseList::processSections(DiagnosticsEngine &Diags) {
535 static constexpr auto WarningFlavor = clang::diag::Flavor::WarningOrError;
536 for (const auto &SectionEntry : sections()) {
537 StringRef DiagGroup = SectionEntry.SectionStr;
538 if (DiagGroup == "*") {
539 // Drop the default section introduced by special case list, we only
540 // support exact diagnostic group names.
541 // FIXME: We should make this configurable in the parser instead.
542 continue;
543 }
544 SmallVector<diag::kind> GroupDiags;
545 if (Diags.getDiagnosticIDs()->getDiagnosticsInGroup(
546 WarningFlavor, DiagGroup, GroupDiags)) {
547 StringRef Suggestion =
548 DiagnosticIDs::getNearestOption(WarningFlavor, DiagGroup);
549 Diags.Report(diag::warn_unknown_diag_option)
550 << static_cast<unsigned>(WarningFlavor) << DiagGroup
551 << !Suggestion.empty() << Suggestion;
552 continue;
553 }
554 for (diag::kind Diag : GroupDiags)
555 // We're intentionally overwriting any previous mappings here to make sure
556 // latest one takes precedence.
557 DiagToSection[Diag] = &SectionEntry;
558 }
559}
560
561void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &Input) {
562 std::string Error;
563 auto WarningSuppressionList = WarningsSpecialCaseList::create(Input, Error);
564 if (!WarningSuppressionList) {
565 // FIXME: Use a `%select` statement instead of printing `Error` as-is. This
566 // should help localization.
567 Report(diag::err_drv_malformed_warning_suppression_mapping)
568 << Input.getBufferIdentifier() << Error;
569 return;
570 }
571 WarningSuppressionList->processSections(*this);
572 DiagSuppressionMapping =
573 [WarningSuppressionList(std::move(WarningSuppressionList))](
574 diag::kind DiagId, SourceLocation DiagLoc, const SourceManager &SM) {
575 return WarningSuppressionList->isDiagSuppressed(DiagId, DiagLoc, SM);
576 };
577}
578
579bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
580 SourceLocation DiagLoc,
581 const SourceManager &SM) const {
582 PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc);
583 if (!PLoc.isValid())
584 return false;
585 const Section *DiagSection = DiagToSection.lookup(DiagId);
586 if (!DiagSection)
587 return false;
588
589 StringRef F = llvm::sys::path::remove_leading_dotslash(PLoc.getFilename());
590
591 StringRef LongestSup = DiagSection->getLongestMatch("src", F, "");
592 if (LongestSup.empty())
593 return false;
594
595 StringRef LongestEmit = DiagSection->getLongestMatch("src", F, "emit");
596 if (LongestEmit.empty())
597 return true;
598
599 return LongestSup.size() > LongestEmit.size();
600}
601
603 SourceLocation DiagLoc) const {
604 if (!hasSourceManager() || !DiagSuppressionMapping)
605 return false;
606 return DiagSuppressionMapping(DiagId, DiagLoc, getSourceManager());
607}
608
610 DiagnosticStorage DiagStorage;
611 DiagStorage.DiagRanges.append(storedDiag.range_begin(),
612 storedDiag.range_end());
613
614 DiagStorage.FixItHints.append(storedDiag.fixit_begin(),
615 storedDiag.fixit_end());
616
617 assert(Client && "DiagnosticConsumer not set!");
618 Level DiagLevel = storedDiag.getLevel();
619 Diagnostic Info(this, storedDiag.getLocation(), storedDiag.getID(),
620 DiagStorage, storedDiag.getMessage());
621 Report(DiagLevel, Info);
622}
623
624void DiagnosticsEngine::Report(Level DiagLevel, const Diagnostic &Info) {
625 assert(DiagLevel != Ignored && "Cannot emit ignored diagnostics!");
626 assert(!getDiagnosticIDs()->isTrapDiag(Info.getID()) &&
627 "Trap diagnostics should not be consumed by the DiagnosticsEngine");
628 Client->HandleDiagnostic(DiagLevel, Info);
629 if (Client->IncludeInDiagnosticCounts()) {
630 if (DiagLevel == Warning)
631 ++NumWarnings;
632 }
633}
634
635/// ProcessDiag - This is the method used to report a diagnostic that is
636/// finally fully formed.
637bool DiagnosticsEngine::ProcessDiag(const DiagnosticBuilder &DiagBuilder) {
638 Diagnostic Info(this, DiagBuilder);
639
640 assert(getClient() && "DiagnosticClient not set!");
641
642 // Figure out the diagnostic level of this message.
643 unsigned DiagID = Info.getID();
644 Level DiagLevel = getDiagnosticLevel(DiagID, Info.getLocation());
645
646 // Update counts for DiagnosticErrorTrap even if a fatal error occurred
647 // or diagnostics are suppressed.
648 if (DiagLevel >= Error) {
649 ++TrapNumErrorsOccurred;
650 if (Diags->isUnrecoverable(DiagID))
651 ++TrapNumUnrecoverableErrorsOccurred;
652 }
653
654 if (SuppressAllDiagnostics)
655 return false;
656
657 if (DiagLevel != Note) {
658 // Record that a fatal error occurred only when we see a second
659 // non-note diagnostic. This allows notes to be attached to the
660 // fatal error, but suppresses any diagnostics that follow those
661 // notes.
662 if (LastDiagLevel == Fatal)
663 FatalErrorOccurred = true;
664
665 LastDiagLevel = DiagLevel;
666 }
667
668 // If a fatal error has already been emitted, silence all subsequent
669 // diagnostics.
670 if (FatalErrorOccurred) {
671 if (DiagLevel >= Error && Client->IncludeInDiagnosticCounts())
672 ++NumErrors;
673
674 return false;
675 }
676
677 // If the client doesn't care about this message, don't issue it. If this is
678 // a note and the last real diagnostic was ignored, ignore it too.
679 if (DiagLevel == Ignored || (DiagLevel == Note && LastDiagLevel == Ignored))
680 return false;
681
682 if (DiagLevel >= Error) {
683 if (Diags->isUnrecoverable(DiagID))
684 UnrecoverableErrorOccurred = true;
685
686 // Warnings which have been upgraded to errors do not prevent compilation.
687 if (Diags->isDefaultMappingAsError(DiagID))
688 UncompilableErrorOccurred = true;
689
690 ErrorOccurred = true;
691 if (Client->IncludeInDiagnosticCounts())
692 ++NumErrors;
693
694 // If we've emitted a lot of errors, emit a fatal error instead of it to
695 // stop a flood of bogus errors.
696 if (ErrorLimit && NumErrors > ErrorLimit && DiagLevel == Error) {
697 Report(diag::fatal_too_many_errors);
698 return false;
699 }
700 }
701
702 // Make sure we set FatalErrorOccurred to ensure that the notes from the
703 // diagnostic that caused `fatal_too_many_errors` won't be emitted.
704 if (Info.getID() == diag::fatal_too_many_errors)
705 FatalErrorOccurred = true;
706
707 // Finally, report it.
708 Report(DiagLevel, Info);
709 return true;
710}
711
713 bool Force) {
714 assert(getClient() && "DiagnosticClient not set!");
715
716 bool Emitted;
717 if (Force) {
718 Diagnostic Info(this, DB);
719
720 // Figure out the diagnostic level of this message.
721 Level DiagLevel = getDiagnosticLevel(Info.getID(), Info.getLocation());
722
723 // Emit the diagnostic regardless of suppression level.
724 Emitted = DiagLevel != Ignored;
725 if (Emitted)
726 Report(DiagLevel, Info);
727 } else {
728 // Process the diagnostic, sending the accumulated information to the
729 // DiagnosticConsumer.
730 Emitted = ProcessDiag(DB);
731 }
732
733 return Emitted;
734}
735
736DiagnosticBuilder::DiagnosticBuilder(DiagnosticsEngine *DiagObj,
737 SourceLocation DiagLoc, unsigned DiagID)
738 : StreamingDiagnostic(DiagObj->DiagAllocator), DiagObj(DiagObj),
739 DiagLoc(DiagLoc), DiagID(DiagID), IsActive(true) {
740 assert(DiagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");
741}
742
743DiagnosticBuilder::DiagnosticBuilder(const DiagnosticBuilder &D)
745 DiagLoc = D.DiagLoc;
746 DiagID = D.DiagID;
747 FlagValue = D.FlagValue;
748 DiagObj = D.DiagObj;
750 D.DiagStorage = nullptr;
752 IsActive = D.IsActive;
753 IsForceEmit = D.IsForceEmit;
754 D.Clear();
755}
756
758 const DiagnosticBuilder &DiagBuilder)
759 : DiagObj(DO), DiagLoc(DiagBuilder.DiagLoc), DiagID(DiagBuilder.DiagID),
760 FlagValue(DiagBuilder.FlagValue), DiagStorage(*DiagBuilder.getStorage()) {
761}
762
764 unsigned DiagID, const DiagnosticStorage &DiagStorage,
765 StringRef StoredDiagMessage)
766 : DiagObj(DO), DiagLoc(DiagLoc), DiagID(DiagID), DiagStorage(DiagStorage),
767 StoredDiagMessage(StoredDiagMessage) {}
768
770
772 const Diagnostic &Info) {
774 return;
775
776 if (DiagLevel == DiagnosticsEngine::Warning)
777 ++NumWarnings;
778 else if (DiagLevel >= DiagnosticsEngine::Error)
779 ++NumErrors;
780}
781
782/// ModifierIs - Return true if the specified modifier matches specified string.
783template <std::size_t StrLen>
784static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
785 const char (&Str)[StrLen]) {
786 return StrLen - 1 == ModifierLen && memcmp(Modifier, Str, StrLen - 1) == 0;
787}
788
789/// ScanForward - Scans forward, looking for the given character, skipping
790/// nested clauses and escaped characters.
791static const char *ScanFormat(const char *I, const char *E, char Target) {
792 unsigned Depth = 0;
793
794 for (; I != E; ++I) {
795 if (Depth == 0 && *I == Target)
796 return I;
797 if (Depth != 0 && *I == '}')
798 Depth--;
799
800 if (*I == '%') {
801 I++;
802 if (I == E)
803 break;
804
805 // Escaped characters get implicitly skipped here.
806
807 // Format specifier.
808 if (!isDigit(*I) && !isPunctuation(*I)) {
809 for (I++; I != E && !isDigit(*I) && *I != '{'; I++)
810 ;
811 if (I == E)
812 break;
813 if (*I == '{')
814 Depth++;
815 }
816 }
817 }
818 return E;
819}
820
821/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
822/// like this: %select{foo|bar|baz}2. This means that the integer argument
823/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
824/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
825/// This is very useful for certain classes of variant diagnostics.
826static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
827 const char *Argument, unsigned ArgumentLen,
828 SmallVectorImpl<char> &OutStr) {
829 const char *ArgumentEnd = Argument + ArgumentLen;
830
831 // Skip over 'ValNo' |'s.
832 while (ValNo) {
833 const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
834 assert(NextVal != ArgumentEnd &&
835 "Value for integer select modifier was"
836 " larger than the number of options in the diagnostic string!");
837 Argument = NextVal + 1; // Skip this string.
838 --ValNo;
839 }
840
841 // Get the end of the value. This is either the } or the |.
842 const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
843
844 // Recursively format the result of the select clause into the output string.
845 DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
846}
847
848/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
849/// letter 's' to the string if the value is not 1. This is used in cases like
850/// this: "you idiot, you have %4 parameter%s4!".
851static void HandleIntegerSModifier(unsigned ValNo,
852 SmallVectorImpl<char> &OutStr) {
853 if (ValNo != 1)
854 OutStr.push_back('s');
855}
856
857/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
858/// prints the ordinal form of the given integer, with 1 corresponding
859/// to the first ordinal. Currently this is hard-coded to use the
860/// English form.
861static void HandleOrdinalModifier(unsigned ValNo,
862 SmallVectorImpl<char> &OutStr) {
863 assert(ValNo != 0 && "ValNo must be strictly positive!");
864
865 llvm::raw_svector_ostream Out(OutStr);
866
867 // We could use text forms for the first N ordinals, but the numeric
868 // forms are actually nicer in diagnostics because they stand out.
869 Out << ValNo << llvm::getOrdinalSuffix(ValNo);
870}
871
872// 123 -> "123".
873// 1234 -> "1.23k".
874// 123456 -> "123.46k".
875// 1234567 -> "1.23M".
876// 1234567890 -> "1.23G".
877// 1234567890123 -> "1.23T".
878static void HandleIntegerHumanModifier(int64_t ValNo,
879 SmallVectorImpl<char> &OutStr) {
880 static constexpr std::array<std::pair<int64_t, char>, 4> Units = {
881 {{1'000'000'000'000L, 'T'},
882 {1'000'000'000L, 'G'},
883 {1'000'000L, 'M'},
884 {1'000L, 'k'}}};
885
886 llvm::raw_svector_ostream Out(OutStr);
887 if (ValNo < 0) {
888 Out << "-";
889 ValNo = -ValNo;
890 }
891 for (const auto &[UnitSize, UnitSign] : Units) {
892 if (ValNo >= UnitSize) {
893 Out << llvm::format("%0.2f%c", ValNo / static_cast<double>(UnitSize),
894 UnitSign);
895 return;
896 }
897 }
898 Out << ValNo;
899}
900
901/// PluralNumber - Parse an unsigned integer and advance Start.
902static unsigned PluralNumber(const char *&Start, const char *End) {
903 // Programming 101: Parse a decimal number :-)
904 unsigned Val = 0;
905 while (Start != End && *Start >= '0' && *Start <= '9') {
906 Val *= 10;
907 Val += *Start - '0';
908 ++Start;
909 }
910 return Val;
911}
912
913/// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
914static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
915 if (*Start != '[') {
916 unsigned Ref = PluralNumber(Start, End);
917 return Ref == Val;
918 }
919
920 ++Start;
921 unsigned Low = PluralNumber(Start, End);
922 assert(*Start == ',' && "Bad plural expression syntax: expected ,");
923 ++Start;
924 unsigned High = PluralNumber(Start, End);
925 assert(*Start == ']' && "Bad plural expression syntax: expected )");
926 ++Start;
927 return Low <= Val && Val <= High;
928}
929
930/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
931static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
932 // Empty condition?
933 if (*Start == ':')
934 return true;
935
936 while (true) {
937 char C = *Start;
938 if (C == '%') {
939 // Modulo expression
940 ++Start;
941 unsigned Arg = PluralNumber(Start, End);
942 assert(*Start == '=' && "Bad plural expression syntax: expected =");
943 ++Start;
944 unsigned ValMod = ValNo % Arg;
945 if (TestPluralRange(ValMod, Start, End))
946 return true;
947 } else {
948 assert((C == '[' || (C >= '0' && C <= '9')) &&
949 "Bad plural expression syntax: unexpected character");
950 // Range expression
951 if (TestPluralRange(ValNo, Start, End))
952 return true;
953 }
954
955 // Scan for next or-expr part.
956 Start = std::find(Start, End, ',');
957 if (Start == End)
958 break;
959 ++Start;
960 }
961 return false;
962}
963
964/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
965/// for complex plural forms, or in languages where all plurals are complex.
966/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
967/// conditions that are tested in order, the form corresponding to the first
968/// that applies being emitted. The empty condition is always true, making the
969/// last form a default case.
970/// Conditions are simple boolean expressions, where n is the number argument.
971/// Here are the rules.
972/// condition := expression | empty
973/// empty := -> always true
974/// expression := numeric [',' expression] -> logical or
975/// numeric := range -> true if n in range
976/// | '%' number '=' range -> true if n % number in range
977/// range := number
978/// | '[' number ',' number ']' -> ranges are inclusive both ends
979///
980/// Here are some examples from the GNU gettext manual written in this form:
981/// English:
982/// {1:form0|:form1}
983/// Latvian:
984/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
985/// Gaeilge:
986/// {1:form0|2:form1|:form2}
987/// Romanian:
988/// {1:form0|0,%100=[1,19]:form1|:form2}
989/// Lithuanian:
990/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
991/// Russian (requires repeated form):
992/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
993/// Slovak
994/// {1:form0|[2,4]:form1|:form2}
995/// Polish (requires repeated form):
996/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
997static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
998 const char *Argument, unsigned ArgumentLen,
999 SmallVectorImpl<char> &OutStr) {
1000 const char *ArgumentEnd = Argument + ArgumentLen;
1001 while (true) {
1002 assert(Argument < ArgumentEnd && "Plural expression didn't match.");
1003 const char *ExprEnd = Argument;
1004 while (*ExprEnd != ':') {
1005 assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
1006 ++ExprEnd;
1007 }
1008 if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
1009 Argument = ExprEnd + 1;
1010 ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
1011
1012 // Recursively format the result of the plural clause into the
1013 // output string.
1014 DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
1015 return;
1016 }
1017 Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
1018 }
1019}
1020
1021/// Returns the friendly description for a token kind that will appear
1022/// without quotes in diagnostic messages. These strings may be translatable in
1023/// future.
1025 switch (Kind) {
1026 case tok::identifier:
1027 return "identifier";
1028 default:
1029 return nullptr;
1030 }
1031}
1032
1033/// FormatDiagnostic - Format this diagnostic into a string, substituting the
1034/// formal arguments into the %0 slots. The result is appended onto the Str
1035/// array.
1037 if (StoredDiagMessage.has_value()) {
1038 OutStr.append(StoredDiagMessage->begin(), StoredDiagMessage->end());
1039 return;
1040 }
1041
1042 StringRef Diag = getDiags()->getDiagnosticIDs()->getDescription(getID());
1043
1044 FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
1045}
1046
1047/// EscapeStringForDiagnostic - Append Str to the diagnostic buffer,
1048/// escaping non-printable characters and ill-formed code unit sequences.
1050 SmallVectorImpl<char> &OutStr) {
1051 OutStr.reserve(OutStr.size() + Str.size());
1052 auto *Begin = reinterpret_cast<const unsigned char *>(Str.data());
1053 llvm::raw_svector_ostream OutStream(OutStr);
1054 const unsigned char *End = Begin + Str.size();
1055 while (Begin != End) {
1056 // ASCII case
1057 if (isPrintable(*Begin) || isWhitespace(*Begin)) {
1058 OutStream << *Begin;
1059 ++Begin;
1060 continue;
1061 }
1062 if (llvm::isLegalUTF8Sequence(Begin, End)) {
1063 llvm::UTF32 CodepointValue;
1064 llvm::UTF32 *CpPtr = &CodepointValue;
1065 const unsigned char *CodepointBegin = Begin;
1066 const unsigned char *CodepointEnd =
1067 Begin + llvm::getNumBytesForUTF8(*Begin);
1068 llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(
1069 &Begin, CodepointEnd, &CpPtr, CpPtr + 1, llvm::strictConversion);
1070 (void)Res;
1071 assert(
1072 llvm::conversionOK == Res &&
1073 "the sequence is legal UTF-8 but we couldn't convert it to UTF-32");
1074 assert(Begin == CodepointEnd &&
1075 "we must be further along in the string now");
1076 if (llvm::sys::unicode::isPrintable(CodepointValue) ||
1077 llvm::sys::unicode::isFormatting(CodepointValue)) {
1078 OutStr.append(CodepointBegin, CodepointEnd);
1079 continue;
1080 }
1081 // Unprintable code point.
1082 OutStream << "<U+" << llvm::format_hex_no_prefix(CodepointValue, 4, true)
1083 << ">";
1084 continue;
1085 }
1086 // Invalid code unit.
1087 OutStream << "<" << llvm::format_hex_no_prefix(*Begin, 2, true) << ">";
1088 ++Begin;
1089 }
1090}
1091
1092void Diagnostic::FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
1093 SmallVectorImpl<char> &OutStr) const {
1094 // When the diagnostic string is only "%0", the entire string is being given
1095 // by an outside source. Remove unprintable characters from this string
1096 // and skip all the other string processing.
1097 if (DiagEnd - DiagStr == 2 && StringRef(DiagStr, DiagEnd - DiagStr) == "%0" &&
1099 const std::string &S = getArgStdStr(0);
1100 EscapeStringForDiagnostic(S, OutStr);
1101 return;
1102 }
1103
1104 /// FormattedArgs - Keep track of all of the arguments formatted by
1105 /// ConvertArgToString and pass them into subsequent calls to
1106 /// ConvertArgToString, allowing the implementation to avoid redundancies in
1107 /// obvious cases.
1109
1110 /// QualTypeVals - Pass a vector of arrays so that QualType names can be
1111 /// compared to see if more information is needed to be printed.
1112 SmallVector<intptr_t, 2> QualTypeVals;
1113 SmallString<64> Tree;
1114
1115 for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
1117 QualTypeVals.push_back(getRawArg(i));
1118
1119 while (DiagStr != DiagEnd) {
1120 if (DiagStr[0] != '%') {
1121 // Append non-%0 substrings to Str if we have one.
1122 const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
1123 OutStr.append(DiagStr, StrEnd);
1124 DiagStr = StrEnd;
1125 continue;
1126 } else if (isPunctuation(DiagStr[1])) {
1127 OutStr.push_back(DiagStr[1]); // %% -> %.
1128 DiagStr += 2;
1129 continue;
1130 }
1131
1132 // Skip the %.
1133 ++DiagStr;
1134
1135 // This must be a placeholder for a diagnostic argument. The format for a
1136 // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
1137 // The digit is a number from 0-9 indicating which argument this comes from.
1138 // The modifier is a string of digits from the set [-a-z]+, arguments is a
1139 // brace enclosed string.
1140 const char *Modifier = nullptr, *Argument = nullptr;
1141 unsigned ModifierLen = 0, ArgumentLen = 0;
1142
1143 // Check to see if we have a modifier. If so eat it.
1144 if (!isDigit(DiagStr[0])) {
1145 Modifier = DiagStr;
1146 while (DiagStr[0] == '-' || (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
1147 ++DiagStr;
1148 ModifierLen = DiagStr - Modifier;
1149
1150 // If we have an argument, get it next.
1151 if (DiagStr[0] == '{') {
1152 ++DiagStr; // Skip {.
1153 Argument = DiagStr;
1154
1155 DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
1156 assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
1157 ArgumentLen = DiagStr - Argument;
1158 ++DiagStr; // Skip }.
1159 }
1160 }
1161
1162 assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
1163 unsigned ArgNo = *DiagStr++ - '0';
1164
1165 // Only used for type diffing.
1166 unsigned ArgNo2 = ArgNo;
1167
1169 if (ModifierIs(Modifier, ModifierLen, "diff")) {
1170 assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
1171 "Invalid format for diff modifier");
1172 ++DiagStr; // Comma.
1173 ArgNo2 = *DiagStr++ - '0';
1175 if (Kind == DiagnosticsEngine::ak_qualtype &&
1178 else {
1179 // %diff only supports QualTypes. For other kinds of arguments,
1180 // use the default printing. For example, if the modifier is:
1181 // "%diff{compare $ to $|other text}1,2"
1182 // treat it as:
1183 // "compare %1 to %2"
1184 const char *ArgumentEnd = Argument + ArgumentLen;
1185 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1186 assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd &&
1187 "Found too many '|'s in a %diff modifier!");
1188 const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
1189 const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
1190 const char ArgStr1[] = {'%', static_cast<char>('0' + ArgNo)};
1191 const char ArgStr2[] = {'%', static_cast<char>('0' + ArgNo2)};
1192 FormatDiagnostic(Argument, FirstDollar, OutStr);
1193 FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
1194 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1195 FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
1196 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1197 continue;
1198 }
1199 }
1200
1201 switch (Kind) {
1202 // ---- STRINGS ----
1205 StringRef S = [&]() -> StringRef {
1207 return getArgStdStr(ArgNo);
1208 const char *SZ = getArgCStr(ArgNo);
1209 // Don't crash if get passed a null pointer by accident.
1210 return SZ ? SZ : "(null)";
1211 }();
1212 bool Quoted = false;
1213 if (ModifierIs(Modifier, ModifierLen, "quoted")) {
1214 Quoted = true;
1215 OutStr.push_back('\'');
1216 } else {
1217 assert(ModifierLen == 0 && "unknown modifier for string");
1218 }
1219 EscapeStringForDiagnostic(S, OutStr);
1220 if (Quoted)
1221 OutStr.push_back('\'');
1222 break;
1223 }
1224 // ---- INTEGERS ----
1226 int64_t Val = getArgSInt(ArgNo);
1227
1228 if (ModifierIs(Modifier, ModifierLen, "select")) {
1229 HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1230 OutStr);
1231 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1232 HandleIntegerSModifier(Val, OutStr);
1233 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1234 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1235 OutStr);
1236 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1237 HandleOrdinalModifier((unsigned)Val, OutStr);
1238 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1239 HandleIntegerHumanModifier(Val, OutStr);
1240 } else {
1241 assert(ModifierLen == 0 && "Unknown integer modifier");
1242 llvm::raw_svector_ostream(OutStr) << Val;
1243 }
1244 break;
1245 }
1247 uint64_t Val = getArgUInt(ArgNo);
1248
1249 if (ModifierIs(Modifier, ModifierLen, "select")) {
1250 HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
1251 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1252 HandleIntegerSModifier(Val, OutStr);
1253 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1254 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1255 OutStr);
1256 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1257 HandleOrdinalModifier(Val, OutStr);
1258 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1259 HandleIntegerHumanModifier(Val, OutStr);
1260 } else {
1261 assert(ModifierLen == 0 && "Unknown integer modifier");
1262 llvm::raw_svector_ostream(OutStr) << Val;
1263 }
1264 break;
1265 }
1266 // ---- TOKEN SPELLINGS ----
1268 tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo));
1269 assert(ModifierLen == 0 && "No modifiers for token kinds yet");
1270
1271 llvm::raw_svector_ostream Out(OutStr);
1272 if (const char *S = tok::getPunctuatorSpelling(Kind))
1273 // Quoted token spelling for punctuators.
1274 Out << '\'' << S << '\'';
1275 else if ((S = tok::getKeywordSpelling(Kind)))
1276 // Unquoted token spelling for keywords.
1277 Out << S;
1278 else if ((S = getTokenDescForDiagnostic(Kind)))
1279 // Unquoted translatable token name.
1280 Out << S;
1281 else if ((S = tok::getTokenName(Kind)))
1282 // Debug name, shouldn't appear in user-facing diagnostics.
1283 Out << '<' << S << '>';
1284 else
1285 Out << "(null)";
1286 break;
1287 }
1288 // ---- NAMES and TYPES ----
1290 const IdentifierInfo *II = getArgIdentifier(ArgNo);
1291 assert(ModifierLen == 0 && "No modifiers for strings yet");
1292
1293 // Don't crash if get passed a null pointer by accident.
1294 if (!II) {
1295 const char *S = "(null)";
1296 OutStr.append(S, S + strlen(S));
1297 continue;
1298 }
1299
1300 llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
1301 break;
1302 }
1313 getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
1314 StringRef(Modifier, ModifierLen),
1315 StringRef(Argument, ArgumentLen),
1316 FormattedArgs, OutStr, QualTypeVals);
1317 break;
1319 // Create a struct with all the info needed for printing.
1321 TDT.FromType = getRawArg(ArgNo);
1322 TDT.ToType = getRawArg(ArgNo2);
1323 TDT.ElideType = getDiags()->ElideType;
1324 TDT.ShowColors = getDiags()->ShowColors;
1325 TDT.TemplateDiffUsed = false;
1326 intptr_t val = reinterpret_cast<intptr_t>(&TDT);
1327
1328 const char *ArgumentEnd = Argument + ArgumentLen;
1329 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1330
1331 // Print the tree. If this diagnostic already has a tree, skip the
1332 // second tree.
1333 if (getDiags()->PrintTemplateTree && Tree.empty()) {
1334 TDT.PrintFromType = true;
1335 TDT.PrintTree = true;
1336 getDiags()->ConvertArgToString(Kind, val,
1337 StringRef(Modifier, ModifierLen),
1338 StringRef(Argument, ArgumentLen),
1339 FormattedArgs, Tree, QualTypeVals);
1340 // If there is no tree information, fall back to regular printing.
1341 if (!Tree.empty()) {
1342 FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr);
1343 break;
1344 }
1345 }
1346
1347 // Non-tree printing, also the fall-back when tree printing fails.
1348 // The fall-back is triggered when the types compared are not templates.
1349 const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');
1350 const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');
1351
1352 // Append before text
1353 FormatDiagnostic(Argument, FirstDollar, OutStr);
1354
1355 // Append first type
1356 TDT.PrintTree = false;
1357 TDT.PrintFromType = true;
1358 getDiags()->ConvertArgToString(Kind, val,
1359 StringRef(Modifier, ModifierLen),
1360 StringRef(Argument, ArgumentLen),
1361 FormattedArgs, OutStr, QualTypeVals);
1362 if (!TDT.TemplateDiffUsed)
1363 FormattedArgs.push_back(
1364 std::make_pair(DiagnosticsEngine::ak_qualtype, TDT.FromType));
1365
1366 // Append middle text
1367 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1368
1369 // Append second type
1370 TDT.PrintFromType = false;
1371 getDiags()->ConvertArgToString(Kind, val,
1372 StringRef(Modifier, ModifierLen),
1373 StringRef(Argument, ArgumentLen),
1374 FormattedArgs, OutStr, QualTypeVals);
1375 if (!TDT.TemplateDiffUsed)
1376 FormattedArgs.push_back(
1377 std::make_pair(DiagnosticsEngine::ak_qualtype, TDT.ToType));
1378
1379 // Append end text
1380 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1381 break;
1382 }
1383 }
1384
1385 // Remember this argument info for subsequent formatting operations. Turn
1386 // std::strings into a null terminated string to make it be the same case as
1387 // all the other ones.
1389 continue;
1390 else if (Kind != DiagnosticsEngine::ak_std_string)
1391 FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
1392 else
1393 FormattedArgs.push_back(
1394 std::make_pair(DiagnosticsEngine::ak_c_string,
1395 (intptr_t)getArgStdStr(ArgNo).c_str()));
1396 }
1397
1398 // Append the type tree to the end of the diagnostics.
1399 OutStr.append(Tree.begin(), Tree.end());
1400}
1401
1403 StringRef Message)
1404 : ID(ID), Level(Level), Message(Message) {}
1405
1407 const Diagnostic &Info)
1408 : ID(Info.getID()), Level(Level) {
1409 assert(
1410 (Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
1411 "Valid source location without setting a source manager for diagnostic");
1412 if (Info.getLocation().isValid())
1413 Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
1414 SmallString<64> Message;
1415 Info.FormatDiagnostic(Message);
1416 this->Message.assign(Message.begin(), Message.end());
1417 this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end());
1418 this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end());
1419}
1420
1422 StringRef Message, FullSourceLoc Loc,
1424 ArrayRef<FixItHint> FixIts)
1425 : ID(ID), Level(Level), Loc(Loc), Message(Message),
1426 Ranges(Ranges.begin(), Ranges.end()),
1427 FixIts(FixIts.begin(), FixIts.end()) {}
1428
1429llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
1430 const StoredDiagnostic &SD) {
1431 if (SD.getLocation().hasManager())
1432 OS << SD.getLocation().printToString(SD.getLocation().getManager()) << ": ";
1433 OS << SD.getMessage();
1434 return OS;
1435}
1436
1437/// IncludeInDiagnosticCounts - This method (whose default implementation
1438/// returns true) indicates whether the diagnostics handled by this
1439/// DiagnosticConsumer should be included in the number of diagnostics
1440/// reported by DiagnosticsEngine.
1442
1443void IgnoringDiagConsumer::anchor() {}
1444
1446
1448 DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
1449 Target.HandleDiagnostic(DiagLevel, Info);
1450}
1451
1454 Target.clear();
1455}
1456
1458 return Target.IncludeInDiagnosticCounts();
1459}
1460
1462 for (unsigned I = 0; I != NumCached; ++I)
1463 FreeList[I] = Cached + I;
1464 NumFreeListEntries = NumCached;
1465}
1466
1468 // Don't assert if we are in a CrashRecovery context, as this invariant may
1469 // be invalidated during a crash.
1470 assert((NumFreeListEntries == NumCached ||
1471 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1472 "A partial is on the lam");
1473}
1474
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