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