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