[HLSL] Implement RWBuffer::operator[] via __builtin_hlsl_resource_getpointer (#117017)
[llvm-project.git] / clang / lib / Basic / Diagnostic.cpp
blob2d0e358116362c0b2beb6edc4b123d597d9aa17e
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.
11 //===----------------------------------------------------------------------===//
13 #include "clang/Basic/Diagnostic.h"
14 #include "clang/Basic/CharInfo.h"
15 #include "clang/Basic/DiagnosticDriver.h"
16 #include "clang/Basic/DiagnosticError.h"
17 #include "clang/Basic/DiagnosticFrontend.h"
18 #include "clang/Basic/DiagnosticIDs.h"
19 #include "clang/Basic/DiagnosticOptions.h"
20 #include "clang/Basic/IdentifierTable.h"
21 #include "clang/Basic/PartialDiagnostic.h"
22 #include "clang/Basic/SourceLocation.h"
23 #include "clang/Basic/SourceManager.h"
24 #include "clang/Basic/Specifiers.h"
25 #include "clang/Basic/TokenKinds.h"
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>
51 using namespace clang;
53 const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
54 DiagNullabilityKind nullability) {
55 DB.AddString(
56 ("'" +
57 getNullabilitySpelling(nullability.first,
58 /*isContextSensitive=*/nullability.second) +
59 "'")
60 .str());
61 return DB;
64 const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
65 llvm::Error &&E) {
66 DB.AddString(toString(std::move(E)));
67 return DB;
70 static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
71 StringRef Modifier, StringRef Argument,
72 ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,
73 SmallVectorImpl<char> &Output,
74 void *Cookie,
75 ArrayRef<intptr_t> QualTypeVals) {
76 StringRef Str = "<can't format argument>";
77 Output.append(Str.begin(), Str.end());
80 DiagnosticsEngine::DiagnosticsEngine(
81 IntrusiveRefCntPtr<DiagnosticIDs> diags,
82 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, DiagnosticConsumer *client,
83 bool ShouldOwnClient)
84 : Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) {
85 setClient(client, ShouldOwnClient);
86 ArgToStringFn = DummyArgToStringFn;
88 Reset();
91 DiagnosticsEngine::~DiagnosticsEngine() {
92 // If we own the diagnostic client, destroy it first so that it can access the
93 // engine from its destructor.
94 setClient(nullptr);
97 void DiagnosticsEngine::dump() const {
98 DiagStatesByLoc.dump(*SourceMgr);
101 void DiagnosticsEngine::dump(StringRef DiagName) const {
102 DiagStatesByLoc.dump(*SourceMgr, DiagName);
105 void DiagnosticsEngine::setClient(DiagnosticConsumer *client,
106 bool ShouldOwnClient) {
107 Owner.reset(ShouldOwnClient ? client : nullptr);
108 Client = client;
111 void DiagnosticsEngine::pushMappings(SourceLocation Loc) {
112 DiagStateOnPushStack.push_back(GetCurDiagState());
115 bool DiagnosticsEngine::popMappings(SourceLocation Loc) {
116 if (DiagStateOnPushStack.empty())
117 return false;
119 if (DiagStateOnPushStack.back() != GetCurDiagState()) {
120 // State changed at some point between push/pop.
121 PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
123 DiagStateOnPushStack.pop_back();
124 return true;
127 void DiagnosticsEngine::Reset(bool soft /*=false*/) {
128 ErrorOccurred = false;
129 UncompilableErrorOccurred = false;
130 FatalErrorOccurred = false;
131 UnrecoverableErrorOccurred = false;
133 NumWarnings = 0;
134 NumErrors = 0;
135 TrapNumErrorsOccurred = 0;
136 TrapNumUnrecoverableErrorsOccurred = 0;
138 LastDiagLevel = DiagnosticIDs::Ignored;
140 if (!soft) {
141 // Clear state related to #pragma diagnostic.
142 DiagStates.clear();
143 DiagStatesByLoc.clear();
144 DiagStateOnPushStack.clear();
146 // Create a DiagState and DiagStatePoint representing diagnostic changes
147 // through command-line.
148 DiagStates.emplace_back();
149 DiagStatesByLoc.appendFirst(&DiagStates.back());
153 DiagnosticMapping &
154 DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) {
155 std::pair<iterator, bool> Result =
156 DiagMap.insert(std::make_pair(Diag, DiagnosticMapping()));
158 // Initialize the entry if we added it.
159 if (Result.second)
160 Result.first->second = DiagnosticIDs::getDefaultMapping(Diag);
162 return Result.first->second;
165 void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState *State) {
166 assert(Files.empty() && "not first");
167 FirstDiagState = CurDiagState = State;
168 CurDiagStateLoc = SourceLocation();
171 void DiagnosticsEngine::DiagStateMap::append(SourceManager &SrcMgr,
172 SourceLocation Loc,
173 DiagState *State) {
174 CurDiagState = State;
175 CurDiagStateLoc = Loc;
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");
185 if (Last.Offset == Offset) {
186 if (Last.State == State)
187 break;
188 Last.State = State;
189 continue;
192 F->StateTransitions.push_back({State, Offset});
196 DiagnosticsEngine::DiagState *
197 DiagnosticsEngine::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;
203 std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
204 const File *F = getFile(SrcMgr, Decomp.first);
205 return F->lookup(Decomp.second);
208 DiagnosticsEngine::DiagState *
209 DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const {
210 auto OnePastIt =
211 llvm::partition_point(StateTransitions, [=](const DiagStatePoint &P) {
212 return P.Offset <= Offset;
214 assert(OnePastIt != StateTransitions.begin() && "missing initial state");
215 return OnePastIt[-1].State;
218 DiagnosticsEngine::DiagStateMap::File *
219 DiagnosticsEngine::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;
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.
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});
244 return &F;
247 void 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";
253 for (auto &F : Files) {
254 FileID ID = F.first;
255 File &File = F.second;
257 bool PrintedOuterHeading = false;
258 auto PrintOuterHeading = [&] {
259 if (PrintedOuterHeading) return;
260 PrintedOuterHeading = true;
262 llvm::errs() << "File " << &File << " <FileID " << ID.getHashValue()
263 << ">: " << SrcMgr.getBufferOrFake(ID).getBufferIdentifier();
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);
275 if (File.HasLocalTransitions)
276 llvm::errs() << " has_local_transitions";
277 llvm::errs() << "\n";
280 if (DiagName.empty())
281 PrintOuterHeading();
283 for (DiagStatePoint &Transition : File.StateTransitions) {
284 bool PrintedInnerHeading = false;
285 auto PrintInnerHeading = [&] {
286 if (PrintedInnerHeading) return;
287 PrintedInnerHeading = true;
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";
297 if (DiagName.empty())
298 PrintInnerHeading();
300 for (auto &Mapping : *Transition.State) {
301 StringRef Option =
302 DiagnosticIDs::getWarningOptionForDiag(Mapping.first);
303 if (!DiagName.empty() && DiagName != Option)
304 continue;
306 PrintInnerHeading();
307 llvm::errs() << " ";
308 if (Option.empty())
309 llvm::errs() << "<unknown " << Mapping.first << ">";
310 else
311 llvm::errs() << Option;
312 llvm::errs() << ": ";
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;
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";
338 void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,
339 SourceLocation Loc) {
340 assert(Loc.isValid() && "Adding invalid loc point");
341 DiagStatesByLoc.append(*SourceMgr, Loc, State);
344 void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
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");
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 ||
359 Info.getSeverity() == diag::Severity::Fatal) {
360 Map = Info.getSeverity();
361 WasUpgradedFromWarning = true;
364 DiagnosticMapping Mapping = makeUserMapping(Map, L);
365 Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
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);
370 Mapping.setNoWarningAsError(Info.hasNoWarningAsError() ||
371 Mapping.hasNoWarningAsError());
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;
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);
392 bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
393 StringRef Group, diag::Severity Map,
394 SourceLocation Loc) {
395 // Get the diagnostics in this group.
396 SmallVector<diag::kind, 256> GroupDiags;
397 if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
398 return true;
400 // Set the mapping.
401 for (diag::kind Diag : GroupDiags)
402 setSeverity(Diag, Map, Loc);
404 return false;
407 bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
408 diag::Group Group,
409 diag::Severity Map,
410 SourceLocation Loc) {
411 return setSeverityForGroup(Flavor, Diags->getWarningOptionForGroup(Group),
412 Map, Loc);
415 bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
416 bool Enabled) {
417 // If we are enabling this feature, just set the diagnostic mappings to map to
418 // errors.
419 if (Enabled)
420 return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
421 diag::Severity::Error);
423 // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
424 // potentially downgrade anything already mapped to be a warning.
426 // Get the diagnostics in this group.
427 SmallVector<diag::kind, 8> GroupDiags;
428 if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
429 GroupDiags))
430 return true;
432 // Perform the mapping change.
433 for (diag::kind Diag : GroupDiags) {
434 DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
436 if (Info.getSeverity() == diag::Severity::Error ||
437 Info.getSeverity() == diag::Severity::Fatal)
438 Info.setSeverity(diag::Severity::Warning);
440 Info.setNoWarningAsError(true);
443 return false;
446 bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
447 bool Enabled) {
448 // If we are enabling this feature, just set the diagnostic mappings to map to
449 // fatal errors.
450 if (Enabled)
451 return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
452 diag::Severity::Fatal);
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.
457 // Get the diagnostics in this group.
458 SmallVector<diag::kind, 8> GroupDiags;
459 if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
460 GroupDiags))
461 return true;
463 // Perform the mapping change.
464 for (diag::kind Diag : GroupDiags) {
465 DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
467 if (Info.getSeverity() == diag::Severity::Fatal)
468 Info.setSeverity(diag::Severity::Error);
470 Info.setNoErrorAsFatal(true);
473 return false;
476 void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor,
477 diag::Severity Map,
478 SourceLocation Loc) {
479 // Get all the diagnostics.
480 std::vector<diag::kind> AllDiags;
481 DiagnosticIDs::getAllDiagnostics(Flavor, AllDiags);
483 // Set the mapping.
484 for (diag::kind Diag : AllDiags)
485 if (Diags->isBuiltinWarningOrExtension(Diag))
486 setSeverity(Diag, Map, Loc);
489 namespace {
490 // FIXME: We should isolate the parser from SpecialCaseList and just use it
491 // here.
492 class WarningsSpecialCaseList : public llvm::SpecialCaseList {
493 public:
494 static std::unique_ptr<WarningsSpecialCaseList>
495 create(const llvm::MemoryBuffer &Input, std::string &Err);
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);
503 bool isDiagSuppressed(diag::kind DiagId, StringRef FilePath) const;
505 private:
506 // Find the longest glob pattern that matches FilePath amongst
507 // CategoriesToMatchers, return true iff the match exists and belongs to a
508 // positive category.
509 bool globsMatches(const llvm::StringMap<Matcher> &CategoriesToMatchers,
510 StringRef FilePath) const;
512 llvm::DenseMap<diag::kind, const Section *> DiagToSection;
514 } // namespace
516 std::unique_ptr<WarningsSpecialCaseList>
517 WarningsSpecialCaseList::create(const llvm::MemoryBuffer &Input,
518 std::string &Err) {
519 auto WarningSuppressionList = std::make_unique<WarningsSpecialCaseList>();
520 if (!WarningSuppressionList->createInternal(&Input, Err))
521 return nullptr;
522 return WarningSuppressionList;
525 void WarningsSpecialCaseList::processSections(DiagnosticsEngine &Diags) {
526 // Drop the default section introduced by special case list, we only support
527 // exact diagnostic group names.
528 // FIXME: We should make this configurable in the parser instead.
529 Sections.erase("*");
530 // Make sure we iterate sections by their line numbers.
531 std::vector<std::pair<unsigned, const llvm::StringMapEntry<Section> *>>
532 LineAndSectionEntry;
533 LineAndSectionEntry.reserve(Sections.size());
534 for (const auto &Entry : Sections) {
535 StringRef DiagName = Entry.getKey();
536 // Each section has a matcher with that section's name, attached to that
537 // line.
538 const auto &DiagSectionMatcher = Entry.getValue().SectionMatcher;
539 unsigned DiagLine = DiagSectionMatcher->Globs.at(DiagName).second;
540 LineAndSectionEntry.emplace_back(DiagLine, &Entry);
542 llvm::sort(LineAndSectionEntry);
543 static constexpr auto WarningFlavor = clang::diag::Flavor::WarningOrError;
544 for (const auto &[_, SectionEntry] : LineAndSectionEntry) {
545 SmallVector<diag::kind> GroupDiags;
546 StringRef DiagGroup = SectionEntry->getKey();
547 if (Diags.getDiagnosticIDs()->getDiagnosticsInGroup(
548 WarningFlavor, DiagGroup, GroupDiags)) {
549 StringRef Suggestion =
550 DiagnosticIDs::getNearestOption(WarningFlavor, DiagGroup);
551 Diags.Report(diag::warn_unknown_diag_option)
552 << static_cast<unsigned>(WarningFlavor) << DiagGroup
553 << !Suggestion.empty() << Suggestion;
554 continue;
556 for (diag::kind Diag : GroupDiags)
557 // We're intentionally overwriting any previous mappings here to make sure
558 // latest one takes precedence.
559 DiagToSection[Diag] = &SectionEntry->getValue();
563 void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &Input) {
564 std::string Error;
565 auto WarningSuppressionList = WarningsSpecialCaseList::create(Input, Error);
566 if (!WarningSuppressionList) {
567 // FIXME: Use a `%select` statement instead of printing `Error` as-is. This
568 // should help localization.
569 Report(diag::err_drv_malformed_warning_suppression_mapping)
570 << Input.getBufferIdentifier() << Error;
571 return;
573 WarningSuppressionList->processSections(*this);
574 DiagSuppressionMapping =
575 [WarningSuppressionList(std::move(WarningSuppressionList))](
576 diag::kind DiagId, StringRef Path) {
577 return WarningSuppressionList->isDiagSuppressed(DiagId, Path);
581 bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
582 StringRef FilePath) const {
583 const Section *DiagSection = DiagToSection.lookup(DiagId);
584 if (!DiagSection)
585 return false;
586 const SectionEntries &EntityTypeToCategories = DiagSection->Entries;
587 auto SrcEntriesIt = EntityTypeToCategories.find("src");
588 if (SrcEntriesIt == EntityTypeToCategories.end())
589 return false;
590 const llvm::StringMap<llvm::SpecialCaseList::Matcher> &CategoriesToMatchers =
591 SrcEntriesIt->getValue();
592 return globsMatches(CategoriesToMatchers, FilePath);
595 bool WarningsSpecialCaseList::globsMatches(
596 const llvm::StringMap<Matcher> &CategoriesToMatchers,
597 StringRef FilePath) const {
598 StringRef LongestMatch;
599 bool LongestIsPositive = false;
600 for (const auto &Entry : CategoriesToMatchers) {
601 StringRef Category = Entry.getKey();
602 const llvm::SpecialCaseList::Matcher &Matcher = Entry.getValue();
603 bool IsPositive = Category != "emit";
604 for (const auto &[Pattern, Glob] : Matcher.Globs) {
605 if (Pattern.size() < LongestMatch.size())
606 continue;
607 if (!Glob.first.match(FilePath))
608 continue;
609 LongestMatch = Pattern;
610 LongestIsPositive = IsPositive;
613 return LongestIsPositive;
616 bool DiagnosticsEngine::isSuppressedViaMapping(diag::kind DiagId,
617 StringRef FilePath) const {
618 return DiagSuppressionMapping && DiagSuppressionMapping(DiagId, FilePath);
621 void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
622 DiagnosticStorage DiagStorage;
623 DiagStorage.DiagRanges.append(storedDiag.range_begin(),
624 storedDiag.range_end());
626 DiagStorage.FixItHints.append(storedDiag.fixit_begin(),
627 storedDiag.fixit_end());
629 assert(Client && "DiagnosticConsumer not set!");
630 Level DiagLevel = storedDiag.getLevel();
631 Diagnostic Info(this, storedDiag.getLocation(), storedDiag.getID(),
632 DiagStorage, storedDiag.getMessage());
633 Client->HandleDiagnostic(DiagLevel, Info);
634 if (Client->IncludeInDiagnosticCounts()) {
635 if (DiagLevel == DiagnosticsEngine::Warning)
636 ++NumWarnings;
640 bool DiagnosticsEngine::EmitDiagnostic(const DiagnosticBuilder &DB,
641 bool Force) {
642 assert(getClient() && "DiagnosticClient not set!");
644 bool Emitted;
645 if (Force) {
646 Diagnostic Info(this, DB);
648 // Figure out the diagnostic level of this message.
649 DiagnosticIDs::Level DiagLevel
650 = Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this);
652 Emitted = (DiagLevel != DiagnosticIDs::Ignored);
653 if (Emitted) {
654 // Emit the diagnostic regardless of suppression level.
655 Diags->EmitDiag(*this, DB, DiagLevel);
657 } else {
658 // Process the diagnostic, sending the accumulated information to the
659 // DiagnosticConsumer.
660 Emitted = ProcessDiag(DB);
663 return Emitted;
666 DiagnosticBuilder::DiagnosticBuilder(DiagnosticsEngine *DiagObj,
667 SourceLocation DiagLoc, unsigned DiagID)
668 : StreamingDiagnostic(DiagObj->DiagAllocator), DiagObj(DiagObj),
669 DiagLoc(DiagLoc), DiagID(DiagID), IsActive(true) {
670 assert(DiagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");
673 DiagnosticBuilder::DiagnosticBuilder(const DiagnosticBuilder &D)
674 : StreamingDiagnostic() {
675 DiagLoc = D.DiagLoc;
676 DiagID = D.DiagID;
677 FlagValue = D.FlagValue;
678 DiagObj = D.DiagObj;
679 DiagStorage = D.DiagStorage;
680 D.DiagStorage = nullptr;
681 Allocator = D.Allocator;
682 IsActive = D.IsActive;
683 IsForceEmit = D.IsForceEmit;
684 D.Clear();
687 Diagnostic::Diagnostic(const DiagnosticsEngine *DO,
688 const DiagnosticBuilder &DiagBuilder)
689 : DiagObj(DO), DiagLoc(DiagBuilder.DiagLoc), DiagID(DiagBuilder.DiagID),
690 FlagValue(DiagBuilder.FlagValue), DiagStorage(*DiagBuilder.getStorage()) {
693 Diagnostic::Diagnostic(const DiagnosticsEngine *DO, SourceLocation DiagLoc,
694 unsigned DiagID, const DiagnosticStorage &DiagStorage,
695 StringRef StoredDiagMessage)
696 : DiagObj(DO), DiagLoc(DiagLoc), DiagID(DiagID), DiagStorage(DiagStorage),
697 StoredDiagMessage(StoredDiagMessage) {}
699 DiagnosticConsumer::~DiagnosticConsumer() = default;
701 void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
702 const Diagnostic &Info) {
703 if (!IncludeInDiagnosticCounts())
704 return;
706 if (DiagLevel == DiagnosticsEngine::Warning)
707 ++NumWarnings;
708 else if (DiagLevel >= DiagnosticsEngine::Error)
709 ++NumErrors;
712 /// ModifierIs - Return true if the specified modifier matches specified string.
713 template <std::size_t StrLen>
714 static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
715 const char (&Str)[StrLen]) {
716 return StrLen-1 == ModifierLen && memcmp(Modifier, Str, StrLen-1) == 0;
719 /// ScanForward - Scans forward, looking for the given character, skipping
720 /// nested clauses and escaped characters.
721 static const char *ScanFormat(const char *I, const char *E, char Target) {
722 unsigned Depth = 0;
724 for ( ; I != E; ++I) {
725 if (Depth == 0 && *I == Target) return I;
726 if (Depth != 0 && *I == '}') Depth--;
728 if (*I == '%') {
729 I++;
730 if (I == E) break;
732 // Escaped characters get implicitly skipped here.
734 // Format specifier.
735 if (!isDigit(*I) && !isPunctuation(*I)) {
736 for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ;
737 if (I == E) break;
738 if (*I == '{')
739 Depth++;
743 return E;
746 /// HandleSelectModifier - Handle the integer 'select' modifier. This is used
747 /// like this: %select{foo|bar|baz}2. This means that the integer argument
748 /// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
749 /// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
750 /// This is very useful for certain classes of variant diagnostics.
751 static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
752 const char *Argument, unsigned ArgumentLen,
753 SmallVectorImpl<char> &OutStr) {
754 const char *ArgumentEnd = Argument+ArgumentLen;
756 // Skip over 'ValNo' |'s.
757 while (ValNo) {
758 const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
759 assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
760 " larger than the number of options in the diagnostic string!");
761 Argument = NextVal+1; // Skip this string.
762 --ValNo;
765 // Get the end of the value. This is either the } or the |.
766 const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
768 // Recursively format the result of the select clause into the output string.
769 DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
772 /// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
773 /// letter 's' to the string if the value is not 1. This is used in cases like
774 /// this: "you idiot, you have %4 parameter%s4!".
775 static void HandleIntegerSModifier(unsigned ValNo,
776 SmallVectorImpl<char> &OutStr) {
777 if (ValNo != 1)
778 OutStr.push_back('s');
781 /// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
782 /// prints the ordinal form of the given integer, with 1 corresponding
783 /// to the first ordinal. Currently this is hard-coded to use the
784 /// English form.
785 static void HandleOrdinalModifier(unsigned ValNo,
786 SmallVectorImpl<char> &OutStr) {
787 assert(ValNo != 0 && "ValNo must be strictly positive!");
789 llvm::raw_svector_ostream Out(OutStr);
791 // We could use text forms for the first N ordinals, but the numeric
792 // forms are actually nicer in diagnostics because they stand out.
793 Out << ValNo << llvm::getOrdinalSuffix(ValNo);
796 // 123 -> "123".
797 // 1234 -> "1.23k".
798 // 123456 -> "123.46k".
799 // 1234567 -> "1.23M".
800 // 1234567890 -> "1.23G".
801 // 1234567890123 -> "1.23T".
802 static void HandleIntegerHumanModifier(int64_t ValNo,
803 SmallVectorImpl<char> &OutStr) {
804 static constexpr std::array<std::pair<int64_t, char>, 4> Units = {
805 {{1'000'000'000'000L, 'T'},
806 {1'000'000'000L, 'G'},
807 {1'000'000L, 'M'},
808 {1'000L, 'k'}}};
810 llvm::raw_svector_ostream Out(OutStr);
811 if (ValNo < 0) {
812 Out << "-";
813 ValNo = -ValNo;
815 for (const auto &[UnitSize, UnitSign] : Units) {
816 if (ValNo >= UnitSize) {
817 Out << llvm::format("%0.2f%c", ValNo / static_cast<double>(UnitSize),
818 UnitSign);
819 return;
822 Out << ValNo;
825 /// PluralNumber - Parse an unsigned integer and advance Start.
826 static unsigned PluralNumber(const char *&Start, const char *End) {
827 // Programming 101: Parse a decimal number :-)
828 unsigned Val = 0;
829 while (Start != End && *Start >= '0' && *Start <= '9') {
830 Val *= 10;
831 Val += *Start - '0';
832 ++Start;
834 return Val;
837 /// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
838 static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
839 if (*Start != '[') {
840 unsigned Ref = PluralNumber(Start, End);
841 return Ref == Val;
844 ++Start;
845 unsigned Low = PluralNumber(Start, End);
846 assert(*Start == ',' && "Bad plural expression syntax: expected ,");
847 ++Start;
848 unsigned High = PluralNumber(Start, End);
849 assert(*Start == ']' && "Bad plural expression syntax: expected )");
850 ++Start;
851 return Low <= Val && Val <= High;
854 /// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
855 static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
856 // Empty condition?
857 if (*Start == ':')
858 return true;
860 while (true) {
861 char C = *Start;
862 if (C == '%') {
863 // Modulo expression
864 ++Start;
865 unsigned Arg = PluralNumber(Start, End);
866 assert(*Start == '=' && "Bad plural expression syntax: expected =");
867 ++Start;
868 unsigned ValMod = ValNo % Arg;
869 if (TestPluralRange(ValMod, Start, End))
870 return true;
871 } else {
872 assert((C == '[' || (C >= '0' && C <= '9')) &&
873 "Bad plural expression syntax: unexpected character");
874 // Range expression
875 if (TestPluralRange(ValNo, Start, End))
876 return true;
879 // Scan for next or-expr part.
880 Start = std::find(Start, End, ',');
881 if (Start == End)
882 break;
883 ++Start;
885 return false;
888 /// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
889 /// for complex plural forms, or in languages where all plurals are complex.
890 /// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
891 /// conditions that are tested in order, the form corresponding to the first
892 /// that applies being emitted. The empty condition is always true, making the
893 /// last form a default case.
894 /// Conditions are simple boolean expressions, where n is the number argument.
895 /// Here are the rules.
896 /// condition := expression | empty
897 /// empty := -> always true
898 /// expression := numeric [',' expression] -> logical or
899 /// numeric := range -> true if n in range
900 /// | '%' number '=' range -> true if n % number in range
901 /// range := number
902 /// | '[' number ',' number ']' -> ranges are inclusive both ends
904 /// Here are some examples from the GNU gettext manual written in this form:
905 /// English:
906 /// {1:form0|:form1}
907 /// Latvian:
908 /// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
909 /// Gaeilge:
910 /// {1:form0|2:form1|:form2}
911 /// Romanian:
912 /// {1:form0|0,%100=[1,19]:form1|:form2}
913 /// Lithuanian:
914 /// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
915 /// Russian (requires repeated form):
916 /// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
917 /// Slovak
918 /// {1:form0|[2,4]:form1|:form2}
919 /// Polish (requires repeated form):
920 /// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
921 static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
922 const char *Argument, unsigned ArgumentLen,
923 SmallVectorImpl<char> &OutStr) {
924 const char *ArgumentEnd = Argument + ArgumentLen;
925 while (true) {
926 assert(Argument < ArgumentEnd && "Plural expression didn't match.");
927 const char *ExprEnd = Argument;
928 while (*ExprEnd != ':') {
929 assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
930 ++ExprEnd;
932 if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
933 Argument = ExprEnd + 1;
934 ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
936 // Recursively format the result of the plural clause into the
937 // output string.
938 DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
939 return;
941 Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
945 /// Returns the friendly description for a token kind that will appear
946 /// without quotes in diagnostic messages. These strings may be translatable in
947 /// future.
948 static const char *getTokenDescForDiagnostic(tok::TokenKind Kind) {
949 switch (Kind) {
950 case tok::identifier:
951 return "identifier";
952 default:
953 return nullptr;
957 /// FormatDiagnostic - Format this diagnostic into a string, substituting the
958 /// formal arguments into the %0 slots. The result is appended onto the Str
959 /// array.
960 void Diagnostic::
961 FormatDiagnostic(SmallVectorImpl<char> &OutStr) const {
962 if (StoredDiagMessage.has_value()) {
963 OutStr.append(StoredDiagMessage->begin(), StoredDiagMessage->end());
964 return;
967 StringRef Diag =
968 getDiags()->getDiagnosticIDs()->getDescription(getID());
970 FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
973 /// EscapeStringForDiagnostic - Append Str to the diagnostic buffer,
974 /// escaping non-printable characters and ill-formed code unit sequences.
975 void clang::EscapeStringForDiagnostic(StringRef Str,
976 SmallVectorImpl<char> &OutStr) {
977 OutStr.reserve(OutStr.size() + Str.size());
978 auto *Begin = reinterpret_cast<const unsigned char *>(Str.data());
979 llvm::raw_svector_ostream OutStream(OutStr);
980 const unsigned char *End = Begin + Str.size();
981 while (Begin != End) {
982 // ASCII case
983 if (isPrintable(*Begin) || isWhitespace(*Begin)) {
984 OutStream << *Begin;
985 ++Begin;
986 continue;
988 if (llvm::isLegalUTF8Sequence(Begin, End)) {
989 llvm::UTF32 CodepointValue;
990 llvm::UTF32 *CpPtr = &CodepointValue;
991 const unsigned char *CodepointBegin = Begin;
992 const unsigned char *CodepointEnd =
993 Begin + llvm::getNumBytesForUTF8(*Begin);
994 llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(
995 &Begin, CodepointEnd, &CpPtr, CpPtr + 1, llvm::strictConversion);
996 (void)Res;
997 assert(
998 llvm::conversionOK == Res &&
999 "the sequence is legal UTF-8 but we couldn't convert it to UTF-32");
1000 assert(Begin == CodepointEnd &&
1001 "we must be further along in the string now");
1002 if (llvm::sys::unicode::isPrintable(CodepointValue) ||
1003 llvm::sys::unicode::isFormatting(CodepointValue)) {
1004 OutStr.append(CodepointBegin, CodepointEnd);
1005 continue;
1007 // Unprintable code point.
1008 OutStream << "<U+" << llvm::format_hex_no_prefix(CodepointValue, 4, true)
1009 << ">";
1010 continue;
1012 // Invalid code unit.
1013 OutStream << "<" << llvm::format_hex_no_prefix(*Begin, 2, true) << ">";
1014 ++Begin;
1018 void Diagnostic::
1019 FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
1020 SmallVectorImpl<char> &OutStr) const {
1021 // When the diagnostic string is only "%0", the entire string is being given
1022 // by an outside source. Remove unprintable characters from this string
1023 // and skip all the other string processing.
1024 if (DiagEnd - DiagStr == 2 && StringRef(DiagStr, DiagEnd - DiagStr) == "%0" &&
1025 getArgKind(0) == DiagnosticsEngine::ak_std_string) {
1026 const std::string &S = getArgStdStr(0);
1027 EscapeStringForDiagnostic(S, OutStr);
1028 return;
1031 /// FormattedArgs - Keep track of all of the arguments formatted by
1032 /// ConvertArgToString and pass them into subsequent calls to
1033 /// ConvertArgToString, allowing the implementation to avoid redundancies in
1034 /// obvious cases.
1035 SmallVector<DiagnosticsEngine::ArgumentValue, 8> FormattedArgs;
1037 /// QualTypeVals - Pass a vector of arrays so that QualType names can be
1038 /// compared to see if more information is needed to be printed.
1039 SmallVector<intptr_t, 2> QualTypeVals;
1040 SmallString<64> Tree;
1042 for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
1043 if (getArgKind(i) == DiagnosticsEngine::ak_qualtype)
1044 QualTypeVals.push_back(getRawArg(i));
1046 while (DiagStr != DiagEnd) {
1047 if (DiagStr[0] != '%') {
1048 // Append non-%0 substrings to Str if we have one.
1049 const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
1050 OutStr.append(DiagStr, StrEnd);
1051 DiagStr = StrEnd;
1052 continue;
1053 } else if (isPunctuation(DiagStr[1])) {
1054 OutStr.push_back(DiagStr[1]); // %% -> %.
1055 DiagStr += 2;
1056 continue;
1059 // Skip the %.
1060 ++DiagStr;
1062 // This must be a placeholder for a diagnostic argument. The format for a
1063 // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
1064 // The digit is a number from 0-9 indicating which argument this comes from.
1065 // The modifier is a string of digits from the set [-a-z]+, arguments is a
1066 // brace enclosed string.
1067 const char *Modifier = nullptr, *Argument = nullptr;
1068 unsigned ModifierLen = 0, ArgumentLen = 0;
1070 // Check to see if we have a modifier. If so eat it.
1071 if (!isDigit(DiagStr[0])) {
1072 Modifier = DiagStr;
1073 while (DiagStr[0] == '-' ||
1074 (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
1075 ++DiagStr;
1076 ModifierLen = DiagStr-Modifier;
1078 // If we have an argument, get it next.
1079 if (DiagStr[0] == '{') {
1080 ++DiagStr; // Skip {.
1081 Argument = DiagStr;
1083 DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
1084 assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
1085 ArgumentLen = DiagStr-Argument;
1086 ++DiagStr; // Skip }.
1090 assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
1091 unsigned ArgNo = *DiagStr++ - '0';
1093 // Only used for type diffing.
1094 unsigned ArgNo2 = ArgNo;
1096 DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo);
1097 if (ModifierIs(Modifier, ModifierLen, "diff")) {
1098 assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
1099 "Invalid format for diff modifier");
1100 ++DiagStr; // Comma.
1101 ArgNo2 = *DiagStr++ - '0';
1102 DiagnosticsEngine::ArgumentKind Kind2 = getArgKind(ArgNo2);
1103 if (Kind == DiagnosticsEngine::ak_qualtype &&
1104 Kind2 == DiagnosticsEngine::ak_qualtype)
1105 Kind = DiagnosticsEngine::ak_qualtype_pair;
1106 else {
1107 // %diff only supports QualTypes. For other kinds of arguments,
1108 // use the default printing. For example, if the modifier is:
1109 // "%diff{compare $ to $|other text}1,2"
1110 // treat it as:
1111 // "compare %1 to %2"
1112 const char *ArgumentEnd = Argument + ArgumentLen;
1113 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1114 assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd &&
1115 "Found too many '|'s in a %diff modifier!");
1116 const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
1117 const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
1118 const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) };
1119 const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) };
1120 FormatDiagnostic(Argument, FirstDollar, OutStr);
1121 FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
1122 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1123 FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
1124 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1125 continue;
1129 switch (Kind) {
1130 // ---- STRINGS ----
1131 case DiagnosticsEngine::ak_std_string: {
1132 const std::string &S = getArgStdStr(ArgNo);
1133 assert(ModifierLen == 0 && "No modifiers for strings yet");
1134 EscapeStringForDiagnostic(S, OutStr);
1135 break;
1137 case DiagnosticsEngine::ak_c_string: {
1138 const char *S = getArgCStr(ArgNo);
1139 assert(ModifierLen == 0 && "No modifiers for strings yet");
1141 // Don't crash if get passed a null pointer by accident.
1142 if (!S)
1143 S = "(null)";
1144 EscapeStringForDiagnostic(S, OutStr);
1145 break;
1147 // ---- INTEGERS ----
1148 case DiagnosticsEngine::ak_sint: {
1149 int64_t Val = getArgSInt(ArgNo);
1151 if (ModifierIs(Modifier, ModifierLen, "select")) {
1152 HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1153 OutStr);
1154 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1155 HandleIntegerSModifier(Val, OutStr);
1156 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1157 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1158 OutStr);
1159 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1160 HandleOrdinalModifier((unsigned)Val, OutStr);
1161 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1162 HandleIntegerHumanModifier(Val, OutStr);
1163 } else {
1164 assert(ModifierLen == 0 && "Unknown integer modifier");
1165 llvm::raw_svector_ostream(OutStr) << Val;
1167 break;
1169 case DiagnosticsEngine::ak_uint: {
1170 uint64_t Val = getArgUInt(ArgNo);
1172 if (ModifierIs(Modifier, ModifierLen, "select")) {
1173 HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
1174 } else if (ModifierIs(Modifier, ModifierLen, "s")) {
1175 HandleIntegerSModifier(Val, OutStr);
1176 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
1177 HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
1178 OutStr);
1179 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
1180 HandleOrdinalModifier(Val, OutStr);
1181 } else if (ModifierIs(Modifier, ModifierLen, "human")) {
1182 HandleIntegerHumanModifier(Val, OutStr);
1183 } else {
1184 assert(ModifierLen == 0 && "Unknown integer modifier");
1185 llvm::raw_svector_ostream(OutStr) << Val;
1187 break;
1189 // ---- TOKEN SPELLINGS ----
1190 case DiagnosticsEngine::ak_tokenkind: {
1191 tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo));
1192 assert(ModifierLen == 0 && "No modifiers for token kinds yet");
1194 llvm::raw_svector_ostream Out(OutStr);
1195 if (const char *S = tok::getPunctuatorSpelling(Kind))
1196 // Quoted token spelling for punctuators.
1197 Out << '\'' << S << '\'';
1198 else if ((S = tok::getKeywordSpelling(Kind)))
1199 // Unquoted token spelling for keywords.
1200 Out << S;
1201 else if ((S = getTokenDescForDiagnostic(Kind)))
1202 // Unquoted translatable token name.
1203 Out << S;
1204 else if ((S = tok::getTokenName(Kind)))
1205 // Debug name, shouldn't appear in user-facing diagnostics.
1206 Out << '<' << S << '>';
1207 else
1208 Out << "(null)";
1209 break;
1211 // ---- NAMES and TYPES ----
1212 case DiagnosticsEngine::ak_identifierinfo: {
1213 const IdentifierInfo *II = getArgIdentifier(ArgNo);
1214 assert(ModifierLen == 0 && "No modifiers for strings yet");
1216 // Don't crash if get passed a null pointer by accident.
1217 if (!II) {
1218 const char *S = "(null)";
1219 OutStr.append(S, S + strlen(S));
1220 continue;
1223 llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
1224 break;
1226 case DiagnosticsEngine::ak_addrspace:
1227 case DiagnosticsEngine::ak_qual:
1228 case DiagnosticsEngine::ak_qualtype:
1229 case DiagnosticsEngine::ak_declarationname:
1230 case DiagnosticsEngine::ak_nameddecl:
1231 case DiagnosticsEngine::ak_nestednamespec:
1232 case DiagnosticsEngine::ak_declcontext:
1233 case DiagnosticsEngine::ak_attr:
1234 getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
1235 StringRef(Modifier, ModifierLen),
1236 StringRef(Argument, ArgumentLen),
1237 FormattedArgs,
1238 OutStr, QualTypeVals);
1239 break;
1240 case DiagnosticsEngine::ak_qualtype_pair: {
1241 // Create a struct with all the info needed for printing.
1242 TemplateDiffTypes TDT;
1243 TDT.FromType = getRawArg(ArgNo);
1244 TDT.ToType = getRawArg(ArgNo2);
1245 TDT.ElideType = getDiags()->ElideType;
1246 TDT.ShowColors = getDiags()->ShowColors;
1247 TDT.TemplateDiffUsed = false;
1248 intptr_t val = reinterpret_cast<intptr_t>(&TDT);
1250 const char *ArgumentEnd = Argument + ArgumentLen;
1251 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
1253 // Print the tree. If this diagnostic already has a tree, skip the
1254 // second tree.
1255 if (getDiags()->PrintTemplateTree && Tree.empty()) {
1256 TDT.PrintFromType = true;
1257 TDT.PrintTree = true;
1258 getDiags()->ConvertArgToString(Kind, val,
1259 StringRef(Modifier, ModifierLen),
1260 StringRef(Argument, ArgumentLen),
1261 FormattedArgs,
1262 Tree, QualTypeVals);
1263 // If there is no tree information, fall back to regular printing.
1264 if (!Tree.empty()) {
1265 FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr);
1266 break;
1270 // Non-tree printing, also the fall-back when tree printing fails.
1271 // The fall-back is triggered when the types compared are not templates.
1272 const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');
1273 const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');
1275 // Append before text
1276 FormatDiagnostic(Argument, FirstDollar, OutStr);
1278 // Append first type
1279 TDT.PrintTree = false;
1280 TDT.PrintFromType = true;
1281 getDiags()->ConvertArgToString(Kind, val,
1282 StringRef(Modifier, ModifierLen),
1283 StringRef(Argument, ArgumentLen),
1284 FormattedArgs,
1285 OutStr, QualTypeVals);
1286 if (!TDT.TemplateDiffUsed)
1287 FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
1288 TDT.FromType));
1290 // Append middle text
1291 FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
1293 // Append second type
1294 TDT.PrintFromType = false;
1295 getDiags()->ConvertArgToString(Kind, val,
1296 StringRef(Modifier, ModifierLen),
1297 StringRef(Argument, ArgumentLen),
1298 FormattedArgs,
1299 OutStr, QualTypeVals);
1300 if (!TDT.TemplateDiffUsed)
1301 FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
1302 TDT.ToType));
1304 // Append end text
1305 FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
1306 break;
1310 // Remember this argument info for subsequent formatting operations. Turn
1311 // std::strings into a null terminated string to make it be the same case as
1312 // all the other ones.
1313 if (Kind == DiagnosticsEngine::ak_qualtype_pair)
1314 continue;
1315 else if (Kind != DiagnosticsEngine::ak_std_string)
1316 FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
1317 else
1318 FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string,
1319 (intptr_t)getArgStdStr(ArgNo).c_str()));
1322 // Append the type tree to the end of the diagnostics.
1323 OutStr.append(Tree.begin(), Tree.end());
1326 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
1327 StringRef Message)
1328 : ID(ID), Level(Level), Message(Message) {}
1330 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level,
1331 const Diagnostic &Info)
1332 : ID(Info.getID()), Level(Level) {
1333 assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
1334 "Valid source location without setting a source manager for diagnostic");
1335 if (Info.getLocation().isValid())
1336 Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
1337 SmallString<64> Message;
1338 Info.FormatDiagnostic(Message);
1339 this->Message.assign(Message.begin(), Message.end());
1340 this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end());
1341 this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end());
1344 StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
1345 StringRef Message, FullSourceLoc Loc,
1346 ArrayRef<CharSourceRange> Ranges,
1347 ArrayRef<FixItHint> FixIts)
1348 : ID(ID), Level(Level), Loc(Loc), Message(Message),
1349 Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())
1353 llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
1354 const StoredDiagnostic &SD) {
1355 if (SD.getLocation().hasManager())
1356 OS << SD.getLocation().printToString(SD.getLocation().getManager()) << ": ";
1357 OS << SD.getMessage();
1358 return OS;
1361 /// IncludeInDiagnosticCounts - This method (whose default implementation
1362 /// returns true) indicates whether the diagnostics handled by this
1363 /// DiagnosticConsumer should be included in the number of diagnostics
1364 /// reported by DiagnosticsEngine.
1365 bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; }
1367 void IgnoringDiagConsumer::anchor() {}
1369 ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() = default;
1371 void ForwardingDiagnosticConsumer::HandleDiagnostic(
1372 DiagnosticsEngine::Level DiagLevel,
1373 const Diagnostic &Info) {
1374 Target.HandleDiagnostic(DiagLevel, Info);
1377 void ForwardingDiagnosticConsumer::clear() {
1378 DiagnosticConsumer::clear();
1379 Target.clear();
1382 bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const {
1383 return Target.IncludeInDiagnosticCounts();
1386 DiagStorageAllocator::DiagStorageAllocator() {
1387 for (unsigned I = 0; I != NumCached; ++I)
1388 FreeList[I] = Cached + I;
1389 NumFreeListEntries = NumCached;
1392 DiagStorageAllocator::~DiagStorageAllocator() {
1393 // Don't assert if we are in a CrashRecovery context, as this invariant may
1394 // be invalidated during a crash.
1395 assert((NumFreeListEntries == NumCached ||
1396 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1397 "A partial is on the lam");
1400 char DiagnosticError::ID;