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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/lib/Basic/Diagnostic.cpp