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,
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,
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,
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,
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,
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 // Find the longest glob pattern that matches FilePath amongst
521 // CategoriesToMatchers, return true iff the match exists and belongs to a
522 // positive category.
523 bool globsMatches(const llvm::StringMap<Matcher> &CategoriesToMatchers,
524 StringRef FilePath) const;
525
526 llvm::DenseMap<diag::kind, const Section *> DiagToSection;
527};
528} // namespace
529
530std::unique_ptr<WarningsSpecialCaseList>
531WarningsSpecialCaseList::create(const llvm::MemoryBuffer &Input,
532 std::string &Err) {
533 auto WarningSuppressionList = std::make_unique<WarningsSpecialCaseList>();
534 if (!WarningSuppressionList->createInternal(&Input, Err))
535 return nullptr;
536 return WarningSuppressionList;
537}
538
539void WarningsSpecialCaseList::processSections(DiagnosticsEngine &Diags) {
540 // Drop the default section introduced by special case list, we only support
541 // exact diagnostic group names.
542 // FIXME: We should make this configurable in the parser instead.
543 // FIXME: C++20 can use std::erase_if(Sections, [](Section &sec) { return
544 // sec.SectionStr == "*"; });
545 llvm::erase_if(Sections, [](Section &sec) { return sec.SectionStr == "*"; });
546 // Make sure we iterate sections by their line numbers.
547 std::vector<std::pair<unsigned, const Section *>> LineAndSectionEntry;
548 LineAndSectionEntry.reserve(Sections.size());
549 for (const auto &Entry : Sections) {
550 StringRef DiagName = Entry.SectionStr;
551 // Each section has a matcher with that section's name, attached to that
552 // line.
553 const auto &DiagSectionMatcher = Entry.SectionMatcher;
554 unsigned DiagLine = 0;
555 for (const auto &Glob : DiagSectionMatcher->Globs)
556 if (Glob->Name == DiagName) {
557 DiagLine = Glob->LineNo;
558 break;
559 }
560 LineAndSectionEntry.emplace_back(DiagLine, &Entry);
561 }
562 llvm::sort(LineAndSectionEntry);
563 static constexpr auto WarningFlavor = clang::diag::Flavor::WarningOrError;
564 for (const auto &[_, SectionEntry] : LineAndSectionEntry) {
565 SmallVector<diag::kind> GroupDiags;
566 StringRef DiagGroup = SectionEntry->SectionStr;
567 if (Diags.getDiagnosticIDs()->getDiagnosticsInGroup(
568 WarningFlavor, DiagGroup, GroupDiags)) {
569 StringRef Suggestion =
570 DiagnosticIDs::getNearestOption(WarningFlavor, DiagGroup);
571 Diags.Report(diag::warn_unknown_diag_option)
572 << static_cast<unsigned>(WarningFlavor) << DiagGroup
573 << !Suggestion.empty() << Suggestion;
574 continue;
575 }
576 for (diag::kind Diag : GroupDiags)
577 // We're intentionally overwriting any previous mappings here to make sure
578 // latest one takes precedence.
579 DiagToSection[Diag] = SectionEntry;
580 }
581}
582
583void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &Input) {
584 std::string Error;
585 auto WarningSuppressionList = WarningsSpecialCaseList::create(Input, Error);
586 if (!WarningSuppressionList) {
587 // FIXME: Use a `%select` statement instead of printing `Error` as-is. This
588 // should help localization.
589 Report(diag::err_drv_malformed_warning_suppression_mapping)
590 << Input.getBufferIdentifier() << Error;
591 return;
592 }
593 WarningSuppressionList->processSections(*this);
594 DiagSuppressionMapping =
595 [WarningSuppressionList(std::move(WarningSuppressionList))](
596 diag::kind DiagId, SourceLocation DiagLoc, const SourceManager &SM) {
597 return WarningSuppressionList->isDiagSuppressed(DiagId, DiagLoc, SM);
598 };
599}
600
601bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
602 SourceLocation DiagLoc,
603 const SourceManager &SM) const {
604 const Section *DiagSection = DiagToSection.lookup(DiagId);
605 if (!DiagSection)
606 return false;
607 const SectionEntries &EntityTypeToCategories = DiagSection->Entries;
608 auto SrcEntriesIt = EntityTypeToCategories.find("src");
609 if (SrcEntriesIt == EntityTypeToCategories.end())
610 return false;
611 const llvm::StringMap<llvm::SpecialCaseList::Matcher> &CategoriesToMatchers =
612 SrcEntriesIt->getValue();
613 // We also use presumed locations here to improve reproducibility for
614 // preprocessed inputs.
615 if (PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc); PLoc.isValid())
616 return globsMatches(
617 CategoriesToMatchers,
618 llvm::sys::path::remove_leading_dotslash(PLoc.getFilename()));
619 return false;
620}
621
622bool WarningsSpecialCaseList::globsMatches(
623 const llvm::StringMap<Matcher> &CategoriesToMatchers,
624 StringRef FilePath) const {
625 StringRef LongestMatch;
626 bool LongestIsPositive = false;
627 for (const auto &Entry : CategoriesToMatchers) {
628 StringRef Category = Entry.getKey();
629 const llvm::SpecialCaseList::Matcher &Matcher = Entry.getValue();
630 bool IsPositive = Category != "emit";
631 for (const auto &Glob : Matcher.Globs) {
632 if (Glob->Name.size() < LongestMatch.size())
633 continue;
634 if (!Glob->Pattern.match(FilePath))
635 continue;
636 LongestMatch = Glob->Name;
637 LongestIsPositive = IsPositive;
638 }
639 }
640 return LongestIsPositive;
641}
642
644 SourceLocation DiagLoc) const {
645 if (!hasSourceManager() || !DiagSuppressionMapping)
646 return false;
647 return DiagSuppressionMapping(DiagId, DiagLoc, getSourceManager());
648}
649
651 DiagnosticStorage DiagStorage;
652 DiagStorage.DiagRanges.append(storedDiag.range_begin(),
653 storedDiag.range_end());
654
655 DiagStorage.FixItHints.append(storedDiag.fixit_begin(),
656 storedDiag.fixit_end());
657
658 assert(Client && "DiagnosticConsumer not set!");
659 Level DiagLevel = storedDiag.getLevel();
660 Diagnostic Info(this, storedDiag.getLocation(), storedDiag.getID(),
661 DiagStorage, storedDiag.getMessage());
662 Report(DiagLevel, Info);
663}
664
665void DiagnosticsEngine::Report(Level DiagLevel, const Diagnostic &Info) {
666 assert(DiagLevel != Ignored && "Cannot emit ignored diagnostics!");
667 assert(!getDiagnosticIDs()->isTrapDiag(Info.getID()) &&
668 "Trap diagnostics should not be consumed by the DiagnosticsEngine");
669 Client->HandleDiagnostic(DiagLevel, Info);
670 if (Client->IncludeInDiagnosticCounts()) {
671 if (DiagLevel == Warning)
672 ++NumWarnings;
673 }
674}
675
676/// ProcessDiag - This is the method used to report a diagnostic that is
677/// finally fully formed.
678bool DiagnosticsEngine::ProcessDiag(const DiagnosticBuilder &DiagBuilder) {
679 Diagnostic Info(this, DiagBuilder);
680
681 assert(getClient() && "DiagnosticClient not set!");
682
683 // Figure out the diagnostic level of this message.
684 unsigned DiagID = Info.getID();
685 Level DiagLevel = getDiagnosticLevel(DiagID, Info.getLocation());
686
687 // Update counts for DiagnosticErrorTrap even if a fatal error occurred
688 // or diagnostics are suppressed.
689 if (DiagLevel >= Error) {
690 ++TrapNumErrorsOccurred;
691 if (Diags->isUnrecoverable(DiagID))
692 ++TrapNumUnrecoverableErrorsOccurred;
693 }
694
695 if (SuppressAllDiagnostics)
696 return false;
697
698 if (DiagLevel != Note) {
699 // Record that a fatal error occurred only when we see a second
700 // non-note diagnostic. This allows notes to be attached to the
701 // fatal error, but suppresses any diagnostics that follow those
702 // notes.
703 if (LastDiagLevel == Fatal)
704 FatalErrorOccurred = true;
705
706 LastDiagLevel = DiagLevel;
707 }
708
709 // If a fatal error has already been emitted, silence all subsequent
710 // diagnostics.
711 if (FatalErrorOccurred) {
712 if (DiagLevel >= Error && Client->IncludeInDiagnosticCounts())
713 ++NumErrors;
714
715 return false;
716 }
717
718 // If the client doesn't care about this message, don't issue it. If this is
719 // a note and the last real diagnostic was ignored, ignore it too.
720 if (DiagLevel == Ignored || (DiagLevel == Note && LastDiagLevel == Ignored))
721 return false;
722
723 if (DiagLevel >= Error) {
724 if (Diags->isUnrecoverable(DiagID))
725 UnrecoverableErrorOccurred = true;
726
727 // Warnings which have been upgraded to errors do not prevent compilation.
728 if (Diags->isDefaultMappingAsError(DiagID))
729 UncompilableErrorOccurred = true;
730
731 ErrorOccurred = true;
732 if (Client->IncludeInDiagnosticCounts())
733 ++NumErrors;
734
735 // If we've emitted a lot of errors, emit a fatal error instead of it to
736 // stop a flood of bogus errors.
737 if (ErrorLimit && NumErrors > ErrorLimit && DiagLevel == Error) {
738 Report(diag::fatal_too_many_errors);
739 return false;
740 }
741 }
742
743 // Make sure we set FatalErrorOccurred to ensure that the notes from the
744 // diagnostic that caused `fatal_too_many_errors` won't be emitted.
745 if (Info.getID() == diag::fatal_too_many_errors)
746 FatalErrorOccurred = true;
747
748 // Finally, report it.
749 Report(DiagLevel, Info);
750 return true;
751}
752
754 bool Force) {
755 assert(getClient() && "DiagnosticClient not set!");
756
757 bool Emitted;
758 if (Force) {
759 Diagnostic Info(this, DB);
760
761 // Figure out the diagnostic level of this message.
762 Level DiagLevel = getDiagnosticLevel(Info.getID(), Info.getLocation());
763
764 // Emit the diagnostic regardless of suppression level.
765 Emitted = DiagLevel != Ignored;
766 if (Emitted)
767 Report(DiagLevel, Info);
768 } else {
769 // Process the diagnostic, sending the accumulated information to the
770 // DiagnosticConsumer.
771 Emitted = ProcessDiag(DB);
772 }
773
774 return Emitted;
775}
776
777DiagnosticBuilder::DiagnosticBuilder(DiagnosticsEngine *DiagObj,
778 SourceLocation DiagLoc, unsigned DiagID)
779 : StreamingDiagnostic(DiagObj->DiagAllocator), DiagObj(DiagObj),
780 DiagLoc(DiagLoc), DiagID(DiagID), IsActive(true) {
781 assert(DiagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");
782}
783
784DiagnosticBuilder::DiagnosticBuilder(const DiagnosticBuilder &D)
786 DiagLoc = D.DiagLoc;
787 DiagID = D.DiagID;
788 FlagValue = D.FlagValue;
789 DiagObj = D.DiagObj;
790 DiagStorage = D.DiagStorage;
791 D.DiagStorage = nullptr;
792 Allocator = D.Allocator;
793 IsActive = D.IsActive;
794 IsForceEmit = D.IsForceEmit;
795 D.Clear();
796}
797
799 const DiagnosticBuilder &DiagBuilder)
800 : DiagObj(DO), DiagLoc(DiagBuilder.DiagLoc), DiagID(DiagBuilder.DiagID),
801 FlagValue(DiagBuilder.FlagValue), DiagStorage(*DiagBuilder.getStorage()) {
802}
803
805 unsigned DiagID, const DiagnosticStorage &DiagStorage,
806 StringRef StoredDiagMessage)
807 : DiagObj(DO), DiagLoc(DiagLoc), DiagID(DiagID), DiagStorage(DiagStorage),
808 StoredDiagMessage(StoredDiagMessage) {}
809
811
813 const Diagnostic &Info) {
815 return;
816
817 if (DiagLevel == DiagnosticsEngine::Warning)
818 ++NumWarnings;
819 else if (DiagLevel >= DiagnosticsEngine::Error)
820 ++NumErrors;
821}
822
823/// ModifierIs - Return true if the specified modifier matches specified string.
824template <std::size_t StrLen>
825static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
826 const char (&Str)[StrLen]) {
827 return StrLen - 1 == ModifierLen && memcmp(Modifier, Str, StrLen - 1) == 0;
828}
829
830/// ScanForward - Scans forward, looking for the given character, skipping
831/// nested clauses and escaped characters.
832static const char *ScanFormat(const char *I, const char *E, char Target) {
833 unsigned Depth = 0;
834
835 for (; I != E; ++I) {
836 if (Depth == 0 && *I == Target)
837 return I;
838 if (Depth != 0 && *I == '}')
839 Depth--;
840
841 if (*I == '%') {
842 I++;
843 if (I == E)
844 break;
845
846 // Escaped characters get implicitly skipped here.
847
848 // Format specifier.
849 if (!isDigit(*I) && !isPunctuation(*I)) {
850 for (I++; I != E && !isDigit(*I) && *I != '{'; I++)
851 ;
852 if (I == E)
853 break;
854 if (*I == '{')
855 Depth++;
856 }
857 }
858 }
859 return E;
860}
861
862/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
863/// like this: %select{foo|bar|baz}2. This means that the integer argument
864/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
865/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
866/// This is very useful for certain classes of variant diagnostics.
867static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
868 const char *Argument, unsigned ArgumentLen,
869 SmallVectorImpl<char> &OutStr) {
870 const char *ArgumentEnd = Argument + ArgumentLen;
871
872 // Skip over 'ValNo' |'s.
873 while (ValNo) {
874 const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
875 assert(NextVal != ArgumentEnd &&
876 "Value for integer select modifier was"
877 " larger than the number of options in the diagnostic string!");
878 Argument = NextVal + 1; // Skip this string.
879 --ValNo;
880 }
881
882 // Get the end of the value. This is either the } or the |.
883 const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
884
885 // Recursively format the result of the select clause into the output string.
886 DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
887}
888
889/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
890/// letter 's' to the string if the value is not 1. This is used in cases like
891/// this: "you idiot, you have %4 parameter%s4!".
892static void HandleIntegerSModifier(unsigned ValNo,
893 SmallVectorImpl<char> &OutStr) {
894 if (ValNo != 1)
895 OutStr.push_back('s');
896}
897
898/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
899/// prints the ordinal form of the given integer, with 1 corresponding
900/// to the first ordinal. Currently this is hard-coded to use the
901/// English form.
902static void HandleOrdinalModifier(unsigned ValNo,
903 SmallVectorImpl<char> &OutStr) {
904 assert(ValNo != 0 && "ValNo must be strictly positive!");
905
906 llvm::raw_svector_ostream Out(OutStr);
907
908 // We could use text forms for the first N ordinals, but the numeric
909 // forms are actually nicer in diagnostics because they stand out.
910 Out << ValNo << llvm::getOrdinalSuffix(ValNo);
911}
912
913// 123 -> "123".
914// 1234 -> "1.23k".
915// 123456 -> "123.46k".
916// 1234567 -> "1.23M".
917// 1234567890 -> "1.23G".
918// 1234567890123 -> "1.23T".
919static void HandleIntegerHumanModifier(int64_t ValNo,
920 SmallVectorImpl<char> &OutStr) {
921 static constexpr std::array<std::pair<int64_t, char>, 4> Units = {
922 {{1'000'000'000'000L, 'T'},
923 {1'000'000'000L, 'G'},
924 {1'000'000L, 'M'},
925 {1'000L, 'k'}}};
926
927 llvm::raw_svector_ostream Out(OutStr);
928 if (ValNo < 0) {
929 Out << "-";
930 ValNo = -ValNo;
931 }
932 for (const auto &[UnitSize, UnitSign] : Units) {
933 if (ValNo >= UnitSize) {
934 Out << llvm::format("%0.2f%c", ValNo / static_cast<double>(UnitSize),
935 UnitSign);
936 return;
937 }
938 }
939 Out << ValNo;
940}
941
942/// PluralNumber - Parse an unsigned integer and advance Start.
943static unsigned PluralNumber(const char *&Start, const char *End) {
944 // Programming 101: Parse a decimal number :-)
945 unsigned Val = 0;
946 while (Start != End && *Start >= '0' && *Start <= '9') {
947 Val *= 10;
948 Val += *Start - '0';
949 ++Start;
950 }
951 return Val;
952}
953
954/// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
955static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
956 if (*Start != '[') {
957 unsigned Ref = PluralNumber(Start, End);
958 return Ref == Val;
959 }
960
961 ++Start;
962 unsigned Low = PluralNumber(Start, End);
963 assert(*Start == ',' && "Bad plural expression syntax: expected ,");
964 ++Start;
965 unsigned High = PluralNumber(Start, End);
966 assert(*Start == ']' && "Bad plural expression syntax: expected )");
967 ++Start;
968 return Low <= Val && Val <= High;
969}
970
971/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
972static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
973 // Empty condition?
974 if (*Start == ':')
975 return true;
976
977 while (true) {
978 char C = *Start;
979 if (C == '%') {
980 // Modulo expression
981 ++Start;
982 unsigned Arg = PluralNumber(Start, End);
983 assert(*Start == '=' && "Bad plural expression syntax: expected =");
984 ++Start;
985 unsigned ValMod = ValNo % Arg;
986 if (TestPluralRange(ValMod, Start, End))
987 return true;
988 } else {
989 assert((C == '[' || (C >= '0' && C <= '9')) &&
990 "Bad plural expression syntax: unexpected character");
991 // Range expression
992 if (TestPluralRange(ValNo, Start, End))
993 return true;
994 }
995
996 // Scan for next or-expr part.
997 Start = std::find(Start, End, ',');
998 if (Start == End)
999 break;
1000 ++Start;
1001 }
1002 return false;
1003}
1004
1005/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
1006/// for complex plural forms, or in languages where all plurals are complex.
1007/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
1008/// conditions that are tested in order, the form corresponding to the first
1009/// that applies being emitted. The empty condition is always true, making the
1010/// last form a default case.
1011/// Conditions are simple boolean expressions, where n is the number argument.
1012/// Here are the rules.
1013/// condition := expression | empty
1014/// empty := -> always true
1015/// expression := numeric [',' expression] -> logical or
1016/// numeric := range -> true if n in range
1017/// | '%' number '=' range -> true if n % number in range
1018/// range := number
1019/// | '[' number ',' number ']' -> ranges are inclusive both ends
1020///
1021/// Here are some examples from the GNU gettext manual written in this form:
1022/// English:
1023/// {1:form0|:form1}
1024/// Latvian:
1025/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
1026/// Gaeilge:
1027/// {1:form0|2:form1|:form2}
1028/// Romanian:
1029/// {1:form0|0,%100=[1,19]:form1|:form2}
1030/// Lithuanian:
1031/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
1032/// Russian (requires repeated form):
1033/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
1034/// Slovak
1035/// {1:form0|[2,4]:form1|:form2}
1036/// Polish (requires repeated form):
1037/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
1038static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
1039 const char *Argument, unsigned ArgumentLen,
1040 SmallVectorImpl<char> &OutStr) {
1041 const char *ArgumentEnd = Argument + ArgumentLen;
1042 while (true) {
1043 assert(Argument < ArgumentEnd && "Plural expression didn't match.");
1044 const char *ExprEnd = Argument;
1045 while (*ExprEnd != ':') {
1046 assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
1047 ++ExprEnd;
1048 }
1049 if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
1050 Argument = ExprEnd + 1;
1051 ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
1052
1053 // Recursively format the result of the plural clause into the
1054 // output string.
1055 DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
1056 return;
1057 }
1058 Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
1059 }
1060}
1061
1062/// Returns the friendly description for a token kind that will appear
1063/// without quotes in diagnostic messages. These strings may be translatable in
1064/// future.
1066 switch (Kind) {
1067 case tok::identifier:
1068 return "identifier";
1069 default:
1070 return nullptr;
1071 }
1072}
1073
1074/// FormatDiagnostic - Format this diagnostic into a string, substituting the
1075/// formal arguments into the %0 slots. The result is appended onto the Str
1076/// array.
1078 if (StoredDiagMessage.has_value()) {
1079 OutStr.append(StoredDiagMessage->begin(), StoredDiagMessage->end());
1080 return;
1081 }
1082
1083 StringRef Diag = getDiags()->getDiagnosticIDs()->getDescription(getID());
1084
1085 FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
1086}
1087
1088/// EscapeStringForDiagnostic - Append Str to the diagnostic buffer,
1089/// escaping non-printable characters and ill-formed code unit sequences.
1091 SmallVectorImpl<char> &OutStr) {
1092 OutStr.reserve(OutStr.size() + Str.size());
1093 auto *Begin = reinterpret_cast<const unsigned char *>(Str.data());
1094 llvm::raw_svector_ostream OutStream(OutStr);
1095 const unsigned char *End = Begin + Str.size();
1096 while (Begin != End) {
1097 // ASCII case
1098 if (isPrintable(*Begin) || isWhitespace(*Begin)) {
1099 OutStream << *Begin;
1100 ++Begin;
1101 continue;
1102 }
1103 if (llvm::isLegalUTF8Sequence(Begin, End)) {
1104 llvm::UTF32 CodepointValue;
1105 llvm::UTF32 *CpPtr = &CodepointValue;
1106 const unsigned char *CodepointBegin = Begin;
1107 const unsigned char *CodepointEnd =
1108 Begin + llvm::getNumBytesForUTF8(*Begin);
1109 llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(
1110 &Begin, CodepointEnd, &CpPtr, CpPtr + 1, llvm::strictConversion);
1111 (void)Res;
1112 assert(
1113 llvm::conversionOK == Res &&
1114 "the sequence is legal UTF-8 but we couldn't convert it to UTF-32");
1115 assert(Begin == CodepointEnd &&
1116 "we must be further along in the string now");
1117 if (llvm::sys::unicode::isPrintable(CodepointValue) ||
1118 llvm::sys::unicode::isFormatting(CodepointValue)) {
1119 OutStr.append(CodepointBegin, CodepointEnd);
1120 continue;
1121 }
1122 // Unprintable code point.
1123 OutStream << "<U+" << llvm::format_hex_no_prefix(CodepointValue, 4, true)
1124 << ">";
1125 continue;
1126 }
1127 // Invalid code unit.
1128 OutStream << "<" << llvm::format_hex_no_prefix(*Begin, 2, true) << ">";
1129 ++Begin;
1130 }
1131}
1132
1133void Diagnostic::FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
1134 SmallVectorImpl<char> &OutStr) const {
1135 // When the diagnostic string is only "%0", the entire string is being given
1136 // by an outside source. Remove unprintable characters from this string
1137 // and skip all the other string processing.
1138 if (DiagEnd - DiagStr == 2 && StringRef(DiagStr, DiagEnd - DiagStr) == "%0" &&
1140 const std::string &S = getArgStdStr(0);
1141 EscapeStringForDiagnostic(S, OutStr);
1142 return;
1143 }
1144
1145 /// FormattedArgs - Keep track of all of the arguments formatted by
1146 /// ConvertArgToString and pass them into subsequent calls to
1147 /// ConvertArgToString, allowing the implementation to avoid redundancies in
1148 /// obvious cases.
1150
1151 /// QualTypeVals - Pass a vector of arrays so that QualType names can be
1152 /// compared to see if more information is needed to be printed.
1153 SmallVector<intptr_t, 2> QualTypeVals;
1155
1156 for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
1158 QualTypeVals.push_back(getRawArg(i));
1159
1160 while (DiagStr != DiagEnd) {
1161 if (DiagStr[0] != '%') {
1162 // Append non-%0 substrings to Str if we have one.
1163 const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
1164 OutStr.append(DiagStr, StrEnd);
1165 DiagStr = StrEnd;
1166 continue;
1167 } else if (isPunctuation(DiagStr[1])) {
1168 OutStr.push_back(DiagStr[1]); // %% -> %.
1169 DiagStr += 2;
1170 continue;
1171 }
1172
1173 // Skip the %.
1174 ++DiagStr;
1175
1176 // This must be a placeholder for a diagnostic argument. The format for a
1177 // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
1178 // The digit is a number from 0-9 indicating which argument this comes from.
1179 // The modifier is a string of digits from the set [-a-z]+, arguments is a
1180 // brace enclosed string.
1181 const char *Modifier = nullptr, *Argument = nullptr;
1182 unsigned ModifierLen = 0, ArgumentLen = 0;
1183
1184 // Check to see if we have a modifier. If so eat it.
1185 if (!isDigit(DiagStr[0])) {
1186 Modifier = DiagStr;
1187 while (DiagStr[0] == '-' || (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
1188 ++DiagStr;
1189 ModifierLen = DiagStr - Modifier;
1190
1191 // If we have an argument, get it next.
1192 if (DiagStr[0] == '{') {
1193 ++DiagStr; // Skip {.
1194 Argument = DiagStr;
1195
1196 DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
1197 assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
1198 ArgumentLen = DiagStr - Argument;
1199 ++DiagStr; // Skip }.
1200 }
1201 }
1202
1203 assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
1204 unsigned ArgNo = *DiagStr++ - '0';
1205
1206 // Only used for type diffing.
1207 unsigned ArgNo2 = ArgNo;
1208
1210 if (ModifierIs(Modifier, ModifierLen, "diff")) {
1211 assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
1212 "Invalid format for diff modifier");
1213 ++DiagStr; // Comma.
1214 ArgNo2 = *DiagStr++ - '0';
1216 if (Kind == DiagnosticsEngine::ak_qualtype &&
1219 else {
1220 // %diff only supports QualTypes. For other kinds of arguments,
1221 // use the default printing. For example, if the modifier is:
1222 // "%diff{compare $ to $|other text}1,2"
1223 // treat it as:
1224 // "compare %1 to %2"
1225 const char *ArgumentEnd = Argument + ArgumentLen;
1226 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1227 assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd &&
1228 "Found too many '|'s in a %diff modifier!");
1229 const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
1230 const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
1231 const char ArgStr1[] = {'%', static_cast<char>('0' + ArgNo)};
1232 const char ArgStr2[] = {'%', static_cast<char>('0' + ArgNo2)};
1233 FormatDiagnostic(Argument, FirstDollar, OutStr);
1234 FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
1235 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1236 FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
1237 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1238 continue;
1239 }
1240 }
1241
1242 switch (Kind) {
1243 // ---- STRINGS ----
1246 StringRef S = [&]() -> StringRef {
1248 return getArgStdStr(ArgNo);
1249 const char *SZ = getArgCStr(ArgNo);
1250 // Don't crash if get passed a null pointer by accident.
1251 return SZ ? SZ : "(null)";
1252 }();
1253 bool Quoted = false;
1254 if (ModifierIs(Modifier, ModifierLen, "quoted")) {
1255 Quoted = true;
1256 OutStr.push_back('\'');
1257 } else {
1258 assert(ModifierLen == 0 && "unknown modifier for string");
1259 }
1260 EscapeStringForDiagnostic(S, OutStr);
1261 if (Quoted)
1262 OutStr.push_back('\'');
1263 break;
1264 }
1265 // ---- INTEGERS ----
1267 int64_t Val = getArgSInt(ArgNo);
1268
1269 if (ModifierIs(Modifier, ModifierLen, "select")) {
1270 HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1271 OutStr);
1272 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1273 HandleIntegerSModifier(Val, OutStr);
1274 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1275 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1276 OutStr);
1277 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1278 HandleOrdinalModifier((unsigned)Val, OutStr);
1279 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1280 HandleIntegerHumanModifier(Val, OutStr);
1281 } else {
1282 assert(ModifierLen == 0 && "Unknown integer modifier");
1283 llvm::raw_svector_ostream(OutStr) << Val;
1284 }
1285 break;
1286 }
1288 uint64_t Val = getArgUInt(ArgNo);
1289
1290 if (ModifierIs(Modifier, ModifierLen, "select")) {
1291 HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
1292 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1293 HandleIntegerSModifier(Val, OutStr);
1294 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1295 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1296 OutStr);
1297 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1298 HandleOrdinalModifier(Val, OutStr);
1299 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1300 HandleIntegerHumanModifier(Val, OutStr);
1301 } else {
1302 assert(ModifierLen == 0 && "Unknown integer modifier");
1303 llvm::raw_svector_ostream(OutStr) << Val;
1304 }
1305 break;
1306 }
1307 // ---- TOKEN SPELLINGS ----
1309 tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo));
1310 assert(ModifierLen == 0 && "No modifiers for token kinds yet");
1311
1312 llvm::raw_svector_ostream Out(OutStr);
1313 if (const char *S = tok::getPunctuatorSpelling(Kind))
1314 // Quoted token spelling for punctuators.
1315 Out << '\'' << S << '\'';
1316 else if ((S = tok::getKeywordSpelling(Kind)))
1317 // Unquoted token spelling for keywords.
1318 Out << S;
1319 else if ((S = getTokenDescForDiagnostic(Kind)))
1320 // Unquoted translatable token name.
1321 Out << S;
1322 else if ((S = tok::getTokenName(Kind)))
1323 // Debug name, shouldn't appear in user-facing diagnostics.
1324 Out << '<' << S << '>';
1325 else
1326 Out << "(null)";
1327 break;
1328 }
1329 // ---- NAMES and TYPES ----
1331 const IdentifierInfo *II = getArgIdentifier(ArgNo);
1332 assert(ModifierLen == 0 && "No modifiers for strings yet");
1333
1334 // Don't crash if get passed a null pointer by accident.
1335 if (!II) {
1336 const char *S = "(null)";
1337 OutStr.append(S, S + strlen(S));
1338 continue;
1339 }
1340
1341 llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
1342 break;
1343 }
1354 getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
1355 StringRef(Modifier, ModifierLen),
1356 StringRef(Argument, ArgumentLen),
1357 FormattedArgs, OutStr, QualTypeVals);
1358 break;
1360 // Create a struct with all the info needed for printing.
1362 TDT.FromType = getRawArg(ArgNo);
1363 TDT.ToType = getRawArg(ArgNo2);
1364 TDT.ElideType = getDiags()->ElideType;
1365 TDT.ShowColors = getDiags()->ShowColors;
1366 TDT.TemplateDiffUsed = false;
1367 intptr_t val = reinterpret_cast<intptr_t>(&TDT);
1368
1369 const char *ArgumentEnd = Argument + ArgumentLen;
1370 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1371
1372 // Print the tree. If this diagnostic already has a tree, skip the
1373 // second tree.
1374 if (getDiags()->PrintTemplateTree && Tree.empty()) {
1375 TDT.PrintFromType = true;
1376 TDT.PrintTree = true;
1377 getDiags()->ConvertArgToString(Kind, val,
1378 StringRef(Modifier, ModifierLen),
1379 StringRef(Argument, ArgumentLen),
1380 FormattedArgs, Tree, QualTypeVals);
1381 // If there is no tree information, fall back to regular printing.
1382 if (!Tree.empty()) {
1383 FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr);
1384 break;
1385 }
1386 }
1387
1388 // Non-tree printing, also the fall-back when tree printing fails.
1389 // The fall-back is triggered when the types compared are not templates.
1390 const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');
1391 const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');
1392
1393 // Append before text
1394 FormatDiagnostic(Argument, FirstDollar, OutStr);
1395
1396 // Append first type
1397 TDT.PrintTree = false;
1398 TDT.PrintFromType = true;
1399 getDiags()->ConvertArgToString(Kind, val,
1400 StringRef(Modifier, ModifierLen),
1401 StringRef(Argument, ArgumentLen),
1402 FormattedArgs, OutStr, QualTypeVals);
1403 if (!TDT.TemplateDiffUsed)
1404 FormattedArgs.push_back(
1405 std::make_pair(DiagnosticsEngine::ak_qualtype, TDT.FromType));
1406
1407 // Append middle text
1408 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1409
1410 // Append second type
1411 TDT.PrintFromType = false;
1412 getDiags()->ConvertArgToString(Kind, val,
1413 StringRef(Modifier, ModifierLen),
1414 StringRef(Argument, ArgumentLen),
1415 FormattedArgs, OutStr, QualTypeVals);
1416 if (!TDT.TemplateDiffUsed)
1417 FormattedArgs.push_back(
1418 std::make_pair(DiagnosticsEngine::ak_qualtype, TDT.ToType));
1419
1420 // Append end text
1421 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1422 break;
1423 }
1424 }
1425
1426 // Remember this argument info for subsequent formatting operations. Turn
1427 // std::strings into a null terminated string to make it be the same case as
1428 // all the other ones.
1430 continue;
1431 else if (Kind != DiagnosticsEngine::ak_std_string)
1432 FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
1433 else
1434 FormattedArgs.push_back(
1435 std::make_pair(DiagnosticsEngine::ak_c_string,
1436 (intptr_t)getArgStdStr(ArgNo).c_str()));
1437 }
1438
1439 // Append the type tree to the end of the diagnostics.
1440 OutStr.append(Tree.begin(), Tree.end());
1441}
1442
1444 StringRef Message)
1445 : ID(ID), Level(Level), Message(Message) {}
1446
1448 const Diagnostic &Info)
1449 : ID(Info.getID()), Level(Level) {
1450 assert(
1451 (Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
1452 "Valid source location without setting a source manager for diagnostic");
1453 if (Info.getLocation().isValid())
1455 SmallString<64> Message;
1456 Info.FormatDiagnostic(Message);
1457 this->Message.assign(Message.begin(), Message.end());
1458 this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end());
1459 this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end());
1460}
1461
1463 StringRef Message, FullSourceLoc Loc,
1465 ArrayRef<FixItHint> FixIts)
1466 : ID(ID), Level(Level), Loc(Loc), Message(Message),
1467 Ranges(Ranges.begin(), Ranges.end()),
1468 FixIts(FixIts.begin(), FixIts.end()) {}
1469
1470llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
1471 const StoredDiagnostic &SD) {
1472 if (SD.getLocation().hasManager())
1473 OS << SD.getLocation().printToString(SD.getLocation().getManager()) << ": ";
1474 OS << SD.getMessage();
1475 return OS;
1476}
1477
1478/// IncludeInDiagnosticCounts - This method (whose default implementation
1479/// returns true) indicates whether the diagnostics handled by this
1480/// DiagnosticConsumer should be included in the number of diagnostics
1481/// reported by DiagnosticsEngine.
1483
1484void IgnoringDiagConsumer::anchor() {}
1485
1487
1489 DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
1490 Target.HandleDiagnostic(DiagLevel, Info);
1491}
1492
1495 Target.clear();
1496}
1497
1499 return Target.IncludeInDiagnosticCounts();
1500}
1501
1503 for (unsigned I = 0; I != NumCached; ++I)
1504 FreeList[I] = Cached + I;
1505 NumFreeListEntries = NumCached;
1506}
1507
1509 // Don't assert if we are in a CrashRecovery context, as this invariant may
1510 // be invalidated during a crash.
1511 assert((NumFreeListEntries == NumCached ||
1512 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1513 "A partial is on the lam");
1514}
1515
SyntaxTree::Impl & Tree
Definition: ASTDiff.cpp:192
StringRef P
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...
Definition: Diagnostic.cpp:832
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.
Definition: Diagnostic.cpp:892
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)
Definition: Diagnostic.cpp:68
static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End)
EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
Definition: Diagnostic.cpp:972
static void HandleIntegerHumanModifier(int64_t ValNo, SmallVectorImpl< char > &OutStr)
Definition: Diagnostic.cpp:919
static unsigned PluralNumber(const char *&Start, const char *End)
PluralNumber - Parse an unsigned integer and advance Start.
Definition: Diagnostic.cpp:943
static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, SmallVectorImpl< char > &OutStr)
HandleSelectModifier - Handle the integer 'select' modifier.
Definition: Diagnostic.cpp:867
static bool ModifierIs(const char *Modifier, unsigned ModifierLen, const char(&Str)[StrLen])
ModifierIs - Return true if the specified modifier matches specified string.
Definition: Diagnostic.cpp:825
static bool TestPluralRange(unsigned Val, const char *&Start, const char *End)
TestPluralRange - Test if Val is in the parsed range. Modifies Start.
Definition: Diagnostic.cpp:955
static void HandleOrdinalModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)
HandleOrdinalModifier - Handle the integer 'ord' modifier.
Definition: Diagnostic.cpp:902
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)
Definition: CGObjCMac.cpp:6347
const Decl * D
Expr * E
Defines the Diagnostic IDs-related interfaces.
int Category
Definition: Format.cpp:3180
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)
Definition: OffloadArch.cpp:16
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
SourceRange Range
Definition: SemaObjC.cpp:753
SourceLocation Loc
Definition: SemaObjC.cpp:754
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.
SourceLocation Begin
A little helper class used to produce diagnostics.
Definition: Diagnostic.h:1233
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1722
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.
Definition: Diagnostic.cpp:812
unsigned NumErrors
Number of errors reported.
Definition: Diagnostic.h:1725
unsigned NumWarnings
Number of warnings reported.
Definition: Diagnostic.h:1724
virtual bool IncludeInDiagnosticCounts() const
Indicates whether the diagnostics handled by this DiagnosticConsumer should be included in the number...
static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group)
Get the diagnostic option with the closest edit distance to the given group name.
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...
Definition: Diagnostic.h:1548
Diagnostic(const DiagnosticsEngine *DO, const DiagnosticBuilder &DiagBuilder)
Definition: Diagnostic.cpp:798
const SourceLocation & getLocation() const
Definition: Diagnostic.h:1564
const std::string & getArgStdStr(unsigned Idx) const
Return the provided argument string specified by Idx.
Definition: Diagnostic.h:1585
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.
Definition: Diagnostic.h:1626
const char * getArgCStr(unsigned Idx) const
Return the specified C string argument.
Definition: Diagnostic.h:1593
const IdentifierInfo * getArgIdentifier(unsigned Idx) const
Return the specified IdentifierInfo argument.
Definition: Diagnostic.h:1617
SourceManager & getSourceManager() const
Definition: Diagnostic.h:1566
ArrayRef< FixItHint > getFixItHints() const
Definition: Diagnostic.h:1651
unsigned getNumArgs() const
Definition: Diagnostic.h:1570
bool hasSourceManager() const
Definition: Diagnostic.h:1565
unsigned getID() const
Definition: Diagnostic.h:1563
DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const
Return the kind of the specified index.
Definition: Diagnostic.h:1578
int64_t getArgSInt(unsigned Idx) const
Return the specified signed integer argument.
Definition: Diagnostic.h:1601
uint64_t getArgUInt(unsigned Idx) const
Return the specified unsigned integer argument.
Definition: Diagnostic.h:1609
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic's ranges.
Definition: Diagnostic.h:1642
const DiagnosticsEngine * getDiags() const
Definition: Diagnostic.h:1562
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:231
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1529
bool hasSourceManager() const
Definition: Diagnostic.h:616
bool EmitDiagnostic(const DiagnosticBuilder &DB, bool Force=false)
Emit the diagnostic.
Definition: Diagnostic.cpp:753
void setDiagSuppressionMapping(llvm::MemoryBuffer &Input)
Diagnostic suppression mappings can be used to suppress specific diagnostics in specific files.
Definition: Diagnostic.cpp:583
DiagnosticsEngine(IntrusiveRefCntPtr< DiagnosticIDs > Diags, DiagnosticOptions &DiagOpts, DiagnosticConsumer *client=nullptr, bool ShouldOwnClient=true)
Definition: Diagnostic.cpp:77
bool isSuppressedViaMapping(diag::kind DiagId, SourceLocation DiagLoc) const
Definition: Diagnostic.cpp:643
void setSeverityForAll(diag::Flavor Flavor, diag::Severity Map, SourceLocation Loc=SourceLocation())
Add the specified mapping to all diagnostics of the specified flavor.
Definition: Diagnostic.cpp:489
LLVM_DUMP_METHOD void dump() const
Definition: Diagnostic.cpp:94
void ResetPragmas()
We keep a cache of FileIDs for diagnostics mapped by pragmas.
Definition: Diagnostic.cpp:122
void setClient(DiagnosticConsumer *client, bool ShouldOwnClient=true)
Set the diagnostic client associated with this diagnostic object.
Definition: Diagnostic.cpp:100
SourceManager & getSourceManager() const
Definition: Diagnostic.h:618
void pushMappings(SourceLocation Loc)
Copies the current DiagMappings and pushes the new copy onto the top of the stack.
Definition: Diagnostic.cpp:106
void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc)
This allows the client to specify that certain warnings are ignored.
Definition: Diagnostic.cpp:355
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:236
DiagnosticConsumer * getClient()
Definition: Diagnostic.h:606
@ ak_nameddecl
NamedDecl *.
Definition: Diagnostic.h:277
@ ak_declcontext
DeclContext *.
Definition: Diagnostic.h:283
@ ak_addrspace
address space
Definition: Diagnostic.h:265
@ ak_identifierinfo
IdentifierInfo.
Definition: Diagnostic.h:262
@ ak_qualtype_pair
pair<QualType, QualType>
Definition: Diagnostic.h:286
@ ak_attr_info
AttributeCommonInfo *.
Definition: Diagnostic.h:295
@ ak_c_string
const char *
Definition: Diagnostic.h:250
@ ak_declarationname
DeclarationName.
Definition: Diagnostic.h:274
@ ak_tokenkind
enum TokenKind : unsigned
Definition: Diagnostic.h:259
@ ak_std_string
std::string
Definition: Diagnostic.h:247
@ ak_nestednamespec
NestedNameSpecifier *.
Definition: Diagnostic.h:280
Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const
Based on the way the client configured the DiagnosticsEngine object, classify the specified diagnosti...
Definition: Diagnostic.h:965
bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled)
Set the error-as-fatal flag for the given diagnostic group.
Definition: Diagnostic.cpp:458
bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled)
Set the warning-as-error flag for the given diagnostic group.
Definition: Diagnostic.cpp:426
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:911
bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group, diag::Severity Map, SourceLocation Loc=SourceLocation())
Change an entire diagnostic group (e.g.
Definition: Diagnostic.cpp:401
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...
Definition: Diagnostic.cpp:110
const IntrusiveRefCntPtr< DiagnosticIDs > & getDiagnosticIDs() const
Definition: Diagnostic.h:591
void Reset(bool soft=false)
Reset the state of the diagnostic object to its initial configuration.
Definition: Diagnostic.cpp:124
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
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.
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...
Definition: Diagnostic.h:1672
unsigned getID() const
Definition: Diagnostic.h:1693
range_iterator range_begin() const
Definition: Diagnostic.h:1702
DiagnosticsEngine::Level getLevel() const
Definition: Diagnostic.h:1694
fixit_iterator fixit_begin() const
Definition: Diagnostic.h:1710
const FullSourceLoc & getLocation() const
Definition: Diagnostic.h:1695
range_iterator range_end() const
Definition: Diagnostic.h:1703
StringRef getMessage() const
Definition: Diagnostic.h:1696
fixit_iterator fixit_end() const
Definition: Diagnostic.h:1711
The streaming interface shared between DiagnosticBuilder and PartialDiagnostic.
Definition: Diagnostic.h:1115
DiagStorageAllocator * Allocator
Allocator used to allocate storage for this diagnostic.
Definition: Diagnostic.h:1123
DiagnosticStorage * DiagStorage
Definition: Diagnostic.h:1120
void AddString(StringRef V) const
Definition: Diagnostic.h:1166
Flavor
Flavors of diagnostics we can emit.
Definition: DiagnosticIDs.h:93
@ WarningOrError
A diagnostic that indicates a problem or potential problem.
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...
Definition: DiagnosticIDs.h:82
@ 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.
Definition: TokenKinds.cpp:24
const char * getKeywordSpelling(TokenKind Kind) LLVM_READNONE
Determines the spelling of simple keyword and contextual keyword tokens like 'int' and 'dynamic_cast'...
Definition: TokenKinds.cpp:40
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 '!' or '', and returns NULL for literal and...
Definition: TokenKinds.cpp:31
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
const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ASTContext::SectionInfo &Section)
Insertion operator for diagnostics.
@ Result
The result type of a method or function.
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
std::pair< NullabilityKind, bool > DiagNullabilityKind
A nullability kind paired with a bit indicating whether it used a context-sensitive keyword.
Definition: Diagnostic.h:1524
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:181
SmallVector< FixItHint, 6 > FixItHints
If valid, provides a hint with some code to insert, remove, or modify at a particular position.
Definition: Diagnostic.h:185