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