clang: lib/Basic/Diagnostic.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

26#include "llvm/ADT/IntrusiveRefCntPtr.h"

27#include "llvm/ADT/SmallString.h"

28#include "llvm/ADT/SmallVector.h"

29#include "llvm/ADT/StringExtras.h"

30#include "llvm/ADT/StringMap.h"

31#include "llvm/ADT/StringRef.h"

32#include "llvm/Support/ConvertUTF.h"

33#include "llvm/Support/CrashRecoveryContext.h"

34#include "llvm/Support/Error.h"

35#include "llvm/Support/MemoryBuffer.h"

36#include "llvm/Support/SpecialCaseList.h"

37#include "llvm/Support/Unicode.h"

38#include "llvm/Support/VirtualFileSystem.h"

39#include "llvm/Support/raw_ostream.h"

40#include

41#include

42#include

43#include

44#include

45#include

46#include

47#include

48#include

49#include

50

51using namespace clang;

52

56 ("'" +

58 nullability.second) +

59 "'")

60 .str());

61 return DB;

62}

63

65 llvm::Error &&E) {

67 return DB;

68}

69

71 StringRef Modifier, StringRef Argument,

74 void *Cookie,

76 StringRef Str = "<can't format argument>";

77 Output.append(Str.begin(), Str.end());

78}

79

83 bool ShouldOwnClient)

84 : Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) {

85 setClient(client, ShouldOwnClient);

87

89}

90

92

93

95}

96

98 DiagStatesByLoc.dump(*SourceMgr);

99}

100

102 DiagStatesByLoc.dump(*SourceMgr, DiagName);

103}

104

106 bool ShouldOwnClient) {

107 Owner.reset(ShouldOwnClient ? client : nullptr);

108 Client = client;

109}

110

112 DiagStateOnPushStack.push_back(GetCurDiagState());

113}

114

116 if (DiagStateOnPushStack.empty())

117 return false;

118

119 if (DiagStateOnPushStack.back() != GetCurDiagState()) {

120

121 PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);

122 }

123 DiagStateOnPushStack.pop_back();

124 return true;

125}

126

128 ErrorOccurred = false;

129 UncompilableErrorOccurred = false;

130 FatalErrorOccurred = false;

131 UnrecoverableErrorOccurred = false;

132

133 NumWarnings = 0;

134 NumErrors = 0;

135 TrapNumErrorsOccurred = 0;

136 TrapNumUnrecoverableErrorsOccurred = 0;

137

139

140 if (!soft) {

141

142 DiagStates.clear();

143 DiagStatesByLoc.clear();

144 DiagStateOnPushStack.clear();

145

146

147

148 DiagStates.emplace_back();

149 DiagStatesByLoc.appendFirst(&DiagStates.back());

150 }

151}

152

154DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) {

155 std::pair<iterator, bool> Result =

157

158

161

162 return Result.first->second;

163}

164

165void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState *State) {

166 assert(Files.empty() && "not first");

167 FirstDiagState = CurDiagState = State;

169}

170

171void DiagnosticsEngine::DiagStateMap::append(SourceManager &SrcMgr,

173 DiagState *State) {

174 CurDiagState = State;

175 CurDiagStateLoc = Loc;

176

178 unsigned Offset = Decomp.second;

179 for (File *F = getFile(SrcMgr, Decomp.first); F;

180 Offset = F->ParentOffset, F = F->Parent) {

181 F->HasLocalTransitions = true;

182 auto &Last = F->StateTransitions.back();

183 assert(Last.Offset <= Offset && "state transitions added out of order");

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({State, Offset});

193 }

194}

195

196DiagnosticsEngine::DiagState *

197DiagnosticsEngine::DiagStateMap::lookup(SourceManager &SrcMgr,

199

200 if (Files.empty())

201 return FirstDiagState;

202

204 const File *F = getFile(SrcMgr, Decomp.first);

205 return F->lookup(Decomp.second);

206}

207

208DiagnosticsEngine::DiagState *

209DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const {

210 auto OnePastIt =

211 llvm::partition_point(StateTransitions, [=](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,

221

222 auto Range = Files.equal_range(ID);

224 return &Range.first->second;

225 auto &F = Files.insert(Range.first, std::make_pair(ID, File()))->second;

226

227

228

229 if (ID.isValid()) {

231 F.Parent = getFile(SrcMgr, Decomp.first);

232 F.ParentOffset = Decomp.second;

233 F.StateTransitions.push_back({F.Parent->lookup(Decomp.second), 0});

234 } else {

235

236

237

238

239

240

241

242 F.StateTransitions.push_back({FirstDiagState, 0});

243 }

244 return &F;

245}

246

247void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr,

248 StringRef DiagName) const {

249 llvm::errs() << "diagnostic state at ";

250 CurDiagStateLoc.print(llvm::errs(), SrcMgr);

251 llvm::errs() << ": " << CurDiagState << "\n";

252

253 for (auto &F : Files) {

256

257 bool PrintedOuterHeading = false;

258 auto PrintOuterHeading = [&] {

259 if (PrintedOuterHeading) return;

260 PrintedOuterHeading = true;

261

262 llvm::errs() << "File " << &File << " <FileID " << ID.getHashValue()

263 << ">: " << SrcMgr.getBufferOrFake(ID).getBufferIdentifier();

264

265 if (F.second.Parent) {

266 std::pair<FileID, unsigned> Decomp =

268 assert(File.ParentOffset == Decomp.second);

269 llvm::errs() << " parent " << File.Parent << " <FileID "

270 << Decomp.first.getHashValue() << "> ";

273 .print(llvm::errs(), SrcMgr);

274 }

275 if (File.HasLocalTransitions)

276 llvm::errs() << " has_local_transitions";

277 llvm::errs() << "\n";

278 };

279

280 if (DiagName.empty())

281 PrintOuterHeading();

282

283 for (DiagStatePoint &Transition : File.StateTransitions) {

284 bool PrintedInnerHeading = false;

285 auto PrintInnerHeading = [&] {

286 if (PrintedInnerHeading) return;

287 PrintedInnerHeading = true;

288

289 PrintOuterHeading();

290 llvm::errs() << " ";

293 .print(llvm::errs(), 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 =

303 if (!DiagName.empty() && DiagName != Option)

304 continue;

305

306 PrintInnerHeading();

307 llvm::errs() << " ";

308 if (Option.empty())

309 llvm::errs() << "<unknown " << Mapping.first << ">";

310 else

311 llvm::errs() << Option;

312 llvm::errs() << ": ";

313

314 switch (Mapping.second.getSeverity()) {

320 }

321

322 if (!Mapping.second.isUser())

323 llvm::errs() << " default";

324 if (Mapping.second.isPragma())

325 llvm::errs() << " pragma";

326 if (Mapping.second.hasNoWarningAsError())

327 llvm::errs() << " no-error";

328 if (Mapping.second.hasNoErrorAsFatal())

329 llvm::errs() << " no-fatal";

330 if (Mapping.second.wasUpgradedFromWarning())

331 llvm::errs() << " overruled";

332 llvm::errs() << "\n";

333 }

334 }

335 }

336}

337

338void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,

340 assert(Loc.isValid() && "Adding invalid loc point");

341 DiagStatesByLoc.append(*SourceMgr, Loc, State);

342}

343

347 "Can only map builtin diagnostics");

348 assert((Diags->isBuiltinWarningOrExtension(Diag) ||

350 "Cannot map errors into warnings!");

351 assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");

352

353

354

355 bool WasUpgradedFromWarning = false;

361 WasUpgradedFromWarning = true;

362 }

363 }

366

367

368

372

373

374 if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) &&

375 DiagStatesByLoc.getCurDiagState()) {

376

377

378

379

380 DiagStatesByLoc.getCurDiagState()->setMapping(Diag, Mapping);

381 return;

382 }

383

384

385

386

387 DiagStates.push_back(*GetCurDiagState());

388 DiagStates.back().setMapping(Diag, Mapping);

389 PushDiagStatePoint(&DiagStates.back(), L);

390}

391

395

397 if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))

398 return true;

399

400

403

404 return false;

405}

406

411 return setSeverityForGroup(Flavor, Diags->getWarningOptionForGroup(Group),

412 Map, Loc);

413}

414

416 bool Enabled) {

417

418

419 if (Enabled)

422

423

424

425

426

429 GroupDiags))

430 return true;

431

432

435

439

441 }

442

443 return false;

444}

445

447 bool Enabled) {

448

449

450 if (Enabled)

453

454

455

456

457

460 GroupDiags))

461 return true;

462

463

466

469

471 }

472

473 return false;

474}

475

479

480 std::vectordiag::kind AllDiags;

482

483

485 if (Diags->isBuiltinWarningOrExtension(Diag))

487}

488

489namespace {

490

491

492class WarningsSpecialCaseList : public llvm::SpecialCaseList {

493public:

494 static std::unique_ptr

495 create(const llvm::MemoryBuffer &Input, std::string &Err);

496

497

498

499

500

502

505

506private:

507

508

509

510 bool globsMatches(const llvm::StringMap &CategoriesToMatchers,

511 StringRef FilePath) const;

512

513 llvm::DenseMap<diag::kind, const Section *> DiagToSection;

514};

515}

516

517std::unique_ptr

518WarningsSpecialCaseList::create(const llvm::MemoryBuffer &Input,

519 std::string &Err) {

520 auto WarningSuppressionList = std::make_unique();

521 if (!WarningSuppressionList->createInternal(&Input, Err))

522 return nullptr;

523 return WarningSuppressionList;

524}

525

526void WarningsSpecialCaseList::processSections(DiagnosticsEngine &Diags) {

527

528

529

530 Sections.erase("*");

531

532 std::vector<std::pair<unsigned, const llvm::StringMapEntry

*>>

533 LineAndSectionEntry;

534 LineAndSectionEntry.reserve(Sections.size());

535 for (const auto &Entry : Sections) {

536 StringRef DiagName = Entry.getKey();

537

538

539 const auto &DiagSectionMatcher = Entry.getValue().SectionMatcher;

540 unsigned DiagLine = DiagSectionMatcher->Globs.at(DiagName).second;

541 LineAndSectionEntry.emplace_back(DiagLine, &Entry);

542 }

543 llvm::sort(LineAndSectionEntry);

545 for (const auto &[_, SectionEntry] : LineAndSectionEntry) {

547 StringRef DiagGroup = SectionEntry->getKey();

549 WarningFlavor, DiagGroup, GroupDiags)) {

550 StringRef Suggestion =

552 Diags.Report(diag::warn_unknown_diag_option)

553 << static_cast<unsigned>(WarningFlavor) << DiagGroup

554 << !Suggestion.empty() << Suggestion;

555 continue;

556 }

558

559

560 DiagToSection[Diag] = &SectionEntry->getValue();

561 }

562}

563

565 std::string Error;

566 auto WarningSuppressionList = WarningsSpecialCaseList::create(Input, Error);

567 if (!WarningSuppressionList) {

568

569

570 Report(diag::err_drv_malformed_warning_suppression_mapping)

571 << Input.getBufferIdentifier() << Error;

572 return;

573 }

574 WarningSuppressionList->processSections(*this);

575 DiagSuppressionMapping =

576 [WarningSuppressionList(std::move(WarningSuppressionList))](

578 return WarningSuppressionList->isDiagSuppressed(DiagId, DiagLoc, SM);

579 };

580}

581

582bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,

585 const Section *DiagSection = DiagToSection.lookup(DiagId);

586 if (!DiagSection)

587 return false;

588 const SectionEntries &EntityTypeToCategories = DiagSection->Entries;

589 auto SrcEntriesIt = EntityTypeToCategories.find("src");

590 if (SrcEntriesIt == EntityTypeToCategories.end())

591 return false;

592 const llvm::StringMapllvm::SpecialCaseList::Matcher &CategoriesToMatchers =

593 SrcEntriesIt->getValue();

594

595

596 if (PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc); PLoc.isValid())

597 return globsMatches(

598 CategoriesToMatchers,

599 llvm::sys::path::remove_leading_dotslash(PLoc.getFilename()));

600 return false;

601}

602

603bool WarningsSpecialCaseList::globsMatches(

604 const llvm::StringMap &CategoriesToMatchers,

605 StringRef FilePath) const {

606 StringRef LongestMatch;

607 bool LongestIsPositive = false;

608 for (const auto &Entry : CategoriesToMatchers) {

609 StringRef Category = Entry.getKey();

610 const llvm::SpecialCaseList::Matcher &Matcher = Entry.getValue();

611 bool IsPositive = Category != "emit";

612 for (const auto &[Pattern, Glob] : Matcher.Globs) {

613 if (Pattern.size() < LongestMatch.size())

614 continue;

615 if (!Glob.first.match(FilePath))

616 continue;

617 LongestMatch = Pattern;

618 LongestIsPositive = IsPositive;

619 }

620 }

621 return LongestIsPositive;

622}

623

627 return false;

628 return DiagSuppressionMapping(DiagId, DiagLoc, getSourceManager());

629}

630

635

638

639 assert(Client && "DiagnosticConsumer not set!");

642 DiagStorage, storedDiag.getMessage());

646 ++NumWarnings;

647 }

648}

649

651 bool Force) {

652 assert(getClient() && "DiagnosticClient not set!");

653

654 bool Emitted;

655 if (Force) {

657

658

661

663 if (Emitted) {

664

665 Diags->EmitDiag(*this, DB, DiagLevel);

666 }

667 } else {

668

669

670 Emitted = ProcessDiag(DB);

671 }

672

673 return Emitted;

674}

675

679 DiagLoc(DiagLoc), DiagID(DiagID), IsActive(true) {

680 assert(DiagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");

681}

682

685 DiagLoc = D.DiagLoc;

686 DiagID = D.DiagID;

687 FlagValue = D.FlagValue;

688 DiagObj = D.DiagObj;

690 D.DiagStorage = nullptr;

692 IsActive = D.IsActive;

693 IsForceEmit = D.IsForceEmit;

694 D.Clear();

695}

696

699 : DiagObj(DO), DiagLoc(DiagBuilder.DiagLoc), DiagID(DiagBuilder.DiagID),

700 FlagValue(DiagBuilder.FlagValue), DiagStorage(*DiagBuilder.getStorage()) {

701}

702

705 StringRef StoredDiagMessage)

706 : DiagObj(DO), DiagLoc(DiagLoc), DiagID(DiagID), DiagStorage(DiagStorage),

707 StoredDiagMessage(StoredDiagMessage) {}

708

710

714 return;

715

720}

721

722

723template <std::size_t StrLen>

724static bool ModifierIs(const char *Modifier, unsigned ModifierLen,

725 const char (&Str)[StrLen]) {

726 return StrLen-1 == ModifierLen && memcmp(Modifier, Str, StrLen-1) == 0;

727}

728

729

730

732 unsigned Depth = 0;

733

734 for ( ; I != E; ++I) {

735 if (Depth == 0 && *I == Target) return I;

736 if (Depth != 0 && *I == '}') Depth--;

737

738 if (*I == '%') {

739 I++;

740 if (I == E) break;

741

742

743

744

746 for (I++; I != E && isDigit(*I) && *I != '{'; I++) ;

747 if (I == E) break;

748 if (*I == '{')

749 Depth++;

750 }

751 }

752 }

753 return E;

754}

755

756

757

758

759

760

762 const char *Argument, unsigned ArgumentLen,

764 const char *ArgumentEnd = Argument+ArgumentLen;

765

766

767 while (ValNo) {

768 const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');

769 assert(NextVal != ArgumentEnd && "Value for integer select modifier was"

770 " larger than the number of options in the diagnostic string!");

771 Argument = NextVal+1;

772 --ValNo;

773 }

774

775

776 const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');

777

778

780}

781

782

783

784

787 if (ValNo != 1)

788 OutStr.push_back('s');

789}

790

791

792

793

794

797 assert(ValNo != 0 && "ValNo must be strictly positive!");

798

799 llvm::raw_svector_ostream Out(OutStr);

800

801

802

803 Out << ValNo << llvm::getOrdinalSuffix(ValNo);

804}

805

806

807

808

809

810

811

814 static constexpr std::array<std::pair<int64_t, char>, 4> Units = {

815 {{1'000'000'000'000L, 'T'},

816 {1'000'000'000L, 'G'},

817 {1'000'000L, 'M'},

818 {1'000L, 'k'}}};

819

820 llvm::raw_svector_ostream Out(OutStr);

821 if (ValNo < 0) {

822 Out << "-";

823 ValNo = -ValNo;

824 }

825 for (const auto &[UnitSize, UnitSign] : Units) {

826 if (ValNo >= UnitSize) {

827 Out << llvm::format("%0.2f%c", ValNo / static_cast<double>(UnitSize),

828 UnitSign);

829 return;

830 }

831 }

832 Out << ValNo;

833}

834

835

836static unsigned PluralNumber(const char *&Start, const char *End) {

837

838 unsigned Val = 0;

839 while (Start != End && *Start >= '0' && *Start <= '9') {

840 Val *= 10;

841 Val += *Start - '0';

842 ++Start;

843 }

844 return Val;

845}

846

847

848static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {

849 if (*Start != '[') {

851 return Ref == Val;

852 }

853

854 ++Start;

856 assert(*Start == ',' && "Bad plural expression syntax: expected ,");

857 ++Start;

859 assert(*Start == ']' && "Bad plural expression syntax: expected )");

860 ++Start;

861 return Low <= Val && Val <= High;

862}

863

864

865static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {

866

867 if (*Start == ':')

868 return true;

869

870 while (true) {

871 char C = *Start;

872 if (C == '%') {

873

874 ++Start;

876 assert(*Start == '=' && "Bad plural expression syntax: expected =");

877 ++Start;

878 unsigned ValMod = ValNo % Arg;

880 return true;

881 } else {

882 assert((C == '[' || (C >= '0' && C <= '9')) &&

883 "Bad plural expression syntax: unexpected character");

884

886 return true;

887 }

888

889

890 Start = std::find(Start, End, ',');

891 if (Start == End)

892 break;

893 ++Start;

894 }

895 return false;

896}

897

898

899

900

901

902

903

904

905

906

907

908

909

910

911

912

913

914

915

916

917

918

919

920

921

922

923

924

925

926

927

928

929

930

932 const char *Argument, unsigned ArgumentLen,

934 const char *ArgumentEnd = Argument + ArgumentLen;

935 while (true) {

936 assert(Argument < ArgumentEnd && "Plural expression didn't match.");

937 const char *ExprEnd = Argument;

938 while (*ExprEnd != ':') {

939 assert(ExprEnd != ArgumentEnd && "Plural missing expression end");

940 ++ExprEnd;

941 }

943 Argument = ExprEnd + 1;

944 ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');

945

946

947

949 return;

950 }

951 Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;

952 }

953}

954

955

956

957

959 switch (Kind) {

960 case tok::identifier:

961 return "identifier";

962 default:

963 return nullptr;

964 }

965}

966

967

968

969

972 if (StoredDiagMessage.has_value()) {

973 OutStr.append(StoredDiagMessage->begin(), StoredDiagMessage->end());

974 return;

975 }

976

977 StringRef Diag =

979

981}

982

983

984

987 OutStr.reserve(OutStr.size() + Str.size());

988 auto *Begin = reinterpret_cast<const unsigned char *>(Str.data());

989 llvm::raw_svector_ostream OutStream(OutStr);

990 const unsigned char *End = Begin + Str.size();

991 while (Begin != End) {

992

994 OutStream << *Begin;

996 continue;

997 }

998 if (llvm::isLegalUTF8Sequence(Begin, End)) {

999 llvm::UTF32 CodepointValue;

1000 llvm::UTF32 *CpPtr = &CodepointValue;

1001 const unsigned char *CodepointBegin = Begin;

1002 const unsigned char *CodepointEnd =

1003 Begin + llvm::getNumBytesForUTF8(*Begin);

1004 llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(

1005 &Begin, CodepointEnd, &CpPtr, CpPtr + 1, llvm::strictConversion);

1006 (void)Res;

1007 assert(

1008 llvm::conversionOK == Res &&

1009 "the sequence is legal UTF-8 but we couldn't convert it to UTF-32");

1010 assert(Begin == CodepointEnd &&

1011 "we must be further along in the string now");

1012 if (llvm::sys::unicode::isPrintable(CodepointValue) ||

1013 llvm::sys::unicode::isFormatting(CodepointValue)) {

1014 OutStr.append(CodepointBegin, CodepointEnd);

1015 continue;

1016 }

1017

1018 OutStream << "<U+" << llvm::format_hex_no_prefix(CodepointValue, 4, true)

1019 << ">";

1020 continue;

1021 }

1022

1023 OutStream << "<" << llvm::format_hex_no_prefix(*Begin, 2, true) << ">";

1025 }

1026}

1027

1031

1032

1033

1034 if (DiagEnd - DiagStr == 2 && StringRef(DiagStr, DiagEnd - DiagStr) == "%0" &&

1038 return;

1039 }

1040

1041

1042

1043

1044

1046

1047

1048

1051

1052 for (unsigned i = 0, e = getNumArgs(); i < e; ++i)

1054 QualTypeVals.push_back(getRawArg(i));

1055

1056 while (DiagStr != DiagEnd) {

1057 if (DiagStr[0] != '%') {

1058

1059 const char *StrEnd = std::find(DiagStr, DiagEnd, '%');

1060 OutStr.append(DiagStr, StrEnd);

1061 DiagStr = StrEnd;

1062 continue;

1064 OutStr.push_back(DiagStr[1]);

1065 DiagStr += 2;

1066 continue;

1067 }

1068

1069

1070 ++DiagStr;

1071

1072

1073

1074

1075

1076

1077 const char *Modifier = nullptr, *Argument = nullptr;

1078 unsigned ModifierLen = 0, ArgumentLen = 0;

1079

1080

1081 if (isDigit(DiagStr[0])) {

1082 Modifier = DiagStr;

1083 while (DiagStr[0] == '-' ||

1084 (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))

1085 ++DiagStr;

1086 ModifierLen = DiagStr-Modifier;

1087

1088

1089 if (DiagStr[0] == '{') {

1090 ++DiagStr;

1091 Argument = DiagStr;

1092

1093 DiagStr = ScanFormat(DiagStr, DiagEnd, '}');

1094 assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");

1095 ArgumentLen = DiagStr-Argument;

1096 ++DiagStr;

1097 }

1098 }

1099

1100 assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");

1101 unsigned ArgNo = *DiagStr++ - '0';

1102

1103

1104 unsigned ArgNo2 = ArgNo;

1105

1107 if (ModifierIs(Modifier, ModifierLen, "diff")) {

1108 assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&

1109 "Invalid format for diff modifier");

1110 ++DiagStr;

1111 ArgNo2 = *DiagStr++ - '0';

1116 else {

1117

1118

1119

1120

1121

1122 const char *ArgumentEnd = Argument + ArgumentLen;

1123 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');

1124 assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd &&

1125 "Found too many '|'s in a %diff modifier!");

1126 const char *FirstDollar = ScanFormat(Argument, Pipe, '$');

1127 const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');

1128 const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) };

1129 const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) };

1135 continue;

1136 }

1137 }

1138

1139 switch (Kind) {

1140

1143 assert(ModifierLen == 0 && "No modifiers for strings yet");

1145 break;

1146 }

1149 assert(ModifierLen == 0 && "No modifiers for strings yet");

1150

1151

1152 if (!S)

1153 S = "(null)";

1155 break;

1156 }

1157

1160

1161 if (ModifierIs(Modifier, ModifierLen, "select")) {

1163 OutStr);

1164 } else if (ModifierIs(Modifier, ModifierLen, "s")) {

1166 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {

1168 OutStr);

1169 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {

1171 } else if (ModifierIs(Modifier, ModifierLen, "human")) {

1173 } else {

1174 assert(ModifierLen == 0 && "Unknown integer modifier");

1175 llvm::raw_svector_ostream(OutStr) << Val;

1176 }

1177 break;

1178 }

1181

1182 if (ModifierIs(Modifier, ModifierLen, "select")) {

1184 } else if (ModifierIs(Modifier, ModifierLen, "s")) {

1186 } else if (ModifierIs(Modifier, ModifierLen, "plural")) {

1188 OutStr);

1189 } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {

1191 } else if (ModifierIs(Modifier, ModifierLen, "human")) {

1193 } else {

1194 assert(ModifierLen == 0 && "Unknown integer modifier");

1195 llvm::raw_svector_ostream(OutStr) << Val;

1196 }

1197 break;

1198 }

1199

1202 assert(ModifierLen == 0 && "No modifiers for token kinds yet");

1203

1204 llvm::raw_svector_ostream Out(OutStr);

1206

1207 Out << '\'' << S << '\'';

1209

1210 Out << S;

1212

1213 Out << S;

1215

1216 Out << '<' << S << '>';

1217 else

1218 Out << "(null)";

1219 break;

1220 }

1221

1224 assert(ModifierLen == 0 && "No modifiers for strings yet");

1225

1226

1227 if (!II) {

1228 const char *S = "(null)";

1229 OutStr.append(S, S + strlen(S));

1230 continue;

1231 }

1232

1233 llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';

1234 break;

1235 }

1245 StringRef(Modifier, ModifierLen),

1246 StringRef(Argument, ArgumentLen),

1247 FormattedArgs,

1248 OutStr, QualTypeVals);

1249 break;

1251

1259

1260 const char *ArgumentEnd = Argument + ArgumentLen;

1261 const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');

1262

1263

1264

1265 if (getDiags()->PrintTemplateTree && Tree.empty()) {

1269 StringRef(Modifier, ModifierLen),

1270 StringRef(Argument, ArgumentLen),

1271 FormattedArgs,

1272 Tree, QualTypeVals);

1273

1274 if (Tree.empty()) {

1276 break;

1277 }

1278 }

1279

1280

1281

1282 const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');

1283 const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');

1284

1285

1287

1288

1292 StringRef(Modifier, ModifierLen),

1293 StringRef(Argument, ArgumentLen),

1294 FormattedArgs,

1295 OutStr, QualTypeVals);

1299

1300

1302

1303

1306 StringRef(Modifier, ModifierLen),

1307 StringRef(Argument, ArgumentLen),

1308 FormattedArgs,

1309 OutStr, QualTypeVals);

1313

1314

1316 break;

1317 }

1318 }

1319

1320

1321

1322

1324 continue;

1326 FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));

1327 else

1330 }

1331

1332

1333 OutStr.append(Tree.begin(), Tree.end());

1334}

1335

1337 StringRef Message)

1338 : ID(ID), Level(Level), Message(Message) {}

1339

1342 : ID(Info.getID()), Level(Level) {

1344 "Valid source location without setting a source manager for diagnostic");

1349 this->Message.assign(Message.begin(), Message.end());

1350 this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end());

1352}

1353

1358 : ID(ID), Level(Level), Loc(Loc), Message(Message),

1359 Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())

1360{

1361}

1362

1368 return OS;

1369}

1370

1371

1372

1373

1374

1376

1377void IgnoringDiagConsumer::anchor() {}

1378

1380

1384 Target.HandleDiagnostic(DiagLevel, Info);

1385}

1386

1390}

1391

1393 return Target.IncludeInDiagnosticCounts();

1394}

1395

1397 for (unsigned I = 0; I != NumCached; ++I)

1398 FreeList[I] = Cached + I;

1399 NumFreeListEntries = NumCached;

1400}

1401

1403

1404

1405 assert((NumFreeListEntries == NumCached ||

1406 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&

1407 "A partial is on the lam");

1408}

1409

static const char * ScanFormat(const char *I, const char *E, char Target)

ScanForward - Scans forward, looking for the given character, skipping nested clauses and escaped cha...

static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, SmallVectorImpl< char > &OutStr)

HandlePluralModifier - Handle the integer 'plural' modifier.

static void HandleIntegerSModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)

HandleIntegerSModifier - Handle the integer 's' modifier.

static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT, StringRef Modifier, StringRef Argument, ArrayRef< DiagnosticsEngine::ArgumentValue > PrevArgs, SmallVectorImpl< char > &Output, void *Cookie, ArrayRef< intptr_t > QualTypeVals)

static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End)

EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.

static void HandleIntegerHumanModifier(int64_t ValNo, SmallVectorImpl< char > &OutStr)

static unsigned PluralNumber(const char *&Start, const char *End)

PluralNumber - Parse an unsigned integer and advance Start.

static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, SmallVectorImpl< char > &OutStr)

HandleSelectModifier - Handle the integer 'select' modifier.

static bool ModifierIs(const char *Modifier, unsigned ModifierLen, const char(&Str)[StrLen])

ModifierIs - Return true if the specified modifier matches specified string.

static bool TestPluralRange(unsigned Val, const char *&Start, const char *End)

TestPluralRange - Test if Val is in the parsed range. Modifies Start.

static void HandleOrdinalModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)

HandleOrdinalModifier - Handle the integer 'ord' modifier.

static const char * getTokenDescForDiagnostic(tok::TokenKind Kind)

Returns the friendly description for a token kind that will appear without quotes in diagnostic messa...

Defines the Diagnostic-related interfaces.

static llvm::GlobalValue::DLLStorageClassTypes getStorage(CodeGenModule &CGM, StringRef Name)

Defines the Diagnostic IDs-related interfaces.

Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.

static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)

Produce a diagnostic highlighting some portion of a literal.

llvm::MachO::Target Target

Implements a partial diagnostic that can be emitted anwyhere in a DiagnosticBuilder stream.

static std::string toString(const clang::SanitizerSet &Sanitizers)

Produce a string containing comma-separated names of sanitizers in Sanitizers set.

Defines the clang::SourceLocation class and associated facilities.

Defines the SourceManager interface.

Defines various enumerations that describe declaration and type specifiers.

Defines the clang::TokenKind enum and support functions.

A little helper class used to produce diagnostics.

Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...

virtual ~DiagnosticConsumer()

virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info)

Handle this diagnostic, reporting it to the user or capturing it to a log as needed.

unsigned NumErrors

Number of errors reported.

unsigned NumWarnings

Number of warnings reported.

virtual bool IncludeInDiagnosticCounts() const

Indicates whether the diagnostics handled by this DiagnosticConsumer should be included in the number...

static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group)

Get the diagnostic option with the closest edit distance to the given group name.

static StringRef getWarningOptionForDiag(unsigned DiagID)

Return the lowest-level warning option that enables the specified diagnostic.

Level

The level of the diagnostic, after it has been through mapping.

static void getAllDiagnostics(diag::Flavor Flavor, std::vector< diag::kind > &Diags)

Get the set of all diagnostic IDs.

static DiagnosticMapping getDefaultMapping(unsigned DiagID)

Get the default mapping for this diagnostic.

void setNoWarningAsError(bool Value)

void setSeverity(diag::Severity Value)

diag::Severity getSeverity() const

void setUpgradedFromWarning(bool Value)

void setNoErrorAsFatal(bool Value)

bool hasNoWarningAsError() const

A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...

Diagnostic(const DiagnosticsEngine *DO, const DiagnosticBuilder &DiagBuilder)

const SourceLocation & getLocation() const

const std::string & getArgStdStr(unsigned Idx) const

Return the provided argument string specified by Idx.

void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const

Format this diagnostic into a string, substituting the formal arguments into the %0 slots.

uint64_t getRawArg(unsigned Idx) const

Return the specified non-string argument in an opaque form.

const char * getArgCStr(unsigned Idx) const

Return the specified C string argument.

const IdentifierInfo * getArgIdentifier(unsigned Idx) const

Return the specified IdentifierInfo argument.

SourceManager & getSourceManager() const

ArrayRef< FixItHint > getFixItHints() const

unsigned getNumArgs() const

bool hasSourceManager() const

DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const

Return the kind of the specified index.

int64_t getArgSInt(unsigned Idx) const

Return the specified signed integer argument.

uint64_t getArgUInt(unsigned Idx) const

Return the specified unsigned integer argument.

ArrayRef< CharSourceRange > getRanges() const

Return an array reference for this diagnostic's ranges.

const DiagnosticsEngine * getDiags() const

Concrete class used by the front-end to report problems and issues.

DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)

Issue the message to the client.

bool hasSourceManager() const

bool EmitDiagnostic(const DiagnosticBuilder &DB, bool Force=false)

Emit the diagnostic.

void setDiagSuppressionMapping(llvm::MemoryBuffer &Input)

Diagnostic suppression mappings can be used to suppress specific diagnostics in specific files.

bool isSuppressedViaMapping(diag::kind DiagId, SourceLocation DiagLoc) const

void setSeverityForAll(diag::Flavor Flavor, diag::Severity Map, SourceLocation Loc=SourceLocation())

Add the specified mapping to all diagnostics of the specified flavor.

LLVM_DUMP_METHOD void dump() const

void setClient(DiagnosticConsumer *client, bool ShouldOwnClient=true)

Set the diagnostic client associated with this diagnostic object.

SourceManager & getSourceManager() const

void pushMappings(SourceLocation Loc)

Copies the current DiagMappings and pushes the new copy onto the top of the stack.

void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc)

This allows the client to specify that certain warnings are ignored.

Level

The level of the diagnostic, after it has been through mapping.

DiagnosticConsumer * getClient()

@ ak_nameddecl

NamedDecl *.

@ ak_declcontext

DeclContext *.

@ ak_addrspace

address space

@ ak_identifierinfo

IdentifierInfo.

@ ak_qualtype_pair

pair<QualType, QualType>

@ ak_c_string

const char *

@ ak_declarationname

DeclarationName.

@ ak_tokenkind

enum TokenKind : unsigned

@ ak_std_string

std::string

@ ak_nestednamespec

NestedNameSpecifier *.

Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const

Based on the way the client configured the DiagnosticsEngine object, classify the specified diagnosti...

DiagnosticsEngine(IntrusiveRefCntPtr< DiagnosticIDs > Diags, IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts, DiagnosticConsumer *client=nullptr, bool ShouldOwnClient=true)

bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled)

Set the error-as-fatal flag for the given diagnostic group.

bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled)

Set the warning-as-error flag for the given diagnostic group.

void ConvertArgToString(ArgumentKind Kind, intptr_t Val, StringRef Modifier, StringRef Argument, ArrayRef< ArgumentValue > PrevArgs, SmallVectorImpl< char > &Output, ArrayRef< intptr_t > QualTypeVals) const

Converts a diagnostic argument (as an intptr_t) into the string that represents it.

bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group, diag::Severity Map, SourceLocation Loc=SourceLocation())

Change an entire diagnostic group (e.g.

bool popMappings(SourceLocation Loc)

Pops the current DiagMappings off the top of the stack, causing the new top of the stack to be the ac...

const IntrusiveRefCntPtr< DiagnosticIDs > & getDiagnosticIDs() const

void Reset(bool soft=false)

Reset the state of the diagnostic object to its initial configuration.

An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...

bool IncludeInDiagnosticCounts() const override

Indicates whether the diagnostics handled by this DiagnosticConsumer should be included in the number...

~ForwardingDiagnosticConsumer() override

void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override

Handle this diagnostic, reporting it to the user or capturing it to a log as needed.

A SourceLocation and its associated SourceManager.

bool hasManager() const

Checks whether the SourceManager is present.

const SourceManager & getManager() const

One of these records is kept for each identifier that is lexed.

StringRef getName() const

Return the actual identifier string.

Represents an unpacked "presumed" location which can be presented to the user.

Encodes a location in the source.

std::string printToString(const SourceManager &SM) const

bool isValid() const

Return true if this is a valid SourceLocation object.

void print(raw_ostream &OS, const SourceManager &SM) const

SourceLocation getLocWithOffset(IntTy Offset) const

Return a source location with the specified offset from this SourceLocation.

This class handles loading and caching of source files into memory.

llvm::MemoryBufferRef getBufferOrFake(FileID FID, SourceLocation Loc=SourceLocation()) const

Return the buffer for the specified FileID.

std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const

Decompose the specified location into a raw FileID + Offset pair.

SourceLocation getLocForStartOfFile(FileID FID) const

Return the source location corresponding to the first byte of the specified file.

std::pair< FileID, unsigned > getDecomposedIncludedLoc(FileID FID) const

Returns the "included/expanded in" decomposed location of the given FileID.

Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...

range_iterator range_begin() const

StoredDiagnostic()=default

DiagnosticsEngine::Level getLevel() const

fixit_iterator fixit_begin() const

const FullSourceLoc & getLocation() const

range_iterator range_end() const

StringRef getMessage() const

fixit_iterator fixit_end() const

The streaming interface shared between DiagnosticBuilder and PartialDiagnostic.

DiagStorageAllocator * Allocator

Allocator used to allocate storage for this diagnostic.

DiagnosticStorage * DiagStorage

void AddString(StringRef V) const

Severity

Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...

@ Warning

Present this diagnostic as a warning.

@ Fatal

Present this diagnostic as a fatal error.

@ Error

Present this diagnostic as an error.

@ Remark

Present this diagnostic as a remark.

@ Ignored

Do not present this diagnostic, ignore it.

Flavor

Flavors of diagnostics we can emit.

@ WarningOrError

A diagnostic that indicates a problem or potential problem.

const char * getTokenName(TokenKind Kind) LLVM_READNONE

Determines the name of a token as used within the front end.

const char * getKeywordSpelling(TokenKind Kind) LLVM_READNONE

Determines the spelling of simple keyword and contextual keyword tokens like 'int' and 'dynamic_cast'...

TokenKind

Provides a simple uniform namespace for tokens from all C languages.

const char * getPunctuatorSpelling(TokenKind Kind) LLVM_READNONE

Determines the spelling of simple punctuation tokens like '!' or '', and returns NULL for literal and...

The JSON file list parser is used to communicate input to InstallAPI.

LLVM_READONLY bool isPrintable(unsigned char c)

Return true if this character is an ASCII printable character; that is, a character that should take ...

const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ASTContext::SectionInfo &Section)

Insertion operator for diagnostics.

@ Result

The result type of a method or function.

llvm::StringRef getNullabilitySpelling(NullabilityKind kind, bool isContextSensitive=false)

Retrieve the spelling of the given nullability kind.

void EscapeStringForDiagnostic(StringRef Str, SmallVectorImpl< char > &OutStr)

EscapeStringForDiagnostic - Append Str to the diagnostic buffer, escaping non-printable characters an...

LLVM_READONLY bool isDigit(unsigned char c)

Return true if this character is an ASCII digit: [0-9].

LLVM_READONLY bool isWhitespace(unsigned char c)

Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...

std::pair< NullabilityKind, bool > DiagNullabilityKind

A nullability kind paired with a bit indicating whether it used a context-sensitive keyword.

LLVM_READONLY bool isPunctuation(unsigned char c)

Return true if this character is an ASCII punctuation character.

__INTPTR_TYPE__ intptr_t

A signed integer type with the property that any valid pointer to void can be converted to this type,...

SmallVector< CharSourceRange, 8 > DiagRanges

The list of ranges added to this diagnostic.

SmallVector< FixItHint, 6 > FixItHints

If valid, provides a hint with some code to insert, remove, or modify at a particular position.

unsigned TemplateDiffUsed