clang 20.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
26#include "llvm/ADT/IntrusiveRefCntPtr.h"
27#include "llvm/ADT/SmallString.h"
28#include "llvm/ADT/SmallVector.h"
29#include "llvm/ADT/StringExtras.h"
30#include "llvm/ADT/StringMap.h"
31#include "llvm/ADT/StringRef.h"
32#include "llvm/Support/ConvertUTF.h"
33#include "llvm/Support/CrashRecoveryContext.h"
34#include "llvm/Support/Error.h"
35#include "llvm/Support/MemoryBuffer.h"
36#include "llvm/Support/SpecialCaseList.h"
37#include "llvm/Support/Unicode.h"
38#include "llvm/Support/VirtualFileSystem.h"
39#include "llvm/Support/raw_ostream.h"
40#include <algorithm>
41#include <cassert>
42#include <cstddef>
43#include <cstdint>
44#include <cstring>
45#include <limits>
46#include <memory>
47#include <string>
48#include <utility>
49#include <vector>
50
51using namespace clang;
52
54 DiagNullabilityKind nullability) {
55 DB.AddString(
56 ("'" +
57 getNullabilitySpelling(nullability.first,
58 /*isContextSensitive=*/nullability.second) +
59 "'")
60 .str());
61 return DB;
62}
63
65 llvm::Error &&E) {
66 DB.AddString(toString(std::move(E)));
67 return DB;
68}
69
71 StringRef Modifier, StringRef Argument,
74 void *Cookie,
75 ArrayRef<intptr_t> QualTypeVals) {
76 StringRef Str = "<can't format argument>";
77 Output.append(Str.begin(), Str.end());
78}
79
83 bool ShouldOwnClient)
84 : Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) {
85 setClient(client, ShouldOwnClient);
86 ArgToStringFn = DummyArgToStringFn;
87
88 Reset();
89}
90
92 // If we own the diagnostic client, destroy it first so that it can access the
93 // engine from its destructor.
94 setClient(nullptr);
95}
96
98 DiagStatesByLoc.dump(*SourceMgr);
99}
100
101void DiagnosticsEngine::dump(StringRef DiagName) const {
102 DiagStatesByLoc.dump(*SourceMgr, DiagName);
103}
104
106 bool ShouldOwnClient) {
107 Owner.reset(ShouldOwnClient ? client : nullptr);
108 Client = client;
109}
110
112 DiagStateOnPushStack.push_back(GetCurDiagState());
113}
114
116 if (DiagStateOnPushStack.empty())
117 return false;
118
119 if (DiagStateOnPushStack.back() != GetCurDiagState()) {
120 // State changed at some point between push/pop.
121 PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
122 }
123 DiagStateOnPushStack.pop_back();
124 return true;
125}
126
127void DiagnosticsEngine::Reset(bool soft /*=false*/) {
128 ErrorOccurred = false;
129 UncompilableErrorOccurred = false;
130 FatalErrorOccurred = false;
131 UnrecoverableErrorOccurred = false;
132
133 NumWarnings = 0;
134 NumErrors = 0;
135 TrapNumErrorsOccurred = 0;
136 TrapNumUnrecoverableErrorsOccurred = 0;
137
138 LastDiagLevel = DiagnosticIDs::Ignored;
139
140 if (!soft) {
141 // Clear state related to #pragma diagnostic.
142 DiagStates.clear();
143 DiagStatesByLoc.clear();
144 DiagStateOnPushStack.clear();
145
146 // Create a DiagState and DiagStatePoint representing diagnostic changes
147 // through command-line.
148 DiagStates.emplace_back();
149 DiagStatesByLoc.appendFirst(&DiagStates.back());
150 }
151}
152
154DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) {
155 std::pair<iterator, bool> Result =
156 DiagMap.insert(std::make_pair(Diag, DiagnosticMapping()));
157
158 // Initialize the entry if we added it.
159 if (Result.second)
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,
173 DiagState *State) {
174 CurDiagState = State;
175 CurDiagStateLoc = Loc;
176
177 std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
178 unsigned Offset = Decomp.second;
179 for (File *F = getFile(SrcMgr, Decomp.first); F;
180 Offset = F->ParentOffset, F = F->Parent) {
181 F->HasLocalTransitions = true;
182 auto &Last = F->StateTransitions.back();
183 assert(Last.Offset <= Offset && "state transitions added out of order");
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 std::pair<FileID, unsigned> 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 // Get or insert the File for this ID.
222 auto Range = Files.equal_range(ID);
223 if (Range.first != Range.second)
224 return &Range.first->second;
225 auto &F = Files.insert(Range.first, std::make_pair(ID, File()))->second;
226
227 // We created a new File; look up the diagnostic state at the start of it and
228 // initialize it.
229 if (ID.isValid()) {
230 std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedIncludedLoc(ID);
231 F.Parent = getFile(SrcMgr, Decomp.first);
232 F.ParentOffset = Decomp.second;
233 F.StateTransitions.push_back({F.Parent->lookup(Decomp.second), 0});
234 } else {
235 // This is the (imaginary) root file into which we pretend all top-level
236 // files are included; it descends from the initial state.
237 //
238 // FIXME: This doesn't guarantee that we use the same ordering as
239 // isBeforeInTranslationUnit in the cases where someone invented another
240 // top-level file and added diagnostic pragmas to it. See the code at the
241 // end of isBeforeInTranslationUnit for the quirks it deals with.
242 F.StateTransitions.push_back({FirstDiagState, 0});
243 }
244 return &F;
245}
246
247void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr,
248 StringRef DiagName) const {
249 llvm::errs() << "diagnostic state at ";
250 CurDiagStateLoc.print(llvm::errs(), SrcMgr);
251 llvm::errs() << ": " << CurDiagState << "\n";
252
253 for (auto &F : Files) {
254 FileID ID = F.first;
255 File &File = F.second;
256
257 bool PrintedOuterHeading = false;
258 auto PrintOuterHeading = [&] {
259 if (PrintedOuterHeading) 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 std::pair<FileID, unsigned> Decomp =
267 SrcMgr.getDecomposedIncludedLoc(ID);
268 assert(File.ParentOffset == Decomp.second);
269 llvm::errs() << " parent " << File.Parent << " <FileID "
270 << Decomp.first.getHashValue() << "> ";
271 SrcMgr.getLocForStartOfFile(Decomp.first)
272 .getLocWithOffset(Decomp.second)
273 .print(llvm::errs(), SrcMgr);
274 }
275 if (File.HasLocalTransitions)
276 llvm::errs() << " has_local_transitions";
277 llvm::errs() << "\n";
278 };
279
280 if (DiagName.empty())
281 PrintOuterHeading();
282
283 for (DiagStatePoint &Transition : File.StateTransitions) {
284 bool PrintedInnerHeading = false;
285 auto PrintInnerHeading = [&] {
286 if (PrintedInnerHeading) 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 =
303 if (!DiagName.empty() && DiagName != Option)
304 continue;
305
306 PrintInnerHeading();
307 llvm::errs() << " ";
308 if (Option.empty())
309 llvm::errs() << "<unknown " << Mapping.first << ">";
310 else
311 llvm::errs() << Option;
312 llvm::errs() << ": ";
313
314 switch (Mapping.second.getSeverity()) {
315 case diag::Severity::Ignored: llvm::errs() << "ignored"; break;
316 case diag::Severity::Remark: llvm::errs() << "remark"; break;
317 case diag::Severity::Warning: llvm::errs() << "warning"; break;
318 case diag::Severity::Error: llvm::errs() << "error"; break;
319 case diag::Severity::Fatal: llvm::errs() << "fatal"; break;
320 }
321
322 if (!Mapping.second.isUser())
323 llvm::errs() << " default";
324 if (Mapping.second.isPragma())
325 llvm::errs() << " pragma";
326 if (Mapping.second.hasNoWarningAsError())
327 llvm::errs() << " no-error";
328 if (Mapping.second.hasNoErrorAsFatal())
329 llvm::errs() << " no-fatal";
330 if (Mapping.second.wasUpgradedFromWarning())
331 llvm::errs() << " overruled";
332 llvm::errs() << "\n";
333 }
334 }
335 }
336}
337
338void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,
340 assert(Loc.isValid() && "Adding invalid loc point");
341 DiagStatesByLoc.append(*SourceMgr, Loc, State);
342}
343
345 SourceLocation L) {
346 assert(Diag < diag::DIAG_UPPER_LIMIT &&
347 "Can only map builtin diagnostics");
348 assert((Diags->isBuiltinWarningOrExtension(Diag) ||
349 (Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
350 "Cannot map errors into warnings!");
351 assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
352
353 // A command line -Wfoo has an invalid L and cannot override error/fatal
354 // mapping, while a warning pragma can.
355 bool WasUpgradedFromWarning = false;
356 if (Map == diag::Severity::Warning && L.isInvalid()) {
357 DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
358 if (Info.getSeverity() == diag::Severity::Error ||
360 Map = Info.getSeverity();
361 WasUpgradedFromWarning = true;
362 }
363 }
364 DiagnosticMapping Mapping = makeUserMapping(Map, L);
365 Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
366
367 // Make sure we propagate the NoWarningAsError flag from an existing
368 // mapping (which may be the default mapping).
369 DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
371 Mapping.hasNoWarningAsError());
372
373 // Common case; setting all the diagnostics of a group in one place.
374 if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) &&
375 DiagStatesByLoc.getCurDiagState()) {
376 // FIXME: This is theoretically wrong: if the current state is shared with
377 // some other location (via push/pop) we will change the state for that
378 // other location as well. This cannot currently happen, as we can't update
379 // the diagnostic state at the same location at which we pop.
380 DiagStatesByLoc.getCurDiagState()->setMapping(Diag, Mapping);
381 return;
382 }
383
384 // A diagnostic pragma occurred, create a new DiagState initialized with
385 // the current one and a new DiagStatePoint to record at which location
386 // the new state became active.
387 DiagStates.push_back(*GetCurDiagState());
388 DiagStates.back().setMapping(Diag, Mapping);
389 PushDiagStatePoint(&DiagStates.back(), L);
390}
391
393 StringRef Group, diag::Severity Map,
395 // Get the diagnostics in this group.
397 if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
398 return true;
399
400 // Set the mapping.
401 for (diag::kind Diag : GroupDiags)
402 setSeverity(Diag, Map, Loc);
403
404 return false;
405}
406
408 diag::Group Group,
409 diag::Severity Map,
411 return setSeverityForGroup(Flavor, Diags->getWarningOptionForGroup(Group),
412 Map, Loc);
413}
414
416 bool Enabled) {
417 // If we are enabling this feature, just set the diagnostic mappings to map to
418 // errors.
419 if (Enabled)
422
423 // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
424 // potentially downgrade anything already mapped to be a warning.
425
426 // Get the diagnostics in this group.
428 if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
429 GroupDiags))
430 return true;
431
432 // Perform the mapping change.
433 for (diag::kind Diag : GroupDiags) {
434 DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
435
436 if (Info.getSeverity() == diag::Severity::Error ||
439
440 Info.setNoWarningAsError(true);
441 }
442
443 return false;
444}
445
447 bool Enabled) {
448 // If we are enabling this feature, just set the diagnostic mappings to map to
449 // fatal errors.
450 if (Enabled)
453
454 // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
455 // and potentially downgrade anything already mapped to be a fatal error.
456
457 // Get the diagnostics in this group.
459 if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
460 GroupDiags))
461 return true;
462
463 // Perform the mapping change.
464 for (diag::kind Diag : GroupDiags) {
465 DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
466
469
470 Info.setNoErrorAsFatal(true);
471 }
472
473 return false;
474}
475
477 diag::Severity Map,
479 // Get all the diagnostics.
480 std::vector<diag::kind> AllDiags;
481 DiagnosticIDs::getAllDiagnostics(Flavor, AllDiags);
482
483 // Set the mapping.
484 for (diag::kind Diag : AllDiags)
485 if (Diags->isBuiltinWarningOrExtension(Diag))
486 setSeverity(Diag, Map, Loc);
487}
488
489namespace {
490// FIXME: We should isolate the parser from SpecialCaseList and just use it
491// here.
492class WarningsSpecialCaseList : public llvm::SpecialCaseList {
493public:
494 static std::unique_ptr<WarningsSpecialCaseList>
495 create(const llvm::MemoryBuffer &Input, std::string &Err);
496
497 // Section names refer to diagnostic groups, which cover multiple individual
498 // diagnostics. Expand diagnostic groups here to individual diagnostics.
499 // A diagnostic can have multiple diagnostic groups associated with it, we let
500 // the last section take precedence in such cases.
501 void processSections(DiagnosticsEngine &Diags);
502
503 bool isDiagSuppressed(diag::kind DiagId, SourceLocation DiagLoc,
504 const SourceManager &SM) const;
505
506private:
507 // Find the longest glob pattern that matches FilePath amongst
508 // CategoriesToMatchers, return true iff the match exists and belongs to a
509 // positive category.
510 bool globsMatches(const llvm::StringMap<Matcher> &CategoriesToMatchers,
511 StringRef FilePath) const;
512
513 llvm::DenseMap<diag::kind, const Section *> DiagToSection;
514};
515} // namespace
516
517std::unique_ptr<WarningsSpecialCaseList>
518WarningsSpecialCaseList::create(const llvm::MemoryBuffer &Input,
519 std::string &Err) {
520 auto WarningSuppressionList = std::make_unique<WarningsSpecialCaseList>();
521 if (!WarningSuppressionList->createInternal(&Input, Err))
522 return nullptr;
523 return WarningSuppressionList;
524}
525
526void WarningsSpecialCaseList::processSections(DiagnosticsEngine &Diags) {
527 // Drop the default section introduced by special case list, we only support
528 // exact diagnostic group names.
529 // FIXME: We should make this configurable in the parser instead.
530 Sections.erase("*");
531 // Make sure we iterate sections by their line numbers.
532 std::vector<std::pair<unsigned, const llvm::StringMapEntry<Section> *>>
533 LineAndSectionEntry;
534 LineAndSectionEntry.reserve(Sections.size());
535 for (const auto &Entry : Sections) {
536 StringRef DiagName = Entry.getKey();
537 // Each section has a matcher with that section's name, attached to that
538 // line.
539 const auto &DiagSectionMatcher = Entry.getValue().SectionMatcher;
540 unsigned DiagLine = DiagSectionMatcher->Globs.at(DiagName).second;
541 LineAndSectionEntry.emplace_back(DiagLine, &Entry);
542 }
543 llvm::sort(LineAndSectionEntry);
544 static constexpr auto WarningFlavor = clang::diag::Flavor::WarningOrError;
545 for (const auto &[_, SectionEntry] : LineAndSectionEntry) {
546 SmallVector<diag::kind> GroupDiags;
547 StringRef DiagGroup = SectionEntry->getKey();
548 if (Diags.getDiagnosticIDs()->getDiagnosticsInGroup(
549 WarningFlavor, DiagGroup, GroupDiags)) {
550 StringRef Suggestion =
551 DiagnosticIDs::getNearestOption(WarningFlavor, DiagGroup);
552 Diags.Report(diag::warn_unknown_diag_option)
553 << static_cast<unsigned>(WarningFlavor) << DiagGroup
554 << !Suggestion.empty() << Suggestion;
555 continue;
556 }
557 for (diag::kind Diag : GroupDiags)
558 // We're intentionally overwriting any previous mappings here to make sure
559 // latest one takes precedence.
560 DiagToSection[Diag] = &SectionEntry->getValue();
561 }
562}
563
564void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &Input) {
565 std::string Error;
566 auto WarningSuppressionList = WarningsSpecialCaseList::create(Input, Error);
567 if (!WarningSuppressionList) {
568 // FIXME: Use a `%select` statement instead of printing `Error` as-is. This
569 // should help localization.
570 Report(diag::err_drv_malformed_warning_suppression_mapping)
571 << Input.getBufferIdentifier() << Error;
572 return;
573 }
574 WarningSuppressionList->processSections(*this);
575 DiagSuppressionMapping =
576 [WarningSuppressionList(std::move(WarningSuppressionList))](
577 diag::kind DiagId, SourceLocation DiagLoc, const SourceManager &SM) {
578 return WarningSuppressionList->isDiagSuppressed(DiagId, DiagLoc, SM);
579 };
580}
581
582bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
583 SourceLocation DiagLoc,
584 const SourceManager &SM) const {
585 const Section *DiagSection = DiagToSection.lookup(DiagId);
586 if (!DiagSection)
587 return false;
588 const SectionEntries &EntityTypeToCategories = DiagSection->Entries;
589 auto SrcEntriesIt = EntityTypeToCategories.find("src");
590 if (SrcEntriesIt == EntityTypeToCategories.end())
591 return false;
592 const llvm::StringMap<llvm::SpecialCaseList::Matcher> &CategoriesToMatchers =
593 SrcEntriesIt->getValue();
594 // We also use presumed locations here to improve reproducibility for
595 // preprocessed inputs.
596 if (PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc); PLoc.isValid())
597 return globsMatches(
598 CategoriesToMatchers,
599 llvm::sys::path::remove_leading_dotslash(PLoc.getFilename()));
600 return false;
601}
602
603bool WarningsSpecialCaseList::globsMatches(
604 const llvm::StringMap<Matcher> &CategoriesToMatchers,
605 StringRef FilePath) const {
606 StringRef LongestMatch;
607 bool LongestIsPositive = false;
608 for (const auto &Entry : CategoriesToMatchers) {
609 StringRef Category = Entry.getKey();
610 const llvm::SpecialCaseList::Matcher &Matcher = Entry.getValue();
611 bool IsPositive = Category != "emit";
612 for (const auto &[Pattern, Glob] : Matcher.Globs) {
613 if (Pattern.size() < LongestMatch.size())
614 continue;
615 if (!Glob.first.match(FilePath))
616 continue;
617 LongestMatch = Pattern;
618 LongestIsPositive = IsPositive;
619 }
620 }
621 return LongestIsPositive;
622}
623
625 SourceLocation DiagLoc) const {
626 if (!hasSourceManager() || !DiagSuppressionMapping)
627 return false;
628 return DiagSuppressionMapping(DiagId, DiagLoc, getSourceManager());
629}
630
632 DiagnosticStorage DiagStorage;
633 DiagStorage.DiagRanges.append(storedDiag.range_begin(),
634 storedDiag.range_end());
635
636 DiagStorage.FixItHints.append(storedDiag.fixit_begin(),
637 storedDiag.fixit_end());
638
639 assert(Client && "DiagnosticConsumer not set!");
640 Level DiagLevel = storedDiag.getLevel();
641 Diagnostic Info(this, storedDiag.getLocation(), storedDiag.getID(),
642 DiagStorage, storedDiag.getMessage());
643 Client->HandleDiagnostic(DiagLevel, Info);
644 if (Client->IncludeInDiagnosticCounts()) {
645 if (DiagLevel == DiagnosticsEngine::Warning)
646 ++NumWarnings;
647 }
648}
649
651 bool Force) {
652 assert(getClient() && "DiagnosticClient not set!");
653
654 bool Emitted;
655 if (Force) {
656 Diagnostic Info(this, DB);
657
658 // Figure out the diagnostic level of this message.
659 DiagnosticIDs::Level DiagLevel
660 = Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this);
661
662 Emitted = (DiagLevel != DiagnosticIDs::Ignored);
663 if (Emitted) {
664 // Emit the diagnostic regardless of suppression level.
665 Diags->EmitDiag(*this, DB, DiagLevel);
666 }
667 } else {
668 // Process the diagnostic, sending the accumulated information to the
669 // DiagnosticConsumer.
670 Emitted = ProcessDiag(DB);
671 }
672
673 return Emitted;
674}
675
676DiagnosticBuilder::DiagnosticBuilder(DiagnosticsEngine *DiagObj,
677 SourceLocation DiagLoc, unsigned DiagID)
678 : StreamingDiagnostic(DiagObj->DiagAllocator), DiagObj(DiagObj),
679 DiagLoc(DiagLoc), DiagID(DiagID), IsActive(true) {
680 assert(DiagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");
681}
682
683DiagnosticBuilder::DiagnosticBuilder(const DiagnosticBuilder &D)
685 DiagLoc = D.DiagLoc;
686 DiagID = D.DiagID;
687 FlagValue = D.FlagValue;
688 DiagObj = D.DiagObj;
689 DiagStorage = D.DiagStorage;
690 D.DiagStorage = nullptr;
691 Allocator = D.Allocator;
692 IsActive = D.IsActive;
693 IsForceEmit = D.IsForceEmit;
694 D.Clear();
695}
696
698 const DiagnosticBuilder &DiagBuilder)
699 : DiagObj(DO), DiagLoc(DiagBuilder.DiagLoc), DiagID(DiagBuilder.DiagID),
700 FlagValue(DiagBuilder.FlagValue), DiagStorage(*DiagBuilder.getStorage()) {
701}
702
704 unsigned DiagID, const DiagnosticStorage &DiagStorage,
705 StringRef StoredDiagMessage)
706 : DiagObj(DO), DiagLoc(DiagLoc), DiagID(DiagID), DiagStorage(DiagStorage),
707 StoredDiagMessage(StoredDiagMessage) {}
708
710
712 const Diagnostic &Info) {
714 return;
715
716 if (DiagLevel == DiagnosticsEngine::Warning)
717 ++NumWarnings;
718 else if (DiagLevel >= DiagnosticsEngine::Error)
719 ++NumErrors;
720}
721
722/// ModifierIs - Return true if the specified modifier matches specified string.
723template <std::size_t StrLen>
724static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
725 const char (&Str)[StrLen]) {
726 return StrLen-1 == ModifierLen && memcmp(Modifier, Str, StrLen-1) == 0;
727}
728
729/// ScanForward - Scans forward, looking for the given character, skipping
730/// nested clauses and escaped characters.
731static const char *ScanFormat(const char *I, const char *E, char Target) {
732 unsigned Depth = 0;
733
734 for ( ; I != E; ++I) {
735 if (Depth == 0 && *I == Target) return I;
736 if (Depth != 0 && *I == '}') Depth--;
737
738 if (*I == '%') {
739 I++;
740 if (I == E) break;
741
742 // Escaped characters get implicitly skipped here.
743
744 // Format specifier.
745 if (!isDigit(*I) && !isPunctuation(*I)) {
746 for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ;
747 if (I == E) break;
748 if (*I == '{')
749 Depth++;
750 }
751 }
752 }
753 return E;
754}
755
756/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
757/// like this: %select{foo|bar|baz}2. This means that the integer argument
758/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
759/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
760/// This is very useful for certain classes of variant diagnostics.
761static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
762 const char *Argument, unsigned ArgumentLen,
763 SmallVectorImpl<char> &OutStr) {
764 const char *ArgumentEnd = Argument+ArgumentLen;
765
766 // Skip over 'ValNo' |'s.
767 while (ValNo) {
768 const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
769 assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
770 " larger than the number of options in the diagnostic string!");
771 Argument = NextVal+1; // Skip this string.
772 --ValNo;
773 }
774
775 // Get the end of the value. This is either the } or the |.
776 const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
777
778 // Recursively format the result of the select clause into the output string.
779 DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
780}
781
782/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
783/// letter 's' to the string if the value is not 1. This is used in cases like
784/// this: "you idiot, you have %4 parameter%s4!".
785static void HandleIntegerSModifier(unsigned ValNo,
786 SmallVectorImpl<char> &OutStr) {
787 if (ValNo != 1)
788 OutStr.push_back('s');
789}
790
791/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
792/// prints the ordinal form of the given integer, with 1 corresponding
793/// to the first ordinal. Currently this is hard-coded to use the
794/// English form.
795static void HandleOrdinalModifier(unsigned ValNo,
796 SmallVectorImpl<char> &OutStr) {
797 assert(ValNo != 0 && "ValNo must be strictly positive!");
798
799 llvm::raw_svector_ostream Out(OutStr);
800
801 // We could use text forms for the first N ordinals, but the numeric
802 // forms are actually nicer in diagnostics because they stand out.
803 Out << ValNo << llvm::getOrdinalSuffix(ValNo);
804}
805
806// 123 -> "123".
807// 1234 -> "1.23k".
808// 123456 -> "123.46k".
809// 1234567 -> "1.23M".
810// 1234567890 -> "1.23G".
811// 1234567890123 -> "1.23T".
812static void HandleIntegerHumanModifier(int64_t ValNo,
813 SmallVectorImpl<char> &OutStr) {
814 static constexpr std::array<std::pair<int64_t, char>, 4> Units = {
815 {{1'000'000'000'000L, 'T'},
816 {1'000'000'000L, 'G'},
817 {1'000'000L, 'M'},
818 {1'000L, 'k'}}};
819
820 llvm::raw_svector_ostream Out(OutStr);
821 if (ValNo < 0) {
822 Out << "-";
823 ValNo = -ValNo;
824 }
825 for (const auto &[UnitSize, UnitSign] : Units) {
826 if (ValNo >= UnitSize) {
827 Out << llvm::format("%0.2f%c", ValNo / static_cast<double>(UnitSize),
828 UnitSign);
829 return;
830 }
831 }
832 Out << ValNo;
833}
834
835/// PluralNumber - Parse an unsigned integer and advance Start.
836static unsigned PluralNumber(const char *&Start, const char *End) {
837 // Programming 101: Parse a decimal number :-)
838 unsigned Val = 0;
839 while (Start != End && *Start >= '0' && *Start <= '9') {
840 Val *= 10;
841 Val += *Start - '0';
842 ++Start;
843 }
844 return Val;
845}
846
847/// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
848static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
849 if (*Start != '[') {
850 unsigned Ref = PluralNumber(Start, End);
851 return Ref == Val;
852 }
853
854 ++Start;
855 unsigned Low = PluralNumber(Start, End);
856 assert(*Start == ',' && "Bad plural expression syntax: expected ,");
857 ++Start;
858 unsigned High = PluralNumber(Start, End);
859 assert(*Start == ']' && "Bad plural expression syntax: expected )");
860 ++Start;
861 return Low <= Val && Val <= High;
862}
863
864/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
865static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
866 // Empty condition?
867 if (*Start == ':')
868 return true;
869
870 while (true) {
871 char C = *Start;
872 if (C == '%') {
873 // Modulo expression
874 ++Start;
875 unsigned Arg = PluralNumber(Start, End);
876 assert(*Start == '=' && "Bad plural expression syntax: expected =");
877 ++Start;
878 unsigned ValMod = ValNo % Arg;
879 if (TestPluralRange(ValMod, Start, End))
880 return true;
881 } else {
882 assert((C == '[' || (C >= '0' && C <= '9')) &&
883 "Bad plural expression syntax: unexpected character");
884 // Range expression
885 if (TestPluralRange(ValNo, Start, End))
886 return true;
887 }
888
889 // Scan for next or-expr part.
890 Start = std::find(Start, End, ',');
891 if (Start == End)
892 break;
893 ++Start;
894 }
895 return false;
896}
897
898/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
899/// for complex plural forms, or in languages where all plurals are complex.
900/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
901/// conditions that are tested in order, the form corresponding to the first
902/// that applies being emitted. The empty condition is always true, making the
903/// last form a default case.
904/// Conditions are simple boolean expressions, where n is the number argument.
905/// Here are the rules.
906/// condition := expression | empty
907/// empty := -> always true
908/// expression := numeric [',' expression] -> logical or
909/// numeric := range -> true if n in range
910/// | '%' number '=' range -> true if n % number in range
911/// range := number
912/// | '[' number ',' number ']' -> ranges are inclusive both ends
913///
914/// Here are some examples from the GNU gettext manual written in this form:
915/// English:
916/// {1:form0|:form1}
917/// Latvian:
918/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
919/// Gaeilge:
920/// {1:form0|2:form1|:form2}
921/// Romanian:
922/// {1:form0|0,%100=[1,19]:form1|:form2}
923/// Lithuanian:
924/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
925/// Russian (requires repeated form):
926/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
927/// Slovak
928/// {1:form0|[2,4]:form1|:form2}
929/// Polish (requires repeated form):
930/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
931static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
932 const char *Argument, unsigned ArgumentLen,
933 SmallVectorImpl<char> &OutStr) {
934 const char *ArgumentEnd = Argument + ArgumentLen;
935 while (true) {
936 assert(Argument < ArgumentEnd && "Plural expression didn't match.");
937 const char *ExprEnd = Argument;
938 while (*ExprEnd != ':') {
939 assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
940 ++ExprEnd;
941 }
942 if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
943 Argument = ExprEnd + 1;
944 ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
945
946 // Recursively format the result of the plural clause into the
947 // output string.
948 DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
949 return;
950 }
951 Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
952 }
953}
954
955/// Returns the friendly description for a token kind that will appear
956/// without quotes in diagnostic messages. These strings may be translatable in
957/// future.
959 switch (Kind) {
960 case tok::identifier:
961 return "identifier";
962 default:
963 return nullptr;
964 }
965}
966
967/// FormatDiagnostic - Format this diagnostic into a string, substituting the
968/// formal arguments into the %0 slots. The result is appended onto the Str
969/// array.
972 if (StoredDiagMessage.has_value()) {
973 OutStr.append(StoredDiagMessage->begin(), StoredDiagMessage->end());
974 return;
975 }
976
977 StringRef Diag =
978 getDiags()->getDiagnosticIDs()->getDescription(getID());
979
980 FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
981}
982
983/// EscapeStringForDiagnostic - Append Str to the diagnostic buffer,
984/// escaping non-printable characters and ill-formed code unit sequences.
986 SmallVectorImpl<char> &OutStr) {
987 OutStr.reserve(OutStr.size() + Str.size());
988 auto *Begin = reinterpret_cast<const unsigned char *>(Str.data());
989 llvm::raw_svector_ostream OutStream(OutStr);
990 const unsigned char *End = Begin + Str.size();
991 while (Begin != End) {
992 // ASCII case
993 if (isPrintable(*Begin) || isWhitespace(*Begin)) {
994 OutStream << *Begin;
995 ++Begin;
996 continue;
997 }
998 if (llvm::isLegalUTF8Sequence(Begin, End)) {
999 llvm::UTF32 CodepointValue;
1000 llvm::UTF32 *CpPtr = &CodepointValue;
1001 const unsigned char *CodepointBegin = Begin;
1002 const unsigned char *CodepointEnd =
1003 Begin + llvm::getNumBytesForUTF8(*Begin);
1004 llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(
1005 &Begin, CodepointEnd, &CpPtr, CpPtr + 1, llvm::strictConversion);
1006 (void)Res;
1007 assert(
1008 llvm::conversionOK == Res &&
1009 "the sequence is legal UTF-8 but we couldn't convert it to UTF-32");
1010 assert(Begin == CodepointEnd &&
1011 "we must be further along in the string now");
1012 if (llvm::sys::unicode::isPrintable(CodepointValue) ||
1013 llvm::sys::unicode::isFormatting(CodepointValue)) {
1014 OutStr.append(CodepointBegin, CodepointEnd);
1015 continue;
1016 }
1017 // Unprintable code point.
1018 OutStream << "<U+" << llvm::format_hex_no_prefix(CodepointValue, 4, true)
1019 << ">";
1020 continue;
1021 }
1022 // Invalid code unit.
1023 OutStream << "<" << llvm::format_hex_no_prefix(*Begin, 2, true) << ">";
1024 ++Begin;
1025 }
1026}
1027
1029FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
1030 SmallVectorImpl<char> &OutStr) const {
1031 // When the diagnostic string is only "%0", the entire string is being given
1032 // by an outside source. Remove unprintable characters from this string
1033 // and skip all the other string processing.
1034 if (DiagEnd - DiagStr == 2 && StringRef(DiagStr, DiagEnd - DiagStr) == "%0" &&
1036 const std::string &S = getArgStdStr(0);
1037 EscapeStringForDiagnostic(S, OutStr);
1038 return;
1039 }
1040
1041 /// FormattedArgs - Keep track of all of the arguments formatted by
1042 /// ConvertArgToString and pass them into subsequent calls to
1043 /// ConvertArgToString, allowing the implementation to avoid redundancies in
1044 /// obvious cases.
1046
1047 /// QualTypeVals - Pass a vector of arrays so that QualType names can be
1048 /// compared to see if more information is needed to be printed.
1049 SmallVector<intptr_t, 2> QualTypeVals;
1051
1052 for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
1054 QualTypeVals.push_back(getRawArg(i));
1055
1056 while (DiagStr != DiagEnd) {
1057 if (DiagStr[0] != '%') {
1058 // Append non-%0 substrings to Str if we have one.
1059 const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
1060 OutStr.append(DiagStr, StrEnd);
1061 DiagStr = StrEnd;
1062 continue;
1063 } else if (isPunctuation(DiagStr[1])) {
1064 OutStr.push_back(DiagStr[1]); // %% -> %.
1065 DiagStr += 2;
1066 continue;
1067 }
1068
1069 // Skip the %.
1070 ++DiagStr;
1071
1072 // This must be a placeholder for a diagnostic argument. The format for a
1073 // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
1074 // The digit is a number from 0-9 indicating which argument this comes from.
1075 // The modifier is a string of digits from the set [-a-z]+, arguments is a
1076 // brace enclosed string.
1077 const char *Modifier = nullptr, *Argument = nullptr;
1078 unsigned ModifierLen = 0, ArgumentLen = 0;
1079
1080 // Check to see if we have a modifier. If so eat it.
1081 if (!isDigit(DiagStr[0])) {
1082 Modifier = DiagStr;
1083 while (DiagStr[0] == '-' ||
1084 (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
1085 ++DiagStr;
1086 ModifierLen = DiagStr-Modifier;
1087
1088 // If we have an argument, get it next.
1089 if (DiagStr[0] == '{') {
1090 ++DiagStr; // Skip {.
1091 Argument = DiagStr;
1092
1093 DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
1094 assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
1095 ArgumentLen = DiagStr-Argument;
1096 ++DiagStr; // Skip }.
1097 }
1098 }
1099
1100 assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
1101 unsigned ArgNo = *DiagStr++ - '0';
1102
1103 // Only used for type diffing.
1104 unsigned ArgNo2 = ArgNo;
1105
1107 if (ModifierIs(Modifier, ModifierLen, "diff")) {
1108 assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
1109 "Invalid format for diff modifier");
1110 ++DiagStr; // Comma.
1111 ArgNo2 = *DiagStr++ - '0';
1113 if (Kind == DiagnosticsEngine::ak_qualtype &&
1116 else {
1117 // %diff only supports QualTypes. For other kinds of arguments,
1118 // use the default printing. For example, if the modifier is:
1119 // "%diff{compare $ to $|other text}1,2"
1120 // treat it as:
1121 // "compare %1 to %2"
1122 const char *ArgumentEnd = Argument + ArgumentLen;
1123 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1124 assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd &&
1125 "Found too many '|'s in a %diff modifier!");
1126 const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
1127 const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
1128 const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) };
1129 const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) };
1130 FormatDiagnostic(Argument, FirstDollar, OutStr);
1131 FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
1132 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1133 FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
1134 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1135 continue;
1136 }
1137 }
1138
1139 switch (Kind) {
1140 // ---- STRINGS ----
1142 const std::string &S = getArgStdStr(ArgNo);
1143 assert(ModifierLen == 0 && "No modifiers for strings yet");
1144 EscapeStringForDiagnostic(S, OutStr);
1145 break;
1146 }
1148 const char *S = getArgCStr(ArgNo);
1149 assert(ModifierLen == 0 && "No modifiers for strings yet");
1150
1151 // Don't crash if get passed a null pointer by accident.
1152 if (!S)
1153 S = "(null)";
1154 EscapeStringForDiagnostic(S, OutStr);
1155 break;
1156 }
1157 // ---- INTEGERS ----
1159 int64_t Val = getArgSInt(ArgNo);
1160
1161 if (ModifierIs(Modifier, ModifierLen, "select")) {
1162 HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1163 OutStr);
1164 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1165 HandleIntegerSModifier(Val, OutStr);
1166 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1167 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1168 OutStr);
1169 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1170 HandleOrdinalModifier((unsigned)Val, OutStr);
1171 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1172 HandleIntegerHumanModifier(Val, OutStr);
1173 } else {
1174 assert(ModifierLen == 0 && "Unknown integer modifier");
1175 llvm::raw_svector_ostream(OutStr) << Val;
1176 }
1177 break;
1178 }
1180 uint64_t Val = getArgUInt(ArgNo);
1181
1182 if (ModifierIs(Modifier, ModifierLen, "select")) {
1183 HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
1184 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1185 HandleIntegerSModifier(Val, OutStr);
1186 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1187 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1188 OutStr);
1189 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1190 HandleOrdinalModifier(Val, OutStr);
1191 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1192 HandleIntegerHumanModifier(Val, OutStr);
1193 } else {
1194 assert(ModifierLen == 0 && "Unknown integer modifier");
1195 llvm::raw_svector_ostream(OutStr) << Val;
1196 }
1197 break;
1198 }
1199 // ---- TOKEN SPELLINGS ----
1201 tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo));
1202 assert(ModifierLen == 0 && "No modifiers for token kinds yet");
1203
1204 llvm::raw_svector_ostream Out(OutStr);
1205 if (const char *S = tok::getPunctuatorSpelling(Kind))
1206 // Quoted token spelling for punctuators.
1207 Out << '\'' << S << '\'';
1208 else if ((S = tok::getKeywordSpelling(Kind)))
1209 // Unquoted token spelling for keywords.
1210 Out << S;
1211 else if ((S = getTokenDescForDiagnostic(Kind)))
1212 // Unquoted translatable token name.
1213 Out << S;
1214 else if ((S = tok::getTokenName(Kind)))
1215 // Debug name, shouldn't appear in user-facing diagnostics.
1216 Out << '<' << S << '>';
1217 else
1218 Out << "(null)";
1219 break;
1220 }
1221 // ---- NAMES and TYPES ----
1223 const IdentifierInfo *II = getArgIdentifier(ArgNo);
1224 assert(ModifierLen == 0 && "No modifiers for strings yet");
1225
1226 // Don't crash if get passed a null pointer by accident.
1227 if (!II) {
1228 const char *S = "(null)";
1229 OutStr.append(S, S + strlen(S));
1230 continue;
1231 }
1232
1233 llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
1234 break;
1235 }
1244 getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
1245 StringRef(Modifier, ModifierLen),
1246 StringRef(Argument, ArgumentLen),
1247 FormattedArgs,
1248 OutStr, QualTypeVals);
1249 break;
1251 // Create a struct with all the info needed for printing.
1253 TDT.FromType = getRawArg(ArgNo);
1254 TDT.ToType = getRawArg(ArgNo2);
1255 TDT.ElideType = getDiags()->ElideType;
1256 TDT.ShowColors = getDiags()->ShowColors;
1257 TDT.TemplateDiffUsed = false;
1258 intptr_t val = reinterpret_cast<intptr_t>(&TDT);
1259
1260 const char *ArgumentEnd = Argument + ArgumentLen;
1261 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1262
1263 // Print the tree. If this diagnostic already has a tree, skip the
1264 // second tree.
1265 if (getDiags()->PrintTemplateTree && Tree.empty()) {
1266 TDT.PrintFromType = true;
1267 TDT.PrintTree = true;
1268 getDiags()->ConvertArgToString(Kind, val,
1269 StringRef(Modifier, ModifierLen),
1270 StringRef(Argument, ArgumentLen),
1271 FormattedArgs,
1272 Tree, QualTypeVals);
1273 // If there is no tree information, fall back to regular printing.
1274 if (!Tree.empty()) {
1275 FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr);
1276 break;
1277 }
1278 }
1279
1280 // Non-tree printing, also the fall-back when tree printing fails.
1281 // The fall-back is triggered when the types compared are not templates.
1282 const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');
1283 const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');
1284
1285 // Append before text
1286 FormatDiagnostic(Argument, FirstDollar, OutStr);
1287
1288 // Append first type
1289 TDT.PrintTree = false;
1290 TDT.PrintFromType = true;
1291 getDiags()->ConvertArgToString(Kind, val,
1292 StringRef(Modifier, ModifierLen),
1293 StringRef(Argument, ArgumentLen),
1294 FormattedArgs,
1295 OutStr, QualTypeVals);
1296 if (!TDT.TemplateDiffUsed)
1297 FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
1298 TDT.FromType));
1299
1300 // Append middle text
1301 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1302
1303 // Append second type
1304 TDT.PrintFromType = false;
1305 getDiags()->ConvertArgToString(Kind, val,
1306 StringRef(Modifier, ModifierLen),
1307 StringRef(Argument, ArgumentLen),
1308 FormattedArgs,
1309 OutStr, QualTypeVals);
1310 if (!TDT.TemplateDiffUsed)
1311 FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
1312 TDT.ToType));
1313
1314 // Append end text
1315 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1316 break;
1317 }
1318 }
1319
1320 // Remember this argument info for subsequent formatting operations. Turn
1321 // std::strings into a null terminated string to make it be the same case as
1322 // all the other ones.
1324 continue;
1325 else if (Kind != DiagnosticsEngine::ak_std_string)
1326 FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
1327 else
1328 FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string,
1329 (intptr_t)getArgStdStr(ArgNo).c_str()));
1330 }
1331
1332 // Append the type tree to the end of the diagnostics.
1333 OutStr.append(Tree.begin(), Tree.end());
1334}
1335
1337 StringRef Message)
1338 : ID(ID), Level(Level), Message(Message) {}
1339
1341 const Diagnostic &Info)
1342 : ID(Info.getID()), Level(Level) {
1343 assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
1344 "Valid source location without setting a source manager for diagnostic");
1345 if (Info.getLocation().isValid())
1347 SmallString<64> Message;
1348 Info.FormatDiagnostic(Message);
1349 this->Message.assign(Message.begin(), Message.end());
1350 this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end());
1351 this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end());
1352}
1353
1355 StringRef Message, FullSourceLoc Loc,
1357 ArrayRef<FixItHint> FixIts)
1358 : ID(ID), Level(Level), Loc(Loc), Message(Message),
1359 Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())
1360{
1361}
1362
1363llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
1364 const StoredDiagnostic &SD) {
1365 if (SD.getLocation().hasManager())
1366 OS << SD.getLocation().printToString(SD.getLocation().getManager()) << ": ";
1367 OS << SD.getMessage();
1368 return OS;
1369}
1370
1371/// IncludeInDiagnosticCounts - This method (whose default implementation
1372/// returns true) indicates whether the diagnostics handled by this
1373/// DiagnosticConsumer should be included in the number of diagnostics
1374/// reported by DiagnosticsEngine.
1376
1377void IgnoringDiagConsumer::anchor() {}
1378
1380
1382 DiagnosticsEngine::Level DiagLevel,
1383 const Diagnostic &Info) {
1384 Target.HandleDiagnostic(DiagLevel, Info);
1385}
1386
1389 Target.clear();
1390}
1391
1393 return Target.IncludeInDiagnosticCounts();
1394}
1395
1397 for (unsigned I = 0; I != NumCached; ++I)
1398 FreeList[I] = Cached + I;
1399 NumFreeListEntries = NumCached;
1400}
1401
1403 // Don't assert if we are in a CrashRecovery context, as this invariant may
1404 // be invalidated during a crash.
1405 assert((NumFreeListEntries == NumCached ||
1406 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1407 "A partial is on the lam");
1408}
1409
SyntaxTree::Impl & Tree
Definition: ASTDiff.cpp:192
StringRef P
#define SM(sm)
Definition: Cuda.cpp:84
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:731
static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, SmallVectorImpl< char > &OutStr)
HandlePluralModifier - Handle the integer 'plural' modifier.
Definition: Diagnostic.cpp:931
static void HandleIntegerSModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)
HandleIntegerSModifier - Handle the integer 's' modifier.
Definition: Diagnostic.cpp:785
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:70
static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End)
EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
Definition: Diagnostic.cpp:865
static void HandleIntegerHumanModifier(int64_t ValNo, SmallVectorImpl< char > &OutStr)
Definition: Diagnostic.cpp:812
static unsigned PluralNumber(const char *&Start, const char *End)
PluralNumber - Parse an unsigned integer and advance Start.
Definition: Diagnostic.cpp:836
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:761
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:724
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:848
static void HandleOrdinalModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)
HandleOrdinalModifier - Handle the integer 'ord' modifier.
Definition: Diagnostic.cpp:795
static const char * getTokenDescForDiagnostic(tok::TokenKind Kind)
Returns the friendly description for a token kind that will appear without quotes in diagnostic messa...
Definition: Diagnostic.cpp:958
Defines the Diagnostic-related interfaces.
static llvm::GlobalValue::DLLStorageClassTypes getStorage(CodeGenModule &CGM, StringRef Name)
Definition: CGObjCMac.cpp:6430
const Decl * D
Expr * E
Defines the Diagnostic IDs-related interfaces.
int Category
Definition: Format.cpp:3035
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
Implements a partial diagnostic that can be emitted anwyhere in a DiagnosticBuilder stream.
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:758
SourceLocation Loc
Definition: SemaObjC.cpp:759
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:1220
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1684
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:711
unsigned NumErrors
Number of errors reported.
Definition: Diagnostic.h:1687
unsigned NumWarnings
Number of warnings reported.
Definition: Diagnostic.h:1686
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 StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
Level
The level of the diagnostic, after it has been through mapping.
static void getAllDiagnostics(diag::Flavor Flavor, std::vector< diag::kind > &Diags)
Get the set of all diagnostic IDs.
static DiagnosticMapping getDefaultMapping(unsigned DiagID)
Get the default mapping for this diagnostic.
void setNoWarningAsError(bool Value)
void setSeverity(diag::Severity Value)
diag::Severity getSeverity() const
void setUpgradedFromWarning(bool Value)
void setNoErrorAsFatal(bool Value)
bool hasNoWarningAsError() const
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...
Definition: Diagnostic.h:1512
Diagnostic(const DiagnosticsEngine *DO, const DiagnosticBuilder &DiagBuilder)
Definition: Diagnostic.cpp:697
const SourceLocation & getLocation() const
Definition: Diagnostic.h:1528
const std::string & getArgStdStr(unsigned Idx) const
Return the provided argument string specified by Idx.
Definition: Diagnostic.h:1547
void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const
Format this diagnostic into a string, substituting the formal arguments into the %0 slots.
Definition: Diagnostic.cpp:971
uint64_t getRawArg(unsigned Idx) const
Return the specified non-string argument in an opaque form.
Definition: Diagnostic.h:1588
const char * getArgCStr(unsigned Idx) const
Return the specified C string argument.
Definition: Diagnostic.h:1555
const IdentifierInfo * getArgIdentifier(unsigned Idx) const
Return the specified IdentifierInfo argument.
Definition: Diagnostic.h:1579
SourceManager & getSourceManager() const
Definition: Diagnostic.h:1530
ArrayRef< FixItHint > getFixItHints() const
Definition: Diagnostic.h:1613
unsigned getNumArgs() const
Definition: Diagnostic.h:1532
bool hasSourceManager() const
Definition: Diagnostic.h:1529
unsigned getID() const
Definition: Diagnostic.h:1527
DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const
Return the kind of the specified index.
Definition: Diagnostic.h:1540
int64_t getArgSInt(unsigned Idx) const
Return the specified signed integer argument.
Definition: Diagnostic.h:1563
uint64_t getArgUInt(unsigned Idx) const
Return the specified unsigned integer argument.
Definition: Diagnostic.h:1571
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic's ranges.
Definition: Diagnostic.h:1604
const DiagnosticsEngine * getDiags() const
Definition: Diagnostic.h:1526
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:1493
bool hasSourceManager() const
Definition: Diagnostic.h:605
bool EmitDiagnostic(const DiagnosticBuilder &DB, bool Force=false)
Emit the diagnostic.
Definition: Diagnostic.cpp:650
void setDiagSuppressionMapping(llvm::MemoryBuffer &Input)
Diagnostic suppression mappings can be used to suppress specific diagnostics in specific files.
Definition: Diagnostic.cpp:564
bool isSuppressedViaMapping(diag::kind DiagId, SourceLocation DiagLoc) const
Definition: Diagnostic.cpp:624
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:476
LLVM_DUMP_METHOD void dump() const
Definition: Diagnostic.cpp:97
void setClient(DiagnosticConsumer *client, bool ShouldOwnClient=true)
Set the diagnostic client associated with this diagnostic object.
Definition: Diagnostic.cpp:105
SourceManager & getSourceManager() const
Definition: Diagnostic.h:607
void pushMappings(SourceLocation Loc)
Copies the current DiagMappings and pushes the new copy onto the top of the stack.
Definition: Diagnostic.cpp:111
void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc)
This allows the client to specify that certain warnings are ignored.
Definition: Diagnostic.cpp:344
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:234
DiagnosticConsumer * getClient()
Definition: Diagnostic.h:595
@ ak_nameddecl
NamedDecl *.
Definition: Diagnostic.h:275
@ ak_declcontext
DeclContext *.
Definition: Diagnostic.h:281
@ ak_addrspace
address space
Definition: Diagnostic.h:263
@ ak_identifierinfo
IdentifierInfo.
Definition: Diagnostic.h:260
@ ak_qualtype_pair
pair<QualType, QualType>
Definition: Diagnostic.h:284
@ ak_c_string
const char *
Definition: Diagnostic.h:248
@ ak_declarationname
DeclarationName.
Definition: Diagnostic.h:272
@ ak_tokenkind
enum TokenKind : unsigned
Definition: Diagnostic.h:257
@ ak_std_string
std::string
Definition: Diagnostic.h:245
@ ak_nestednamespec
NestedNameSpecifier *.
Definition: Diagnostic.h:278
Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const
Based on the way the client configured the DiagnosticsEngine object, classify the specified diagnosti...
Definition: Diagnostic.h:954
DiagnosticsEngine(IntrusiveRefCntPtr< DiagnosticIDs > Diags, IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts, DiagnosticConsumer *client=nullptr, bool ShouldOwnClient=true)
Definition: Diagnostic.cpp:80
bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled)
Set the error-as-fatal flag for the given diagnostic group.
Definition: Diagnostic.cpp:446
bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled)
Set the warning-as-error flag for the given diagnostic group.
Definition: Diagnostic.cpp:415
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:903
bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group, diag::Severity Map, SourceLocation Loc=SourceLocation())
Change an entire diagnostic group (e.g.
Definition: Diagnostic.cpp:392
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:115
const IntrusiveRefCntPtr< DiagnosticIDs > & getDiagnosticIDs() const
Definition: Diagnostic.h:580
void Reset(bool soft=false)
Reset the state of the diagnostic object to its initial configuration.
Definition: Diagnostic.cpp:127
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.
llvm::MemoryBufferRef getBufferOrFake(FileID FID, SourceLocation Loc=SourceLocation()) const
Return the buffer for the specified FileID.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
std::pair< FileID, unsigned > getDecomposedIncludedLoc(FileID FID) const
Returns the "included/expanded in" decomposed location of the given FileID.
Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...
Definition: Diagnostic.h:1634
unsigned getID() const
Definition: Diagnostic.h:1655
range_iterator range_begin() const
Definition: Diagnostic.h:1664
DiagnosticsEngine::Level getLevel() const
Definition: Diagnostic.h:1656
fixit_iterator fixit_begin() const
Definition: Diagnostic.h:1672
const FullSourceLoc & getLocation() const
Definition: Diagnostic.h:1657
range_iterator range_end() const
Definition: Diagnostic.h:1665
StringRef getMessage() const
Definition: Diagnostic.h:1658
fixit_iterator fixit_end() const
Definition: Diagnostic.h:1673
The streaming interface shared between DiagnosticBuilder and PartialDiagnostic.
Definition: Diagnostic.h:1102
DiagStorageAllocator * Allocator
Allocator used to allocate storage for this diagnostic.
Definition: Diagnostic.h:1110
DiagnosticStorage * DiagStorage
Definition: Diagnostic.h:1107
void AddString(StringRef V) const
Definition: Diagnostic.h:1153
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...
Definition: DiagnosticIDs.h:87
@ 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.
Flavor
Flavors of diagnostics we can emit.
Definition: DiagnosticIDs.h:98
@ WarningOrError
A diagnostic that indicates a problem or potential problem.
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
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...
Definition: Diagnostic.cpp:985
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:1488
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