clang: lib/Sema/AnalysisBasedWarnings.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

46#include "llvm/ADT/ArrayRef.h"

47#include "llvm/ADT/BitVector.h"

48#include "llvm/ADT/MapVector.h"

49#include "llvm/ADT/STLFunctionalExtras.h"

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

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

52#include

53#include

54#include

55#include

56

57using namespace clang;

58

59

60

61

62

63namespace {

67

68 public:

69 UnreachableCodeHandler(Sema &s) : S(s) {}

70

73 SourceRange R2, bool HasFallThroughAttr) override {

74

75

76

77 if (HasFallThroughAttr &&

80 return;

81

82

83

84 if (PreviousSilenceableCondVal.isValid() &&

85 SilenceableCondVal.isValid() &&

86 PreviousSilenceableCondVal == SilenceableCondVal)

87 return;

88 PreviousSilenceableCondVal = SilenceableCondVal;

89

90 unsigned diag = diag::warn_unreachable;

91 switch (UK) {

93 diag = diag::warn_unreachable_break;

94 break;

96 diag = diag::warn_unreachable_return;

97 break;

99 diag = diag::warn_unreachable_loop_increment;

100 break;

102 break;

103 }

104

105 S.Diag(L, diag) << R1 << R2;

106

108 if (Open.isValid()) {

112 S.Diag(Open, diag::note_unreachable_silence)

115 }

116 }

117 }

118 };

119}

120

121

123

124

125

126

127

128

129

131 return;

132

133 UnreachableCodeHandler UC(S);

135}

136

137namespace {

138

139class LogicalErrorHandler : public CFGCallback {

141

142public:

143 LogicalErrorHandler(Sema &S) : S(S) {}

144

145 static bool HasMacroID(const Expr *E) {

147 return true;

148

149

151 if (const Expr *SubExpr = dyn_cast_or_null(SubStmt))

152 if (HasMacroID(SubExpr))

153 return true;

154

155 return false;

156 }

157

159 if (HasMacroID(B))

160 return;

161

162 unsigned DiagID = isAlwaysTrue

163 ? diag::warn_tautological_negation_or_compare

164 : diag::warn_tautological_negation_and_compare;

167 }

168

170 if (HasMacroID(B))

171 return;

172

174 S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)

175 << DiagRange << isAlwaysTrue;

176 }

177

179 bool isAlwaysTrue) override {

180 if (HasMacroID(B))

181 return;

182

184 S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always)

185 << DiagRange << isAlwaysTrue;

186 }

187

189 if (HasMacroID(B))

190 return;

191

193 S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;

194 }

195

198 return !Diags.isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||

199 !Diags.isIgnored(diag::warn_comparison_bitwise_or, Loc) ||

200 !Diags.isIgnored(diag::warn_tautological_negation_and_compare, Loc);

201 }

202};

203}

204

205

206

207

208

209

210

211

213

214 for (const auto &B : Block) {

216 continue;

217

221 continue;

222

223

228 isa(NNS->getAsType())) {

229 continue;

230 }

231 }

232 }

233

237 return true;

238 }

239 return false;

240}

241

242

246

247 bool foundRecursion = false;

248

250

251

252 WorkList.push_back(&cfg->getEntry());

253

254 while (!WorkList.empty()) {

256

258 if (CFGBlock *SuccBlock = *I) {

259 if (Visited.insert(SuccBlock).second)

260 continue;

261

262

263 if (ExitID == SuccBlock->getBlockID())

264 return false;

265

266

268 foundRecursion = true;

269 continue;

270 }

271

272 WorkList.push_back(SuccBlock);

273 }

274 }

275 }

276 return foundRecursion;

277}

278

282

283

284

287 return;

288

289 CFG *cfg = AC.getCFG();

290 if (!cfg) return;

291

292

294 return;

295

296

298 S.Diag(Body->getBeginLoc(), diag::warn_infinite_recursive_function);

299}

300

301

302

303

304

305

306

308 CFG *Body) {

311

312 Stack.push_back(&ThrowBlock);

313 Queued[ThrowBlock.getBlockID()] = true;

314

315 while (!Stack.empty()) {

316 CFGBlock &UnwindBlock = *Stack.back();

317 Stack.pop_back();

318

319 for (auto &Succ : UnwindBlock.succs()) {

320 if (!Succ.isReachable() || Queued[Succ->getBlockID()])

321 continue;

322

324 return true;

325

326 if (auto *Catch =

327 dyn_cast_or_null(Succ->getLabel())) {

328 QualType Caught = Catch->getCaughtType();

329 if (Caught.isNull() ||

330 E->getSubExpr() ||

332

333 break;

334 } else {

335 Stack.push_back(Succ);

336 Queued[Succ->getBlockID()] = true;

337 }

338 }

339 }

340

341 return false;

342}

343

345 CFG *BodyCFG,

347 llvm::BitVector Reachable(BodyCFG->getNumBlockIDs());

349 for (CFGBlock *B : *BodyCFG) {

350 if (!Reachable[B->getBlockID()])

351 continue;

353 std::optional S = E.getAs<CFGStmt>();

354 if (!S)

355 continue;

356 if (auto *Throw = dyn_cast(S->getStmt()))

357 Visit(Throw, *B);

358 }

359 }

360}

361

366 S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;

368 (isa(FD) ||

372 getAs())

374 << !isa(FD) << !Ty->hasExceptionSpec()

376 } else

379 }

380}

381

384 CFG *BodyCFG = AC.getCFG();

385 if (!BodyCFG)

386 return;

388 return;

392 });

393}

394

397 if (FPT->isNothrow() || FD->hasAttr())

398 return true;

399 return false;

400}

401

402

403

404

405

413

414

415

416

417

418

419

420

421

422

424 CFG *cfg = AC.getCFG();

426

427

428

431 live);

432

433 bool AddEHEdges = AC.getAddEHEdges();

435

436

437

438 for (const auto *B : *cfg) {

439 if (!live[B->getBlockID()]) {

440 if (B->pred_begin() == B->pred_end()) {

441 const Stmt *Term = B->getTerminatorStmt();

442 if (isa_and_nonnull(Term))

443

444

446 continue;

447 }

448 }

449 }

450

451

452

453

454 bool HasLiveReturn = false;

455 bool HasFakeEdge = false;

456 bool HasPlainEdge = false;

457 bool HasAbnormalEdge = false;

458

459

460

463

469 continue;

470

471

472

473

475 HasAbnormalEdge = true;

476 continue;

477 }

478

479

480

481

483

484 for ( ; ri != re ; ++ri)

486 break;

487

488

489 if (ri == re) {

491 if (Term && (isa(Term) || isa(Term))) {

492 HasAbnormalEdge = true;

493 continue;

494 }

495

496 HasPlainEdge = true;

497 continue;

498 }

499

502 if (isa(S) || isa(S)) {

503 HasLiveReturn = true;

504 continue;

505 }

506 if (isa(S)) {

507 HasFakeEdge = true;

508 continue;

509 }

510 if (isa(S)) {

511 HasFakeEdge = true;

512 continue;

513 }

514 if (isa(S)) {

515

516 HasFakeEdge = true;

517 HasLiveReturn = true;

518 continue;

519 }

520 if (isa(S)) {

521 HasAbnormalEdge = true;

522 continue;

523 }

524 if (!llvm::is_contained(B.succs(), &cfg->getExit())) {

525 HasAbnormalEdge = true;

526 continue;

527 }

528

529 HasPlainEdge = true;

530 }

531 if (!HasPlainEdge) {

532 if (HasLiveReturn)

535 }

536 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)

538

539

540

542}

543

544namespace {

545

546struct CheckFallThroughDiagnostics {

547 unsigned diag_MaybeFallThrough_HasNoReturn;

548 unsigned diag_MaybeFallThrough_ReturnsNonVoid;

549 unsigned diag_AlwaysFallThrough_HasNoReturn;

550 unsigned diag_AlwaysFallThrough_ReturnsNonVoid;

551 unsigned diag_NeverFallThroughOrReturn;

552 enum { Function, Block, Lambda, Coroutine } funMode;

554

555 static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {

556 CheckFallThroughDiagnostics D;

557 D.FuncLoc = Func->getLocation();

558 D.diag_MaybeFallThrough_HasNoReturn =

559 diag::warn_falloff_noreturn_function;

560 D.diag_MaybeFallThrough_ReturnsNonVoid =

561 diag::warn_maybe_falloff_nonvoid_function;

562 D.diag_AlwaysFallThrough_HasNoReturn =

563 diag::warn_falloff_noreturn_function;

564 D.diag_AlwaysFallThrough_ReturnsNonVoid =

565 diag::warn_falloff_nonvoid_function;

566

567

568

569 bool isVirtualMethod = false;

571 isVirtualMethod = Method->isVirtual();

572

573

575 if (const FunctionDecl *Function = dyn_cast(Func))

577

579 D.diag_NeverFallThroughOrReturn =

580 diag::warn_suggest_noreturn_function;

581 else

582 D.diag_NeverFallThroughOrReturn = 0;

583

585 return D;

586 }

587

588 static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) {

589 CheckFallThroughDiagnostics D;

590 D.FuncLoc = Func->getLocation();

591 D.diag_MaybeFallThrough_HasNoReturn = 0;

592 D.diag_MaybeFallThrough_ReturnsNonVoid =

593 diag::warn_maybe_falloff_nonvoid_coroutine;

594 D.diag_AlwaysFallThrough_HasNoReturn = 0;

595 D.diag_AlwaysFallThrough_ReturnsNonVoid =

596 diag::warn_falloff_nonvoid_coroutine;

597 D.diag_NeverFallThroughOrReturn = 0;

598 D.funMode = Coroutine;

599 return D;

600 }

601

602 static CheckFallThroughDiagnostics MakeForBlock() {

603 CheckFallThroughDiagnostics D;

604 D.diag_MaybeFallThrough_HasNoReturn =

605 diag::err_noreturn_block_has_return_expr;

606 D.diag_MaybeFallThrough_ReturnsNonVoid =

607 diag::err_maybe_falloff_nonvoid_block;

608 D.diag_AlwaysFallThrough_HasNoReturn =

609 diag::err_noreturn_block_has_return_expr;

610 D.diag_AlwaysFallThrough_ReturnsNonVoid =

611 diag::err_falloff_nonvoid_block;

612 D.diag_NeverFallThroughOrReturn = 0;

614 return D;

615 }

616

617 static CheckFallThroughDiagnostics MakeForLambda() {

618 CheckFallThroughDiagnostics D;

619 D.diag_MaybeFallThrough_HasNoReturn =

620 diag::err_noreturn_lambda_has_return_expr;

621 D.diag_MaybeFallThrough_ReturnsNonVoid =

622 diag::warn_maybe_falloff_nonvoid_lambda;

623 D.diag_AlwaysFallThrough_HasNoReturn =

624 diag::err_noreturn_lambda_has_return_expr;

625 D.diag_AlwaysFallThrough_ReturnsNonVoid =

626 diag::warn_falloff_nonvoid_lambda;

627 D.diag_NeverFallThroughOrReturn = 0;

628 D.funMode = Lambda;

629 return D;

630 }

631

633 bool HasNoReturn) const {

634 if (funMode == Function) {

635 return (ReturnsVoid ||

636 D.isIgnored(diag::warn_maybe_falloff_nonvoid_function,

637 FuncLoc)) &&

638 (!HasNoReturn ||

639 D.isIgnored(diag::warn_noreturn_function_has_return_expr,

640 FuncLoc)) &&

641 (!ReturnsVoid ||

642 D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));

643 }

644 if (funMode == Coroutine) {

645 return (ReturnsVoid ||

646 D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) ||

647 D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine,

648 FuncLoc)) &&

649 (!HasNoReturn);

650 }

651

652 return ReturnsVoid && !HasNoReturn;

653 }

654};

655

656}

657

658

659

660

661

664 const CheckFallThroughDiagnostics &CD,

667

668 bool ReturnsVoid = false;

669 bool HasNoReturn = false;

671

672 if (const auto *FD = dyn_cast(D)) {

673 if (const auto *CBody = dyn_cast(Body))

674 ReturnsVoid = CBody->getFallthroughHandler() != nullptr;

675 else

676 ReturnsVoid = FD->getReturnType()->isVoidType();

677 HasNoReturn = FD->isNoReturn();

678 }

679 else if (const auto *MD = dyn_cast(D)) {

680 ReturnsVoid = MD->getReturnType()->isVoidType();

681 HasNoReturn = MD->hasAttr();

682 }

683 else if (isa(D)) {

686 if (FT->getReturnType()->isVoidType())

687 ReturnsVoid = true;

688 if (FT->getNoReturnAttr())

689 HasNoReturn = true;

690 }

691 }

692

694

695

696 if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))

697 return;

700 if (IsCoroutine)

702 else

704 };

705

706

708 return;

709

710

713 break;

714

716 if (HasNoReturn)

717 EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);

718 else if (!ReturnsVoid)

719 EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);

720 break;

722 if (HasNoReturn)

723 EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);

724 else if (!ReturnsVoid)

725 EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);

726 break;

728 if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {

729 if (const FunctionDecl *FD = dyn_cast(D)) {

730 S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;

731 } else if (const ObjCMethodDecl *MD = dyn_cast(D)) {

732 S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD;

733 } else {

734 S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn);

735 }

736 }

737 break;

739 break;

740 }

741}

742

743

744

745

746

747namespace {

748

749

750

752 bool FoundReference;

754

755public:

757

759 : Inherited(Context), FoundReference(false), Needle(Needle) {}

760

761 void VisitExpr(const Expr *E) {

762

763 if (FoundReference)

764 return;

765

766 Inherited::VisitExpr(E);

767 }

768

770 if (E == Needle)

771 FoundReference = true;

772 else

774 }

775

776 bool doesContainReference() const { return FoundReference; }

777};

778}

779

783 !VD->hasAttr()) {

784 S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization)

787 return true;

788 }

789

790

792 return false;

793

794

796 return false;

797

799

800

802 if (Init.empty())

803 return false;

804

805 S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()

807 return true;

808}

809

810

811

813 const Stmt *Else, bool CondVal,

815 if (CondVal) {

816

819 if (Else) {

821 Fixit2 =

823 }

824 } else {

825

826 if (Else)

829 else

831 }

832}

833

834

835

837 bool IsCapturedByBlock) {

838 bool Diagnosed = false;

839

843 << VD->getDeclName() << IsCapturedByBlock

845 return;

846

849 S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var)

850 << VD->getDeclName() << IsCapturedByBlock

856 return;

857

860

861

862 break;

863 }

864

865

867 I != E; ++I) {

869

871 const Stmt *Term = I->Terminator;

872

873

874 unsigned DiagKind;

875 StringRef Str;

877

878

879

880

881 int RemoveDiagKind = -1;

882 const char *FixitStr =

883 S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false")

884 : (I->Output ? "1" : "0");

886

887 switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) {

888 default:

889

890

891 continue;

892

893

894 case Stmt::IfStmtClass: {

895 const IfStmt *IS = cast(Term);

896 DiagKind = 0;

897 Str = "if";

899 RemoveDiagKind = 0;

901 I->Output, Fixit1, Fixit2);

902 break;

903 }

904 case Stmt::ConditionalOperatorClass: {

906 DiagKind = 0;

907 Str = "?:";

909 RemoveDiagKind = 0;

911 I->Output, Fixit1, Fixit2);

912 break;

913 }

914 case Stmt::BinaryOperatorClass: {

915 const BinaryOperator *BO = cast(Term);

917 continue;

918 DiagKind = 0;

921 RemoveDiagKind = 0;

922 if ((BO->getOpcode() == BO_LAnd && I->Output) ||

923 (BO->getOpcode() == BO_LOr && !I->Output))

924

927 else

928

930 break;

931 }

932

933

934 case Stmt::WhileStmtClass:

935 DiagKind = 1;

936 Str = "while";

937 Range = cast(Term)->getCond()->getSourceRange();

938 RemoveDiagKind = 1;

940 break;

941 case Stmt::ForStmtClass:

942 DiagKind = 1;

943 Str = "for";

944 Range = cast(Term)->getCond()->getSourceRange();

945 RemoveDiagKind = 1;

946 if (I->Output)

948 else

950 break;

951 case Stmt::CXXForRangeStmtClass:

952 if (I->Output == 1) {

953

954

955

956 continue;

957 }

958 DiagKind = 1;

959 Str = "for";

960 Range = cast(Term)->getRangeInit()->getSourceRange();

961 break;

962

963

964 case Stmt::DoStmtClass:

965 DiagKind = 2;

966 Str = "do";

967 Range = cast(Term)->getCond()->getSourceRange();

968 RemoveDiagKind = 1;

970 break;

971

972

973 case Stmt::CaseStmtClass:

974 DiagKind = 3;

975 Str = "case";

976 Range = cast(Term)->getLHS()->getSourceRange();

977 break;

978 case Stmt::DefaultStmtClass:

979 DiagKind = 3;

980 Str = "default";

981 Range = cast(Term)->getDefaultLoc();

982 break;

983 }

984

986 << VD->getDeclName() << IsCapturedByBlock << DiagKind

987 << Str << I->Output << Range;

990 if (RemoveDiagKind != -1)

992 << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;

993

994 Diagnosed = true;

995 }

996

997 if (!Diagnosed)

999 << VD->getDeclName() << IsCapturedByBlock

1001}

1002

1003

1008 return true;

1009}

1010

1011

1012

1013

1014

1015

1018 bool alwaysReportSelfInit = false) {

1019 if (const DeclRefExpr *DRE = dyn_cast(Use.getUser())) {

1020

1021

1022

1023

1024

1025

1026

1027

1028

1029

1030

1032 if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())

1033 return false;

1034

1035 ContainsReference CR(S.Context, DRE);

1037 if (CR.doesContainReference()) {

1038 S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)

1040 return true;

1041 }

1042 }

1043

1045 } else {

1049 diag::warn_uninit_byref_blockvar_captured_by_block)

1052 else

1054 }

1055

1056

1057

1058

1062

1063 return true;

1064}

1065

1066namespace {

1068public:

1069 FallthroughMapper(Sema &S) : FoundSwitchStatements(false), S(S) {

1070 ShouldWalkTypesOfTypeLocs = false;

1071 }

1072

1073 bool foundSwitchStatements() const { return FoundSwitchStatements; }

1074

1076 bool Found = FallthroughStmts.erase(Stmt);

1079 }

1080

1082

1083 const AttrStmts &getFallthroughStmts() const { return FallthroughStmts; }

1084

1085 void fillReachableBlocks(CFG *Cfg) {

1086 assert(ReachableBlocks.empty() && "ReachableBlocks already filled");

1087 std::deque<const CFGBlock *> BlockQueue;

1088

1089 ReachableBlocks.insert(&Cfg->getEntry());

1090 BlockQueue.push_back(&Cfg->getEntry());

1091

1092

1093

1094

1095 for (const auto *B : *Cfg) {

1096 const Stmt *L = B->getLabel();

1097 if (isa_and_nonnull(L) && ReachableBlocks.insert(B).second)

1098 BlockQueue.push_back(B);

1099 }

1100

1101 while (!BlockQueue.empty()) {

1102 const CFGBlock *P = BlockQueue.front();

1103 BlockQueue.pop_front();

1104 for (const CFGBlock *B : P->succs()) {

1105 if (B && ReachableBlocks.insert(B).second)

1106 BlockQueue.push_back(B);

1107 }

1108 }

1109 }

1110

1111 bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt,

1112 bool IsTemplateInstantiation) {

1113 assert(!ReachableBlocks.empty() && "ReachableBlocks empty");

1114

1115 int UnannotatedCnt = 0;

1116 AnnotatedCnt = 0;

1117

1118 std::deque<const CFGBlock *> BlockQueue(B.pred_begin(), B.pred_end());

1119 while (!BlockQueue.empty()) {

1120 const CFGBlock *P = BlockQueue.front();

1121 BlockQueue.pop_front();

1122 if (P)

1123 continue;

1124

1125 const Stmt *Term = P->getTerminatorStmt();

1126 if (isa_and_nonnull(Term))

1127 continue;

1128

1129 const SwitchCase *SW = dyn_cast_or_null(P->getLabel());

1131 continue;

1132

1133 const LabelStmt *L = dyn_cast_or_null(P->getLabel());

1135 continue;

1136

1137 if (!ReachableBlocks.count(P)) {

1138 for (const CFGElement &Elem : llvm::reverse(*P)) {

1139 if (std::optional CS = Elem.getAs<CFGStmt>()) {

1140 if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {

1141

1142

1143

1144 if (!IsTemplateInstantiation)

1145 S.Diag(AS->getBeginLoc(),

1146 diag::warn_unreachable_fallthrough_attr);

1147 markFallthroughVisited(AS);

1148 ++AnnotatedCnt;

1149 break;

1150 }

1151

1152 }

1153 }

1154

1155

1156

1157

1158

1159

1160

1161

1162 continue;

1163 }

1164

1166 if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {

1167 markFallthroughVisited(AS);

1168 ++AnnotatedCnt;

1169 continue;

1170 }

1171

1172 if (!LastStmt) {

1173

1174 std::copy(P->pred_begin(), P->pred_end(),

1175 std::back_inserter(BlockQueue));

1176 continue;

1177 }

1178

1179 ++UnannotatedCnt;

1180 }

1181 return !!UnannotatedCnt;

1182 }

1183

1184 bool VisitAttributedStmt(AttributedStmt *S) override {

1185 if (asFallThroughAttr(S))

1186 FallthroughStmts.insert(S);

1187 return true;

1188 }

1189

1190 bool VisitSwitchStmt(SwitchStmt *S) override {

1191 FoundSwitchStatements = true;

1192 return true;

1193 }

1194

1195

1196

1198

1199

1200 bool TraverseLambdaExpr(LambdaExpr *LE) override {

1201

1202 for (const auto C : zip(LE->captures(), LE->capture_inits()))

1204 return true;

1205 }

1206

1207 private:

1208

1210 if (const AttributedStmt *AS = dyn_cast_or_null(S)) {

1211 if (hasSpecificAttr(AS->getAttrs()))

1212 return AS;

1213 }

1214 return nullptr;

1215 }

1216

1219 return Term;

1220 for (const CFGElement &Elem : llvm::reverse(B))

1221 if (std::optional CS = Elem.getAs<CFGStmt>())

1222 return CS->getStmt();

1223

1224

1225

1226 if (const SwitchCase *SW = dyn_cast_or_null(B.getLabel()))

1227 if (!isa(SW->getSubStmt()))

1229

1230 return nullptr;

1231 }

1232

1233 bool FoundSwitchStatements;

1234 AttrStmts FallthroughStmts;

1237};

1238}

1239

1243 tok::l_square, tok::l_square,

1245 tok::r_square, tok::r_square

1246 };

1247

1248 TokenValue ClangFallthroughTokens[] = {

1251 tok::r_square, tok::r_square

1252 };

1253

1255

1256 StringRef MacroName;

1257 if (PreferClangAttr)

1259 if (MacroName.empty())

1261 if (MacroName.empty() && !PreferClangAttr)

1263 if (MacroName.empty()) {

1264 if (!PreferClangAttr)

1265 MacroName = "[[fallthrough]]";

1267 MacroName = "[[clang::fallthrough]]";

1268 else

1269 MacroName = "__attribute__((fallthrough))";

1270 }

1271 return MacroName;

1272}

1273

1275 bool PerFunction) {

1276 FallthroughMapper FM(S);

1277 FM.TraverseStmt(AC.getBody());

1278

1279 if (!FM.foundSwitchStatements())

1280 return;

1281

1282 if (PerFunction && FM.getFallthroughStmts().empty())

1283 return;

1284

1285 CFG *Cfg = AC.getCFG();

1286

1287 if (!Cfg)

1288 return;

1289

1290 FM.fillReachableBlocks(Cfg);

1291

1292 for (const CFGBlock *B : llvm::reverse(*Cfg)) {

1294

1295 if (!isa_and_nonnull(Label))

1296 continue;

1297

1298 int AnnotatedCnt;

1299

1300 bool IsTemplateInstantiation = false;

1302 IsTemplateInstantiation = Function->isTemplateInstantiation();

1303 if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,

1304 IsTemplateInstantiation))

1305 continue;

1306

1308 PerFunction ? diag::warn_unannotated_fallthrough_per_function

1309 : diag::warn_unannotated_fallthrough);

1310

1311 if (!AnnotatedCnt) {

1314 continue;

1315

1317

1318 while (B->empty() && !Term && B->succ_size() == 1) {

1321 }

1322 if (!(B->empty() && isa_and_nonnull(Term))) {

1326 TextToInsert += "; ";

1327 S.Diag(L, diag::note_insert_fallthrough_fixit)

1328 << AnnotationSpelling

1330 }

1331 S.Diag(L, diag::note_insert_break_fixit)

1333 }

1334 }

1335

1336 for (const auto *F : FM.getFallthroughStmts())

1337 S.Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement);

1338}

1339

1341 const Stmt *S) {

1342 assert(S);

1343

1344 do {

1345 switch (S->getStmtClass()) {

1346 case Stmt::ForStmtClass:

1347 case Stmt::WhileStmtClass:

1348 case Stmt::CXXForRangeStmtClass:

1349 case Stmt::ObjCForCollectionStmtClass:

1350 return true;

1351 case Stmt::DoStmtClass: {

1353 if (!cast(S)->getCond()->EvaluateAsInt(Result, Ctx))

1354 return true;

1355 return Result.Val.getInt().getBoolValue();

1356 }

1357 default:

1358 break;

1359 }

1360 } while ((S = PM.getParent(S)));

1361

1362 return false;

1363}

1364

1372 typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>

1373 StmtUsesPair;

1374

1376

1378

1379

1381 for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();

1382 I != E; ++I) {

1383 const WeakUseVector &Uses = I->second;

1384

1385

1386 WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();

1387 for ( ; UI != UE; ++UI) {

1388 if (UI->isUnsafe())

1389 break;

1390 }

1391

1392

1393 if (UI == UE)

1394 continue;

1395

1396

1397

1398

1399

1400 if (UI == Uses.begin()) {

1401 WeakUseVector::const_iterator UI2 = UI;

1402 for (++UI2; UI2 != UE; ++UI2)

1403 if (UI2->isUnsafe())

1404 break;

1405

1406 if (UI2 == UE) {

1407 if (isInLoop(Ctx, PM, UI->getUseExpr()))

1408 continue;

1409

1410 const WeakObjectProfileTy &Profile = I->first;

1411 if (!Profile.isExactProfile())

1412 continue;

1413

1416 Base = Profile.getProperty();

1417 assert(Base && "A profile always has a base or property.");

1418

1419 if (const VarDecl *BaseVar = dyn_cast(Base))

1420 if (BaseVar->hasLocalStorage() && !isa(Base))

1421 continue;

1422 }

1423 }

1424

1425 UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));

1426 }

1427

1428 if (UsesByStmt.empty())

1429 return;

1430

1431

1433 llvm::sort(UsesByStmt,

1434 [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) {

1436 RHS.first->getBeginLoc());

1437 });

1438

1439

1440

1441

1442

1443

1444 enum {

1446 Method,

1448 Lambda

1449 } FunctionKind;

1450

1451 if (isasema::BlockScopeInfo(CurFn))

1452 FunctionKind = Block;

1453 else if (isasema::LambdaScopeInfo(CurFn))

1454 FunctionKind = Lambda;

1455 else if (isa(D))

1456 FunctionKind = Method;

1457 else

1459

1460

1461 for (const auto &P : UsesByStmt) {

1462 const Stmt *FirstRead = P.first;

1463 const WeakObjectProfileTy &Key = P.second->first;

1464 const WeakUseVector &Uses = P.second->second;

1465

1466

1467

1468

1469

1470

1471 unsigned DiagKind;

1472 if (Key.isExactProfile())

1473 DiagKind = diag::warn_arc_repeated_use_of_weak;

1474 else

1475 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;

1476

1477

1478

1479

1480 enum {

1483 ImplicitProperty,

1484 Ivar

1485 } ObjectKind;

1486

1487 const NamedDecl *KeyProp = Key.getProperty();

1488 if (isa(KeyProp))

1490 else if (isa(KeyProp))

1492 else if (isa(KeyProp))

1493 ObjectKind = ImplicitProperty;

1494 else if (isa(KeyProp))

1495 ObjectKind = Ivar;

1496 else

1497 llvm_unreachable("Unexpected weak object kind!");

1498

1499

1500

1501 if (const ObjCPropertyDecl *Prop = dyn_cast(KeyProp))

1502 if (Prop->hasAttr())

1503 continue;

1504

1505

1507 << int(ObjectKind) << KeyProp << int(FunctionKind)

1509

1510

1511 for (const auto &Use : Uses) {

1512 if (Use.getUseExpr() == FirstRead)

1513 continue;

1514 S.Diag(Use.getUseExpr()->getBeginLoc(),

1515 diag::note_arc_weak_also_accessed_here)

1516 << Use.getUseExpr()->getSourceRange();

1517 }

1518 }

1519}

1520

1521namespace clang {

1522namespace {

1524typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;

1525typedef std::list DiagList;

1526

1527struct SortDiagBySourceLocation {

1530

1531 bool operator()(const DelayedDiag &left, const DelayedDiag &right) {

1532

1533

1534 return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);

1535 }

1536};

1537}

1538}

1539

1540namespace {

1544 typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;

1545

1546

1547

1548 typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;

1549 UsesMap uses;

1550 UsesMap constRefUses;

1551

1552public:

1553 UninitValsDiagReporter(Sema &S) : S(S) {}

1555

1556 MappedType &getUses(UsesMap &um, const VarDecl *vd) {

1557 MappedType &V = um[vd];

1558 if (V.getPointer())

1559 V.setPointer(new UsesVec());

1560 return V;

1561 }

1562

1564 const UninitUse &use) override {

1565 getUses(uses, vd).getPointer()->push_back(use);

1566 }

1567

1569 const UninitUse &use) override {

1570 getUses(constRefUses, vd).getPointer()->push_back(use);

1571 }

1572

1574 getUses(uses, vd).setInt(true);

1575 getUses(constRefUses, vd).setInt(true);

1576 }

1577

1579 for (const auto &P : uses) {

1580 const VarDecl *vd = P.first;

1581 const MappedType &V = P.second;

1582

1583 UsesVec *vec = V.getPointer();

1584 bool hasSelfInit = V.getInt();

1585

1586

1587

1588

1589 if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))

1592 true),

1593 true);

1594 else {

1595

1596

1597

1599

1600 if (a.getKind() != b.getKind())

1601 return a.getKind() > b.getKind();

1603 });

1604

1605 for (const auto &U : *vec) {

1606

1608

1610

1611

1612 break;

1613 }

1614 }

1615

1616

1617 delete vec;

1618 }

1619

1620 uses.clear();

1621

1622

1623 for (const auto &P : constRefUses) {

1624 const VarDecl *vd = P.first;

1625 const MappedType &V = P.second;

1626

1627 UsesVec *vec = V.getPointer();

1628 bool hasSelfInit = V.getInt();

1629

1630 if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))

1633 true),

1634 true);

1635 else {

1636 for (const auto &U : *vec) {

1638 break;

1639 }

1640 }

1641

1642

1643 delete vec;

1644 }

1645

1646 constRefUses.clear();

1647 }

1648

1649private:

1650 static bool hasAlwaysUninitializedUse(const UsesVec* vec) {

1651 return llvm::any_of(*vec, [](const UninitUse &U) {

1655 });

1656 }

1657};

1658

1659

1660class CalledOnceInterProceduralData {

1661public:

1662

1665 DelayedBlockWarnings[Block].emplace_back(std::move(Warning));

1666 }

1667

1670 S.Diag(Delayed.first, Delayed.second);

1671

1672 discardWarnings(Block);

1673 }

1674

1676 DelayedBlockWarnings.erase(Block);

1677 }

1678

1679private:

1681 llvm::DenseMap<const BlockDecl *, DelayedDiagnostics> DelayedBlockWarnings;

1682};

1683

1685public:

1686 CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)

1689 const Expr *PrevCall, bool IsCompletionHandler,

1690 bool Poised) override {

1691 auto DiagToReport = IsCompletionHandler

1692 ? diag::warn_completion_handler_called_twice

1693 : diag::warn_called_once_gets_called_twice;

1695 S.Diag(PrevCall->getBeginLoc(), diag::note_called_once_gets_called_twice)

1696 << Poised;

1697 }

1698

1700 bool IsCompletionHandler) override {

1701 auto DiagToReport = IsCompletionHandler

1702 ? diag::warn_completion_handler_never_called

1703 : diag::warn_called_once_never_called;

1705 << Parameter << false;

1706 }

1707

1710 bool IsCalledDirectly,

1711 bool IsCompletionHandler) override {

1712 auto DiagToReport = IsCompletionHandler

1713 ? diag::warn_completion_handler_never_called_when

1714 : diag::warn_called_once_never_called_when;

1717 << IsCalledDirectly

1718 << (unsigned)Reason);

1719

1720 if (const auto *Block = dyn_cast(Function)) {

1721

1723 } else {

1725 }

1726 }

1727

1729 const Decl *Where,

1730 bool IsCompletionHandler) override {

1731 auto DiagToReport = IsCompletionHandler

1732 ? diag::warn_completion_handler_never_called

1733 : diag::warn_called_once_never_called;

1735 << Parameter << true;

1736 }

1737

1738 void

1741 }

1742

1745 }

1746

1747private:

1749 CalledOnceInterProceduralData &Data;

1750};

1751

1752constexpr unsigned CalledOnceWarnings[] = {

1753 diag::warn_called_once_never_called,

1754 diag::warn_called_once_never_called_when,

1755 diag::warn_called_once_gets_called_twice};

1756

1757constexpr unsigned CompletionHandlerWarnings[]{

1758 diag::warn_completion_handler_never_called,

1759 diag::warn_completion_handler_never_called_when,

1760 diag::warn_completion_handler_called_twice};

1761

1765 return llvm::any_of(DiagIDs, [&Diags, At](unsigned DiagID) {

1766 return !Diags.isIgnored(DiagID, At);

1767 });

1768}

1769

1770bool shouldAnalyzeCalledOnceConventions(const DiagnosticsEngine &Diags,

1772 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);

1773}

1774

1775bool shouldAnalyzeCalledOnceParameters(const DiagnosticsEngine &Diags,

1777 return shouldAnalyzeCalledOnceImpl(CalledOnceWarnings, Diags, At) ||

1778 shouldAnalyzeCalledOnceConventions(Diags, At);

1779}

1780}

1781

1782

1783

1784

1785namespace clang {

1786namespace threadSafety {

1787namespace {

1792

1794 bool Verbose;

1795

1797 if (Verbose && CurrentFunction) {

1799 S.PDiag(diag::note_thread_warning_in_fun)

1800 << CurrentFunction);

1802 }

1804 }

1805

1808 if (Verbose && CurrentFunction) {

1810 S.PDiag(diag::note_thread_warning_in_fun)

1811 << CurrentFunction);

1812 ONS.push_back(std::move(FNote));

1813 }

1814 return ONS;

1815 }

1816

1820 ONS.push_back(Note1);

1821 ONS.push_back(Note2);

1822 if (Verbose && CurrentFunction) {

1824 S.PDiag(diag::note_thread_warning_in_fun)

1825 << CurrentFunction);

1826 ONS.push_back(std::move(FNote));

1827 }

1828 return ONS;

1829 }

1830

1832 return LocLocked.isValid()

1834 LocLocked, S.PDiag(diag::note_locked_here) << Kind))

1835 : getNotes();

1836 }

1837

1839 StringRef Kind) {

1840 return LocUnlocked.isValid()

1842 LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))

1843 : getNotes();

1844 }

1845

1847 return DeclLoc.isValid()

1849 DeclLoc,

1850 S.PDiag(diag::note_managed_mismatch_here_for_param)))

1851 : getNotes();

1852 }

1853

1854 public:

1856 : S(S), FunLocation(FL), FunEndLocation(FEL),

1857 CurrentFunction(nullptr), Verbose(false) {}

1858

1859 void setVerbose(bool b) { Verbose = b; }

1860

1861

1862

1863

1864

1866 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));

1867 for (const auto &Diag : Warnings) {

1868 S.Diag(Diag.first.first, Diag.first.second);

1869 for (const auto &Note : Diag.second)

1871 }

1872 }

1873

1875 Name scopeName, StringRef Kind,

1876 Name expected, Name actual) override {

1878 S.PDiag(diag::warn_unmatched_underlying_mutexes)

1879 << Kind << scopeName << expected << actual);

1880 Warnings.emplace_back(std::move(Warning),

1881 makeManagedMismatchNoteForParam(DLoc));

1882 }

1883

1886 StringRef Kind,

1887 Name expected) override {

1889 Loc, S.PDiag(diag::warn_expect_more_underlying_mutexes)

1890 << Kind << scopeName << expected);

1891 Warnings.emplace_back(std::move(Warning),

1892 makeManagedMismatchNoteForParam(DLoc));

1893 }

1894

1897 StringRef Kind,

1898 Name actual) override {

1900 Loc, S.PDiag(diag::warn_expect_fewer_underlying_mutexes)

1901 << Kind << scopeName << actual);

1902 Warnings.emplace_back(std::move(Warning),

1903 makeManagedMismatchNoteForParam(DLoc));

1904 }

1905

1908 << Loc);

1909 Warnings.emplace_back(std::move(Warning), getNotes());

1910 }

1911

1912 void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,

1915 Loc = FunLocation;

1917 << Kind << LockName);

1918 Warnings.emplace_back(std::move(Warning),

1919 makeUnlockedHereNote(LocPreviousUnlock, Kind));

1920 }

1921

1922 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,

1927 LocUnlock = FunLocation;

1929 LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)

1930 << Kind << LockName << Received << Expected);

1931 Warnings.emplace_back(std::move(Warning),

1932 makeLockedHereNote(LocLocked, Kind));

1933 }

1934

1935 void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,

1938 LocDoubleLock = FunLocation;

1940 << Kind << LockName);

1941 Warnings.emplace_back(std::move(Warning),

1942 makeLockedHereNote(LocLocked, Kind));

1943 }

1944

1945 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,

1949 unsigned DiagID = 0;

1950 switch (LEK) {

1952 DiagID = diag::warn_lock_some_predecessors;

1953 break;

1955 DiagID = diag::warn_expecting_lock_held_on_loop;

1956 break;

1958 DiagID = diag::warn_no_unlock;

1959 break;

1961 DiagID = diag::warn_expecting_locked;

1962 break;

1963 }

1965 LocEndOfScope = FunEndLocation;

1966

1968 << LockName);

1969 Warnings.emplace_back(std::move(Warning),

1970 makeLockedHereNote(LocLocked, Kind));

1971 }

1972

1973 void handleExclusiveAndShared(StringRef Kind, Name LockName,

1977 S.PDiag(diag::warn_lock_exclusive_and_shared)

1978 << Kind << LockName);

1980 << Kind << LockName);

1981 Warnings.emplace_back(std::move(Warning), getNotes(Note));

1982 }

1983

1987 "Only works for variables");

1989 diag::warn_variable_requires_any_lock:

1990 diag::warn_var_deref_requires_any_lock;

1993 Warnings.emplace_back(std::move(Warning), getNotes());

1994 }

1995

1996 void handleMutexNotHeld(StringRef Kind, const NamedDecl *D,

1999 Name *PossibleMatch) override {

2000 unsigned DiagID = 0;

2001 if (PossibleMatch) {

2002 switch (POK) {

2004 DiagID = diag::warn_variable_requires_lock_precise;

2005 break;

2007 DiagID = diag::warn_var_deref_requires_lock_precise;

2008 break;

2010 DiagID = diag::warn_fun_requires_lock_precise;

2011 break;

2013 DiagID = diag::warn_guarded_pass_by_reference;

2014 break;

2016 DiagID = diag::warn_pt_guarded_pass_by_reference;

2017 break;

2019 DiagID = diag::warn_guarded_return_by_reference;

2020 break;

2022 DiagID = diag::warn_pt_guarded_return_by_reference;

2023 break;

2024 }

2026 << D

2027 << LockName << LK);

2029 << *PossibleMatch);

2032 S.PDiag(diag::note_guarded_by_declared_here)

2033 << D->getDeclName());

2034 Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote));

2035 } else

2036 Warnings.emplace_back(std::move(Warning), getNotes(Note));

2037 } else {

2038 switch (POK) {

2040 DiagID = diag::warn_variable_requires_lock;

2041 break;

2043 DiagID = diag::warn_var_deref_requires_lock;

2044 break;

2046 DiagID = diag::warn_fun_requires_lock;

2047 break;

2049 DiagID = diag::warn_guarded_pass_by_reference;

2050 break;

2052 DiagID = diag::warn_pt_guarded_pass_by_reference;

2053 break;

2055 DiagID = diag::warn_guarded_return_by_reference;

2056 break;

2058 DiagID = diag::warn_pt_guarded_return_by_reference;

2059 break;

2060 }

2062 << D

2063 << LockName << LK);

2066 S.PDiag(diag::note_guarded_by_declared_here));

2067 Warnings.emplace_back(std::move(Warning), getNotes(Note));

2068 } else

2069 Warnings.emplace_back(std::move(Warning), getNotes());

2070 }

2071 }

2072

2073 void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,

2076 S.PDiag(diag::warn_acquire_requires_negative_cap)

2077 << Kind << LockName << Neg);

2078 Warnings.emplace_back(std::move(Warning), getNotes());

2079 }

2080

2081 void handleNegativeNotHeld(const NamedDecl *D, Name LockName,

2084 Loc, S.PDiag(diag::warn_fun_requires_negative_cap) << D << LockName);

2085 Warnings.emplace_back(std::move(Warning), getNotes());

2086 }

2087

2088 void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,

2091 << Kind << FunName << LockName);

2092 Warnings.emplace_back(std::move(Warning), getNotes());

2093 }

2094

2095 void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,

2098 S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);

2099 Warnings.emplace_back(std::move(Warning), getNotes());

2100 }

2101

2102 void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override {

2104 S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);

2105 Warnings.emplace_back(std::move(Warning), getNotes());

2106 }

2107

2108 void enterFunction(const FunctionDecl* FD) override {

2109 CurrentFunction = FD;

2110 }

2111

2112 void leaveFunction(const FunctionDecl* FD) override {

2113 CurrentFunction = nullptr;

2114 }

2115};

2116}

2117}

2118}

2119

2120

2121

2122

2123

2124namespace clang {

2125namespace consumed {

2126namespace {

2127class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {

2128

2131

2132public:

2133

2134 ConsumedWarningsHandler(Sema &S) : S(S) {}

2135

2137 Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));

2138 for (const auto &Diag : Warnings) {

2139 S.Diag(Diag.first.first, Diag.first.second);

2140 for (const auto &Note : Diag.second)

2142 }

2143 }

2144

2146 StringRef VariableName) override {

2148 VariableName);

2149

2151 }

2152

2154 StringRef VariableName,

2155 StringRef ExpectedState,

2156 StringRef ObservedState) override {

2157

2159 diag::warn_param_return_typestate_mismatch) << VariableName <<

2160 ExpectedState << ObservedState);

2161

2163 }

2164

2165 void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,

2166 StringRef ObservedState) override {

2167

2169 diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);

2170

2172 }

2173

2175 StringRef TypeName) override {

2177 diag::warn_return_typestate_for_unconsumable_type) << TypeName);

2178

2180 }

2181

2182 void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,

2183 StringRef ObservedState) override {

2184

2186 diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);

2187

2189 }

2190

2191 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,

2193

2195 diag::warn_use_of_temp_in_invalid_state) << MethodName << State);

2196

2198 }

2199

2200 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,

2202

2204 MethodName << VariableName << State);

2205

2207 }

2208};

2209}

2210}

2211}

2212

2213

2214

2215

2216

2217namespace {

2220 bool SuggestSuggestions;

2221

2222

2223

2224 std::string listVariableGroupAsString(

2226 if (VarGroupForVD.size() <= 1)

2227 return "";

2228

2229 std::vector VarNames;

2230 auto PutInQuotes = [](StringRef S) -> std::string {

2231 return "'" + S.str() + "'";

2232 };

2233

2234 for (auto *V : VarGroupForVD) {

2235 if (V == VD)

2236 continue;

2237 VarNames.push_back(V->getName());

2238 }

2239 if (VarNames.size() == 1) {

2240 return PutInQuotes(VarNames[0]);

2241 }

2242 if (VarNames.size() == 2) {

2243 return PutInQuotes(VarNames[0]) + " and " + PutInQuotes(VarNames[1]);

2244 }

2245 assert(VarGroupForVD.size() > 3);

2246 const unsigned N = VarNames.size() -

2247 2;

2248 std::string AllVars = "";

2249

2250 for (unsigned I = 0; I < N; ++I)

2251 AllVars.append(PutInQuotes(VarNames[I]) + ", ");

2252 AllVars.append(PutInQuotes(VarNames[N]) + ", and " +

2253 PutInQuotes(VarNames[N + 1]));

2254 return AllVars;

2255 }

2256

2257public:

2258 UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions)

2259 : S(S), SuggestSuggestions(SuggestSuggestions) {}

2260

2265 unsigned MsgParam = 0;

2267 if (const auto *ASE = dyn_cast(Operation)) {

2268 Loc = ASE->getBase()->getExprLoc();

2269 Range = ASE->getBase()->getSourceRange();

2270 MsgParam = 2;

2271 } else if (const auto *BO = dyn_cast(Operation)) {

2273 if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||

2274 Op == BO_SubAssign) {

2275 if (BO->getRHS()->getType()->isIntegerType()) {

2276 Loc = BO->getLHS()->getExprLoc();

2277 Range = BO->getLHS()->getSourceRange();

2278 } else {

2279 Loc = BO->getRHS()->getExprLoc();

2280 Range = BO->getRHS()->getSourceRange();

2281 }

2282 MsgParam = 1;

2283 }

2284 } else if (const auto *UO = dyn_cast(Operation)) {

2286 if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||

2287 Op == UO_PostDec) {

2288 Loc = UO->getSubExpr()->getExprLoc();

2289 Range = UO->getSubExpr()->getSourceRange();

2290 MsgParam = 1;

2291 }

2292 } else {

2293 if (isa(Operation) || isa(Operation)) {

2294

2295 assert(!IsRelatedToDecl && "Not implemented yet!");

2296 MsgParam = 3;

2297 } else if (isa(Operation)) {

2298

2299 assert(!IsRelatedToDecl && "Not implemented yet!");

2300 auto *ME = cast(Operation);

2301 D = ME->getMemberDecl();

2302 MsgParam = 5;

2303 } else if (const auto *ECE = dyn_cast(Operation)) {

2304 QualType destType = ECE->getType();

2305 bool destTypeComplete = true;

2306

2307 if (!isa(destType))

2308 return;

2311 destTypeComplete = D->isCompleteDefinition();

2312

2313

2314

2315 if (destTypeComplete) {

2317 QualType srcType = ECE->getSubExpr()->getType();

2318

2320

2323

2324 if (sSize >= dSize)

2325 return;

2326 }

2327 if (const auto *CE = dyn_cast(

2328 ECE->getSubExpr()->IgnoreParens())) {

2329 D = CE->getMethodDecl();

2330 }

2331

2332 if (D)

2333 return;

2334

2335 MsgParam = 4;

2336 }

2339 }

2340 if (IsRelatedToDecl) {

2341 assert(!SuggestSuggestions &&

2342 "Variables blamed for unsafe buffer usage without suggestions!");

2343 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;

2344 } else {

2345 if (D) {

2346 S.Diag(Loc, diag::warn_unsafe_buffer_operation)

2347 << MsgParam << D << Range;

2348 } else {

2349 S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range;

2350 }

2351 if (SuggestSuggestions) {

2352 S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);

2353 }

2354 }

2355 }

2356

2359 const Expr *UnsafeArg = nullptr) override {

2360 S.Diag(Call->getBeginLoc(), diag::warn_unsafe_buffer_libc_call)

2361 << Call->getDirectCallee()

2362 << Call->getSourceRange();

2363 if (PrintfInfo > 0) {

2365 UnsafeArg ? UnsafeArg->getSourceRange() : Call->getSourceRange();

2366 S.Diag(R.getBegin(), diag::note_unsafe_buffer_printf_call)

2367 << PrintfInfo << R;

2368 }

2369 }

2370

2372 bool IsRelatedToDecl,

2376 unsigned MsgParam = 0;

2377

2378

2379

2380 const auto *CtorExpr = cast(Operation);

2381 Loc = CtorExpr->getLocation();

2382

2383 S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);

2384 if (IsRelatedToDecl) {

2385 assert(!SuggestSuggestions &&

2386 "Variables blamed for unsafe buffer usage without suggestions!");

2387 S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;

2388 }

2389 }

2390

2393 FixItList &&Fixes, const Decl *D,

2395 assert(!SuggestSuggestions &&

2396 "Unsafe buffer usage fixits displayed without suggestions!");

2400 if (!Fixes.empty()) {

2401 assert(isa(D) &&

2402 "Fix-its are generated only for `NamedDecl`s");

2403 const NamedDecl *ND = cast(D);

2404 bool BriefMsg = false;

2405

2406

2407

2409 unsigned FixItStrategy = 0;

2412 FixItStrategy = 0;

2413 break;

2415 FixItStrategy = 1;

2416 break;

2417 default:

2418 assert(false && "We support only std::span and std::array");

2419 };

2420

2421 const auto &FD =

2423 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together

2424 : diag::note_unsafe_buffer_variable_fixit_group);

2425

2426 FD << Variable << FixItStrategy;

2427 FD << listVariableGroupAsString(Variable, VarGroupForVD)

2428 << (VarGroupForVD.size() > 1) << ND;

2429 for (const auto &F : Fixes) {

2430 FD << F;

2431 }

2432 }

2433

2434#ifndef NDEBUG

2436 for (const DebugNote &Note: DebugNotesByVar[Variable])

2437 S.Diag(Note.first, diag::note_safe_buffer_debug_mode) << Note.second;

2438#endif

2439 }

2440

2443 }

2444

2446 return S.Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container, Loc);

2447 }

2448

2450 return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);

2451 }

2452

2453

2454

2455

2456 std::string

2458 StringRef WSSuffix = "") const override {

2460 TokenValue ClangUnsafeBufferUsageTokens[] = {

2461 tok::l_square,

2462 tok::l_square,

2464 tok::coloncolon,

2466 tok::r_square,

2467 tok::r_square};

2468

2469 StringRef MacroName;

2470

2471

2473 if (MacroName.empty())

2474 MacroName = "[[clang::unsafe_buffer_usage]]";

2475 return MacroName.str() + WSSuffix.str();

2476 }

2477};

2478}

2479

2480

2481

2482

2483

2484

2486 enableCheckFallThrough = 1;

2487 enableCheckUnreachable = 0;

2488 enableThreadSafetyAnalysis = 0;

2489 enableConsumedAnalysis = 0;

2490}

2491

2492

2493

2494

2495

2496

2497

2498

2499

2500

2501

2502

2504public:

2505

2506

2508};

2509

2512}

2513

2516 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),

2517 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),

2518 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),

2519 NumUninitAnalysisBlockVisits(0),

2520 MaxUninitAnalysisBlockVisitsPerFunction(0) {

2521

2522 using namespace diag;

2524

2525 DefaultPolicy.enableCheckUnreachable =

2527 isEnabled(D, warn_unreachable_return) ||

2528 isEnabled(D, warn_unreachable_loop_increment);

2529

2530 DefaultPolicy.enableThreadSafetyAnalysis = isEnabled(D, warn_double_lock);

2531

2532 DefaultPolicy.enableConsumedAnalysis =

2533 isEnabled(D, warn_use_in_invalid_state);

2534}

2535

2536

2538

2541 S.Diag(D.Loc, D.PD);

2542}

2543

2544

2545

2547private:

2548 llvm::function_ref<void(const Decl *)> Callback;

2549

2550public:

2552 : Callback(Callback) {

2553 ShouldVisitTemplateInstantiations = true;

2554 ShouldVisitImplicitCode = false;

2555 }

2556

2558 if (cast(Node)->isDependentContext())

2559 return true;

2560

2561

2562

2563 if (Node->doesThisDeclarationHaveABody())

2564 Callback(Node);

2565 return true;

2566 }

2567

2569 if (cast(Node)->isDependentContext())

2570 return true;

2571 Callback(Node);

2572 return true;

2573 }

2574

2576 if (cast(Node)->isDependentContext())

2577 return true;

2578 if (Node->hasBody())

2579 Callback(Node);

2580 return true;

2581 }

2582

2584 return VisitFunctionDecl(Node->getCallOperator());

2585 }

2586};

2587

2590 if (!TU)

2591 return;

2592

2594

2596

2597 return;

2598

2600

2601

2602 bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;

2603 bool UnsafeBufferUsageShouldEmitSuggestions =

2604 UnsafeBufferUsageCanEmitSuggestions &&

2605 DiagOpts.ShowSafeBufferUsageSuggestions;

2606 bool UnsafeBufferUsageShouldSuggestSuggestions =

2607 UnsafeBufferUsageCanEmitSuggestions &&

2608 !DiagOpts.ShowSafeBufferUsageSuggestions;

2609 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);

2610

2611

2612 auto CallAnalyzers = [&](const Decl *Node) -> void {

2613

2614 if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation,

2615 Node->getBeginLoc()) ||

2616 !Diags.isIgnored(diag::warn_unsafe_buffer_variable,

2617 Node->getBeginLoc()) ||

2618 !Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container,

2619 Node->getBeginLoc()) ||

2620 !Diags.isIgnored(diag::warn_unsafe_buffer_libc_call,

2621 Node->getBeginLoc())) {

2623 UnsafeBufferUsageShouldEmitSuggestions);

2624 }

2625

2626

2627 };

2628

2629

2632 !Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container,

2635 S.getLangOpts().CPlusPlus )) {

2636 CallableVisitor(CallAnalyzers).TraverseTranslationUnitDecl(TU);

2637 }

2638}

2639

2643

2644

2645

2646

2647

2648

2649

2651

2652

2656 return;

2657

2658

2659 if (cast(D)->isDependentContext())

2660 return;

2661

2663

2665 return;

2666 }

2667

2669 assert(Body);

2670

2671

2673

2674

2675

2676 AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;

2677 AC.getCFGBuildOptions().AddEHEdges = false;

2678 AC.getCFGBuildOptions().AddInitializers = true;

2679 AC.getCFGBuildOptions().AddImplicitDtors = true;

2680 AC.getCFGBuildOptions().AddTemporaryDtors = true;

2681 AC.getCFGBuildOptions().AddCXXNewAllocator = false;

2682 AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;

2683

2684

2685

2686

2687

2688

2689

2690 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||

2691 P.enableConsumedAnalysis) {

2692

2693 AC.getCFGBuildOptions().setAllAlwaysAdd();

2694 }

2695 else {

2696 AC.getCFGBuildOptions()

2697 .setAlwaysAdd(Stmt::BinaryOperatorClass)

2698 .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)

2699 .setAlwaysAdd(Stmt::BlockExprClass)

2700 .setAlwaysAdd(Stmt::CStyleCastExprClass)

2701 .setAlwaysAdd(Stmt::DeclRefExprClass)

2702 .setAlwaysAdd(Stmt::ImplicitCastExprClass)

2703 .setAlwaysAdd(Stmt::UnaryOperatorClass);

2704 }

2705

2706

2707 std::optional LEH;

2708 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {

2709 LEH.emplace(S);

2710 AC.getCFGBuildOptions().Observer = &*LEH;

2711 }

2712

2713

2715 bool analyzed = false;

2716

2717

2719 for (const Stmt *S : D.Stmts)

2720 AC.registerForcedBlockExpression(S);

2721 }

2722

2723 if (AC.getCFG()) {

2724 analyzed = true;

2726 bool AllReachable = true;

2727 for (const Stmt *S : D.Stmts) {

2728 const CFGBlock *block = AC.getBlockForRegisteredExpression(S);

2730 AC.getCFGReachablityAnalysis();

2731

2732

2733

2734 if (block && cra) {

2735

2736 if (!cra->isReachable(&AC.getCFG()->getEntry(), block)) {

2737 AllReachable = false;

2738 break;

2739 }

2740 }

2741

2742

2743 }

2744

2745 if (AllReachable)

2746 S.Diag(D.Loc, D.PD);

2747 }

2748 }

2749

2750 if (!analyzed)

2752 }

2753

2754

2755 if (P.enableCheckFallThrough) {

2756 const CheckFallThroughDiagnostics &CD =

2757 (isa(D)

2758 ? CheckFallThroughDiagnostics::MakeForBlock()

2759 : (isa(D) &&

2760 cast(D)->getOverloadedOperator() == OO_Call &&

2761 cast(D)->getParent()->isLambda())

2762 ? CheckFallThroughDiagnostics::MakeForLambda()

2764 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)

2765 : CheckFallThroughDiagnostics::MakeForFunction(D)));

2767 }

2768

2769

2770 if (P.enableCheckUnreachable) {

2771

2772

2773

2774

2780 }

2781

2782

2783 if (P.enableThreadSafetyAnalysis) {

2786 threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL);

2788 Reporter.setIssueBetaWarnings(true);

2790 Reporter.setVerbose(true);

2791

2794 Reporter.emitDiagnostics();

2795 }

2796

2797

2798 if (P.enableConsumedAnalysis) {

2799 consumed::ConsumedWarningsHandler WarningHandler(S);

2801 Analyzer.run(AC);

2802 }

2803

2808 if (CFG *cfg = AC.getCFG()) {

2809 UninitValsDiagReporter reporter(S);

2813 reporter, stats);

2814

2816 ++NumUninitAnalysisFunctions;

2818 NumUninitAnalysisBlockVisits += stats.NumBlockVisits;

2819 MaxUninitAnalysisVariablesPerFunction =

2820 std::max(MaxUninitAnalysisVariablesPerFunction,

2822 MaxUninitAnalysisBlockVisitsPerFunction =

2823 std::max(MaxUninitAnalysisBlockVisitsPerFunction,

2825 }

2826 }

2827 }

2828

2829

2831 shouldAnalyzeCalledOnceParameters(Diags, D->getBeginLoc())) {

2832 if (AC.getCFG()) {

2833 CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);

2835 AC, Reporter,

2836 shouldAnalyzeCalledOnceConventions(Diags, D->getBeginLoc()));

2837 }

2838 }

2839

2840 bool FallThroughDiagFull =

2842 bool FallThroughDiagPerFunction = !Diags.isIgnored(

2843 diag::warn_unannotated_fallthrough_per_function, D->getBeginLoc());

2844 if (FallThroughDiagFull || FallThroughDiagPerFunction ||

2847 }

2848

2852

2853

2854

2855 if (!Diags.isIgnored(diag::warn_infinite_recursive_function,

2857 if (const FunctionDecl *FD = dyn_cast(D)) {

2859 }

2860 }

2861

2862

2864 if (const FunctionDecl *FD = dyn_cast(D))

2867

2868

2869

2870 if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {

2871 AC.getCFG();

2872 }

2873

2874

2876 ++NumFunctionsAnalyzed;

2877 if (CFG *cfg = AC.getCFG()) {

2878

2879

2880 NumCFGBlocks += cfg->getNumBlockIDs();

2881 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,

2882 cfg->getNumBlockIDs());

2883 } else {

2884 ++NumFunctionsWithBadCFGs;

2885 }

2886 }

2887}

2888

2890 llvm::errs() << "\n*** Analysis Based Warnings Stats:\n";

2891

2892 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;

2893 unsigned AvgCFGBlocksPerFunction =

2894 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;

2895 llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("

2896 << NumFunctionsWithBadCFGs << " w/o CFGs).\n"

2897 << " " << NumCFGBlocks << " CFG blocks built.\n"

2898 << " " << AvgCFGBlocksPerFunction

2899 << " average CFG blocks per function.\n"

2900 << " " << MaxCFGBlocksPerFunction

2901 << " max CFG blocks per function.\n";

2902

2903 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0

2904 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;

2905 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0

2906 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;

2907 llvm::errs() << NumUninitAnalysisFunctions

2908 << " functions analyzed for uninitialiazed variables\n"

2909 << " " << NumUninitAnalysisVariables << " variables analyzed.\n"

2910 << " " << AvgUninitVariablesPerFunction

2911 << " average variables per function.\n"

2912 << " " << MaxUninitAnalysisVariablesPerFunction

2913 << " max variables per function.\n"

2914 << " " << NumUninitAnalysisBlockVisits << " block visits.\n"

2915 << " " << AvgUninitBlockVisitsPerFunction

2916 << " average block visits per function.\n"

2917 << " " << MaxUninitAnalysisBlockVisitsPerFunction

2918 << " max block visits per function.\n";

2919}

static void visitReachableThrows(CFG *BodyCFG, llvm::function_ref< void(const CXXThrowExpr *, CFGBlock &)> Visit)

static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD)

static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, const Stmt *S)

static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC)

CheckFallThrough - Check that we don't fall off the end of a Statement that should return a value.

static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope)

static void diagnoseRepeatedUseOfWeak(Sema &S, const sema::FunctionScopeInfo *CurFn, const Decl *D, const ParentMap &PM)

static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, const FunctionDecl *FD)

static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction)

static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, AnalysisDeclContext &AC)

static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then, const Stmt *Else, bool CondVal, FixItHint &Fixit1, FixItHint &Fixit2)

Create a fixit to remove an if-like statement, on the assumption that its condition is CondVal.

static StringRef getFallthroughAttrSpelling(Preprocessor &PP, SourceLocation Loc)

static unsigned isEnabled(DiagnosticsEngine &D, unsigned diag)

static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, const UninitUse &Use, bool alwaysReportSelfInit=false)

DiagnoseUninitializedUse – Helper function for diagnosing uses of an uninitialized variable.

static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block)

static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, CFG *Body)

Determine whether an exception thrown by E, unwinding from ThrowBlock, can reach ExitBlock.

static bool isNoexcept(const FunctionDecl *FD)

static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD, const UninitUse &Use)

Diagnose uninitialized const reference usages.

static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, bool IsCapturedByBlock)

DiagUninitUse – Helper function to produce a diagnostic for an uninitialized use of a variable.

static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC)

CheckUnreachable - Check for unreachable code.

static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, QualType BlockType, const CheckFallThroughDiagnostics &CD, AnalysisDeclContext &AC, sema::FunctionScopeInfo *FSI)

CheckFallThroughForBody - Check that we don't fall off the end of a function that should return a val...

@ NeverFallThroughOrReturn

static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, const Stmt *Body, AnalysisDeclContext &AC)

static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg)

This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...

Defines the Diagnostic-related interfaces.

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

Defines the clang::Expr interface and subclasses for C++ expressions.

static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult, const ASTContext &Ctx, Expr::SideEffectsKind AllowSideEffects, EvalInfo &Info)

static std::pair< const Stmt *, const CFGBlock * > getLastStmt(const ExplodedNode *Node)

llvm::DenseSet< const void * > Visited

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.

static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)

Defines the clang::Preprocessor interface.

Defines the clang::SourceLocation class and associated facilities.

Defines the SourceManager interface.

Defines the Objective-C statement AST node classes.

C Language Family Type Representation.

@ Open

The standard open() call: int open(const char *path, int oflag, ...);.

TextDiagnosticBuffer::DiagList DiagList

__device__ __2f16 float __ockl_bool s

CallableVisitor(llvm::function_ref< void(const Decl *)> Callback)

bool VisitObjCMethodDecl(ObjCMethodDecl *Node) override

bool VisitBlockDecl(BlockDecl *Node) override

bool VisitFunctionDecl(FunctionDecl *Node) override

bool VisitLambdaExpr(LambdaExpr *Node) override

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

uint64_t getTypeSize(QualType T) const

Return the size of the specified (complete) type T, in bits.

AnalysisDeclContext contains the context data for the function, method or block under analysis.

Represents an attribute applied to a statement.

A builtin binary operation expression such as "x + y" or "x <= y".

static bool isLogicalOp(Opcode Opc)

SourceLocation getBeginLoc() const LLVM_READONLY

SourceLocation getOperatorLoc() const

SourceLocation getExprLoc() const

static StringRef getOpcodeStr(Opcode Op)

getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...

Represents a block literal declaration, which is like an unnamed FunctionDecl.

BlockExpr - Adaptor class for mixing a BlockDecl with expressions.

SourceLocation getBeginLoc() const LLVM_READONLY

unsigned IgnoreDefaultsWithCoveredEnums

Represents a single basic block in a source-level CFG.

filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const

reverse_iterator rbegin()

bool hasNoReturnElement() const

succ_iterator succ_begin()

Stmt * getTerminatorStmt()

pred_iterator pred_begin()

unsigned getBlockID() const

unsigned succ_size() const

CFGCallback defines methods that should be called when a logical operator error is found when buildin...

virtual void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue)

virtual void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)

virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)

virtual void compareBitwiseOr(const BinaryOperator *B)

Represents a top-level expression in a basic block.

T castAs() const

Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.

std::optional< T > getAs() const

Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...

bool isReachable(const CFGBlock *Src, const CFGBlock *Dst)

Returns true if the block 'Dst' can be reached from block 'Src'.

const Stmt * getStmt() const

Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.

unsigned getNumBlockIDs() const

Returns the total number of BlockIDs allocated (which start at 0).

Represents a call to a member function that may be written either with member call syntax (e....

CXXMethodDecl * getMethodDecl() const

Retrieve the declaration of the called method.

Expr * getImplicitObjectArgument() const

Retrieve the implicit object argument for the member call.

Represents a static or instance method of a struct/union/class.

A C++ throw-expression (C++ [except.throw]).

SourceLocation getThrowLoc() const

CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).

virtual void handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl *Block)

Called when the block is guaranteed to be called exactly once.

virtual void handleBlockWithNoGuarantees(const BlockDecl *Block)

Called when the block has no guarantees about how many times it can get called.

virtual void handleDoubleCall(const ParmVarDecl *Parameter, const Expr *Call, const Expr *PrevCall, bool IsCompletionHandler, bool Poised)

Called when parameter is called twice.

virtual void handleNeverCalled(const ParmVarDecl *Parameter, bool IsCompletionHandler)

Called when parameter is not called at all.

virtual void handleCapturedNeverCalled(const ParmVarDecl *Parameter, const Decl *Where, bool IsCompletionHandler)

Called when captured parameter is not called at all.

static CharSourceRange getCharRange(SourceRange R)

SourceLocation getBegin() const

ConditionalOperator - The ?: ternary operator.

Expr * getFalseExpr() const

getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...

Expr * getCond() const

getCond - Return the expression representing the condition for the ?: operator.

Expr * getTrueExpr() const

getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...

ConstEvaluatedExprVisitor - This class visits 'const Expr *'s.

DeclContext - This is used only as base class of specific decl types that can act as declaration cont...

A reference to a declared variable, function, enum, etc.

Decl - This represents one declaration (or definition), e.g.

SourceLocation getEndLoc() const LLVM_READONLY

virtual Stmt * getBody() const

getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...

FunctionDecl * getAsFunction() LLVM_READONLY

Returns the function itself, or the templated function if this is a function template.

SourceLocation getLocation() const

SourceLocation getBeginLoc() const LLVM_READONLY

DeclContext * getLexicalDeclContext()

getLexicalDeclContext - The declaration context where this Decl was lexically declared (LexicalDC).

virtual Decl * getCanonicalDecl()

Retrieves the "canonical" declaration of the given declaration.

OverloadedOperatorKind getCXXOverloadedOperator() const

If this name is the name of an overloadable operator in C++ (e.g., operator+), retrieve the kind of o...

SourceLocation getBeginLoc() const LLVM_READONLY

TypeSourceInfo * getTypeSourceInfo() const

Options for controlling the compiler diagnostics engine.

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

bool getIgnoreAllWarnings() const

DiagnosticOptions & getDiagnosticOptions() const

Retrieve the diagnostic options.

bool isIgnored(unsigned DiagID, SourceLocation Loc) const

Determine whether the diagnostic is known to be ignored.

bool getSuppressSystemWarnings() const

Recursive AST visitor that supports extension via dynamic dispatch.

virtual bool TraverseDecl(Decl *D)

Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...

virtual bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, Expr *Init)

Recursively visit a lambda capture.

void VisitDeclRefExpr(PTR(DeclRefExpr) E)

This represents one expression.

Expr * IgnoreParenCasts() LLVM_READONLY

Skip past any parentheses and casts which might surround this expression until reaching a fixed point...

Expr * IgnoreParenImpCasts() LLVM_READONLY

Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...

SourceLocation getExprLoc() const LLVM_READONLY

getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...

Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...

CharSourceRange RemoveRange

Code that should be replaced to correct the error.

static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)

Create a code modification hint that replaces the given source range with the given code string.

static FixItHint CreateRemoval(CharSourceRange RemoveRange)

Create a code modification hint that removes the given source range.

static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)

Create a code modification hint that inserts the given code string at a specific location.

Kind lookup(const VarDecl *VD) const

Represents a function declaration or definition.

Stmt * getBody(const FunctionDecl *&Definition) const

Retrieve the body (definition) of the function.

FunctionDecl * getCanonicalDecl() override

Retrieves the "canonical" declaration of the given declaration.

SourceRange getExceptionSpecSourceRange() const

Attempt to compute an informative source range covering the function exception specification,...

@ TK_MemberSpecialization

TemplatedKind getTemplatedKind() const

What kind of templated function this is.

bool isCPUDispatchMultiVersion() const

True if this function is a multiversioned dispatch function as a part of the cpu_specific/cpu_dispatc...

Represents a prototype with parameter type info, e.g.

FunctionType - C99 6.7.5.3 - Function Declarators.

IfStmt - This represents an if/then/else.

LabelStmt - Represents a label, which has a substatement.

A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...

This represents a decl that may have a name.

DeclarationName getDeclName() const

Get the actual, stored name of the declaration, which may be a special name.

Represents a C++ nested name specifier, such as "\::std::vector::".

@ TypeSpec

A type, stored as a Type*.

ObjCMethodDecl - Represents an instance or class method declaration.

Represents one property declaration in an Objective-C interface.

Stmt * getParent(Stmt *) const

Represents a parameter to a function.

Engages in a tight little dance with the lexer to efficiently preprocess tokens.

bool isSafeBufferOptOut(const SourceManager &SourceMgr, const SourceLocation &Loc) const

IdentifierInfo * getIdentifierInfo(StringRef Name) const

Return information about the specified preprocessor identifier token.

const LangOptions & getLangOpts() const

StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef< TokenValue > Tokens) const

Return the name of the macro defined before Loc that has spelling Tokens.

A (possibly-)qualified type.

bool isNull() const

Return true if this QualType doesn't point to a type yet.

const Type * getTypePtr() const

Retrieves a pointer to the underlying (unqualified) type.

Qualifiers getQualifiers() const

Retrieve the set of qualifiers applied to this type.

QualType getCanonicalType() const

bool hasObjCLifetime() const

SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)

Emit a diagnostic.

PartialDiagnostic PDiag(unsigned DiagID=0)

Build a partial diagnostic.

Sema - This implements semantic analysis and AST building for C.

Preprocessor & getPreprocessor() const

DiagnosticsEngine & getDiagnostics() const

ASTContext & getASTContext() const

std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const

Get a string to suggest for zero-initialization of a type.

SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)

Calls Lexer::getLocForEndOfToken()

const LangOptions & getLangOpts() const

threadSafety::BeforeSet * ThreadSafetyDeclCache

bool CollectStats

Flag indicating whether or not to collect detailed statistics.

SourceManager & getSourceManager() const

bool handlerCanCatch(QualType HandlerType, QualType ExceptionType)

bool hasUncompilableErrorOccurred() const

Whether uncompilable error has occurred.

SourceManager & SourceMgr

DiagnosticsEngine & Diags

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

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

bool isInMainFile(SourceLocation Loc) const

Returns whether the PresumedLoc for a given SourceLocation is in the main file.

bool isInSystemHeader(SourceLocation Loc) const

Returns if a SourceLocation is in a system header.

bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const

Determines the order of 2 source locations in the translation unit.

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

Stmt - This represents one statement.

SourceLocation getEndLoc() const LLVM_READONLY

StmtClass getStmtClass() const

SourceRange getSourceRange() const LLVM_READONLY

SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...

SourceLocation getBeginLoc() const LLVM_READONLY

SwitchStmt - This represents a 'switch' stmt.

Stores token information for comparing actual tokens with predefined values.

The top declaration context.

QualType getType() const

Return the type wrapped by this type source info.

bool isBlockPointerType() const

bool isPointerType() const

const T * castAs() const

Member-template castAs.

QualType getPointeeType() const

If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.

const T * getAs() const

Member-template getAs'.

TagDecl * getAsTagDecl() const

Retrieves the TagDecl that this type refers to, either because the type is a TagType or because it is...

A use of a variable, which might be uninitialized.

const Expr * getUser() const

Get the expression containing the uninitialized use.

SmallVectorImpl< Branch >::const_iterator branch_iterator

branch_iterator branch_end() const

branch_iterator branch_begin() const

Branches which inevitably result in the variable being used uninitialized.

@ Always

The use is always uninitialized.

@ AfterDecl

The use is uninitialized the first time it is reached after we reach the variable's declaration.

@ Maybe

The use might be uninitialized.

@ AfterCall

The use is uninitialized the first time it is reached after the function is called.

@ Sometimes

The use is uninitialized whenever a certain branch is taken.

Kind getKind() const

Get the kind of uninitialized use.

virtual void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use)

Called when the uninitialized variable is used at the given expression.

virtual void handleSelfInit(const VarDecl *vd)

Called when the uninitialized variable analysis detects the idiom 'int x = x'.

virtual void handleConstRefUseOfUninitVariable(const VarDecl *vd, const UninitUse &use)

Called when the uninitialized variable is used as const refernce argument.

The interface that lets the caller handle unsafe buffer usage analysis results by overriding this cla...

bool areDebugNotesRequested()

virtual std::string getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, StringRef WSSuffix="") const =0

virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const =0

virtual bool ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const =0

virtual void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0

Invoked when an unsafe operation over raw pointers is found.

virtual void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, const FixitStrategy &VarTargetTypes)=0

Invoked when a fix is suggested against a variable.

virtual void handleUnsafeOperationInContainer(const Stmt *Operation, bool IsRelatedToDecl, ASTContext &Ctx)=0

Invoked when an unsafe operation with a std container is found.

virtual bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const =0

virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo, ASTContext &Ctx, const Expr *UnsafeArg=nullptr)=0

Invoked when a call to an unsafe libc function is found.

Represents a variable declaration or definition.

SourceRange getSourceRange() const override LLVM_READONLY

Source range that this declaration covers.

const Expr * getInit() const

virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm=nullptr) const =0

Returns the set of variables (including Var) that need to be fixed together in one step.

A class that handles the analysis of uniqueness violations.

void run(AnalysisDeclContext &AC)

Check a function's CFG for consumed violations.

virtual void HandleUnreachable(UnreachableKind UK, SourceLocation L, SourceRange ConditionVal, SourceRange R1, SourceRange R2, bool HasFallThroughAttr)=0

void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, QualType BlockType)

AnalysisBasedWarnings(Sema &s)

Represents a simple identification of a weak object.

Retains information about a function, method, or block that is currently being parsed.

llvm::SmallDenseMap< WeakObjectProfileTy, WeakUseVector, 8, WeakObjectProfileTy::DenseMapInfo > WeakObjectUseMap

Used to collect all uses of weak objects in a function body.

bool HasFallthroughStmt

Whether there is a fallthrough statement in this function.

VarDecl * CoroutinePromise

The promise object for this coroutine, if any.

SmallVector< PossiblyUnreachableDiag, 4 > PossiblyUnreachableDiags

A list of PartialDiagnostics created but delayed within the current function scope.

const WeakObjectUseMap & getWeakObjectUses() const

Handler class for thread safety warnings.

InterProceduralData aims to be a storage of whatever data should be passed between analyses of differ...

CalledOnceInterProceduralData CalledOnceData

SmallVector< PartialDiagnosticAt, 1 > OptionalNotes

std::pair< PartialDiagnosticAt, OptionalNotes > DelayedDiag

bool LE(InterpState &S, CodePtr OpPC)

void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, Callback &CB)

unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable)

ScanReachableFromBlock - Mark all blocks reachable from Start.

UnreachableKind

Classifications of unreachable code.

LockKind getLockKindFromAccessKind(AccessKind AK)

Helper function that returns a LockKind required for the given level of access.

@ LEK_NotLockedAtEndOfFunction

@ LEK_LockedSomePredecessors

@ LEK_LockedAtEndOfFunction

@ LEK_LockedSomeLoopIterations

LockKind

This enum distinguishes between different kinds of lock actions.

void runThreadSafetyAnalysis(AnalysisDeclContext &AC, ThreadSafetyHandler &Handler, BeforeSet **Bset)

Check a function's CFG for thread-safety violations.

ProtectedOperationKind

This enum distinguishes between different kinds of operations that may need to be protected by locks.

@ POK_PtPassByRef

Passing a pt-guarded variable by reference.

@ POK_VarDereference

Dereferencing a variable (e.g. p in *p = 5;)

@ POK_PassByRef

Passing a guarded variable by reference.

@ POK_ReturnByRef

Returning a guarded variable by reference.

@ POK_VarAccess

Reading or writing a variable (e.g. x in x = 5;)

@ POK_FunctionCall

Making a function call (e.g. fool())

@ POK_PtReturnByRef

Returning a pt-guarded variable by reference.

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

bool isTemplateInstantiation(TemplateSpecializationKind Kind)

Determine whether this template specialization kind refers to an instantiation of an entity (as oppos...

void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, bool EmitSuggestions)

@ If

'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...

@ Property

The type of a property.

@ Parameter

The parameter type of a method or function.

void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)

void checkCalledOnceParameters(AnalysisDeclContext &AC, CalledOnceCheckHandler &Handler, bool CheckConventionalParameters)

Check given CFG for 'called once' parameter violations.

std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt

A partial diagnostic along with the source location where this diagnostic occurs.

EvalResult is a struct with detailed info about an evaluated expression.

unsigned NumVariablesAnalyzed