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