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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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

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

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

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

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

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

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

54#include "llvm/Support/Debug.h"

55#include

56#include

57#include

58#include

59

60using namespace clang;

61

62

63

64

65

66namespace {

68 Sema &S;

69 SourceRange PreviousSilenceableCondVal;

70

71 public:

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

73

75 SourceRange SilenceableCondVal, SourceRange R1,

76 SourceRange R2, bool HasFallThroughAttr) override {

77

78

79

80 if (HasFallThroughAttr &&

81 !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,

82 SourceLocation()))

83 return;

84

85

86

87 if (PreviousSilenceableCondVal.isValid() &&

88 SilenceableCondVal.isValid() &&

89 PreviousSilenceableCondVal == SilenceableCondVal)

90 return;

91 PreviousSilenceableCondVal = SilenceableCondVal;

92

93 unsigned diag = diag::warn_unreachable;

94 switch (UK) {

96 diag = diag::warn_unreachable_break;

97 break;

99 diag = diag::warn_unreachable_return;

100 break;

102 diag = diag::warn_unreachable_loop_increment;

103 break;

105 break;

106 }

107

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

109

110 SourceLocation Open = SilenceableCondVal.getBegin();

111 if (Open.isValid()) {

112 SourceLocation Close = SilenceableCondVal.getEnd();

113 Close = S.getLocForEndOfToken(Close);

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

118 }

119 }

120 }

121 };

122}

123

124

126

127

128

129

130

131

132

134 return;

135

136 UnreachableCodeHandler UC(S);

138}

139

140namespace {

141

142class LogicalErrorHandler : public CFGCallback {

143 Sema &S;

144

145public:

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

147

148 static bool HasMacroID(const Expr *E) {

150 return true;

151

152

153 for (const Stmt *SubStmt : E->children())

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

155 if (HasMacroID(SubExpr))

156 return true;

157

158 return false;

159 }

160

161 void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override {

162 if (HasMacroID(B))

163 return;

164

165 unsigned DiagID = isAlwaysTrue

166 ? diag::warn_tautological_negation_or_compare

167 : diag::warn_tautological_negation_and_compare;

169 S.Diag(B->getExprLoc(), DiagID) << DiagRange;

170 }

171

172 void compareAlwaysTrue(const BinaryOperator *B,

173 bool isAlwaysTrueOrFalse) override {

174 if (HasMacroID(B))

175 return;

176

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

179 << DiagRange << isAlwaysTrueOrFalse;

180 }

181

182 void compareBitwiseEquality(const BinaryOperator *B,

183 bool isAlwaysTrue) override {

184 if (HasMacroID(B))

185 return;

186

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

189 << DiagRange << isAlwaysTrue;

190 }

191

192 void compareBitwiseOr(const BinaryOperator *B) override {

193 if (HasMacroID(B))

194 return;

195

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

198 }

199

200 static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,

201 SourceLocation Loc) {

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

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

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

205 }

206};

207}

208

209

210

211

212

213

214

215

217

218 for (const auto &B : Block) {

220 continue;

221

225 continue;

226

227

232 if (isa_and_nonnull(NNS.getAsType()))

233 continue;

234

238 return true;

239 }

240 return false;

241}

242

243

247

248 bool foundRecursion = false;

249

251

252

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

254

255 while (!WorkList.empty()) {

257

258 for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) {

259 if (CFGBlock *SuccBlock = *I) {

260 if (!Visited.insert(SuccBlock).second)

261 continue;

262

263

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

265 return false;

266

267

269 foundRecursion = true;

270 continue;

271 }

272

273 WorkList.push_back(SuccBlock);

274 }

275 }

276 }

277 return foundRecursion;

278}

279

283

284

285

288 return;

289

291 if (!cfg) return;

292

293

295 return;

296

297

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

300}

301

302

303

304

305

306

307

309 CFG *Body) {

312

313 Stack.push_back(&ThrowBlock);

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

315

316 while (!Stack.empty()) {

317 CFGBlock &UnwindBlock = *Stack.pop_back_val();

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;

372 getAs())

376 } else

379 }

380}

381

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

405 if (auto *DRef = dyn_cast(E->IgnoreParenCasts()))

406 if (auto *FD = dyn_cast(DRef->getDecl()))

407 return FD->isNoReturn();

408 return false;

409}

410

411

412

415 if (auto *ListInit = dyn_cast(Init);

419 }

420 return false;

421}

422

423namespace {

424

425

426struct TransferFunctions : public StmtVisitor {

427 const VarDecl *Var;

428 std::optional AllValuesAreNoReturn;

429

430 TransferFunctions(const VarDecl *VD) : Var(VD) {}

431

432 void reset() { AllValuesAreNoReturn = std::nullopt; }

433

434 void VisitDeclStmt(DeclStmt *DS) {

435 for (auto *DI : DS->decls())

436 if (auto *VD = dyn_cast(DI))

437 if (VarDecl *Def = VD->getDefinition())

438 if (Def == Var)

440 }

441

442 void VisitUnaryOperator(UnaryOperator *UO) {

443 if (UO->getOpcode() == UO_AddrOf) {

444 if (auto *DRef =

446 if (DRef->getDecl() == Var)

447 AllValuesAreNoReturn = false;

448 }

449 }

450

451 void VisitBinaryOperator(BinaryOperator *BO) {

452 if (BO->getOpcode() == BO_Assign)

454 if (DRef->getDecl() == Var)

456 }

457

458 void VisitCallExpr(CallExpr *CE) {

460 ++I) {

461 const Expr *Arg = *I;

463 if (auto *DRef = dyn_cast(Arg->IgnoreParenCasts()))

464 if (auto VD = dyn_cast(DRef->getDecl()))

465 if (VD->getDefinition() == Var)

466 AllValuesAreNoReturn = false;

467 }

468 }

469};

470}

471

472

473

476

477

481 return false;

482 }

483

484

485

487 return false;

488

489

490

491

492 using MapTy = llvm::DenseMap<const CFGBlock *, std::optional>;

493 using ValueTy = MapTy::value_type;

494 MapTy BlocksToCheck;

495 BlocksToCheck[&VarBlk] = std::nullopt;

496 const auto BlockSatisfiesCondition = [](ValueTy Item) {

497 return Item.getSecond().value_or(false);

498 };

499

500 TransferFunctions TF(VD);

502 llvm::DenseSet<const CFGBlock *> Visited;

505 if (Visited.contains(B))

506 continue;

507 Visited.insert(B);

508

510 ri != re; ++ri) {

511 if (std::optional cs = ri->getAs<CFGStmt>()) {

512 const Stmt *S = cs->getStmt();

513 TF.reset();

514 TF.Visit(const_cast<Stmt *>(S));

515 if (TF.AllValuesAreNoReturn) {

516 if (!TF.AllValuesAreNoReturn.value())

517 return false;

518 BlocksToCheck[B] = true;

519 break;

520 }

521 }

522 }

523

524

525 if (llvm::all_of(BlocksToCheck, BlockSatisfiesCondition))

526 return true;

527

528

529

530 if (!BlocksToCheck[B]) {

532 BlocksToCheck.erase(B);

533 for (const auto &PredBlk : B->preds())

534 if (!BlocksToCheck.contains(PredBlk))

535 BlocksToCheck[PredBlk] = std::nullopt;

536 }

537 }

538

539 return false;

540}

541

542

543

544

545

553

554

555

556

557

558

559

560

561

562

566

567

568

571 live);

572

575

576

577

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

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

580 if (B->preds().empty()) {

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

582 if (isa_and_nonnull(Term))

583

584

586 continue;

587 }

588 }

589 }

590

591

592

593

594 bool HasLiveReturn = false;

595 bool HasFakeEdge = false;

596 bool HasPlainEdge = false;

597 bool HasAbnormalEdge = false;

598

599

600

603

609 continue;

610

611

612

613

615 HasAbnormalEdge = true;

616 continue;

617 }

618

619

620

621

623

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

626 break;

627

628

629 if (ri == re) {

632 HasAbnormalEdge = true;

633 continue;

634 }

635

636 HasPlainEdge = true;

637 continue;

638 }

639

643 HasLiveReturn = true;

644 continue;

645 }

647 HasFakeEdge = true;

648 continue;

649 }

651 HasFakeEdge = true;

652 continue;

653 }

655

656 HasFakeEdge = true;

657 HasLiveReturn = true;

658 continue;

659 }

661 HasAbnormalEdge = true;

662 continue;

663 }

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

665 HasAbnormalEdge = true;

666 continue;

667 }

668 if (auto *Call = dyn_cast(S)) {

669 const Expr *Callee = Call->getCallee();

670 if (Callee->getType()->isPointerType())

671 if (auto *DeclRef =

672 dyn_cast(Callee->IgnoreParenImpCasts()))

673 if (auto *VD = dyn_cast(DeclRef->getDecl()))

675 HasAbnormalEdge = true;

676 continue;

677 }

678 }

679

680 HasPlainEdge = true;

681 }

682 if (!HasPlainEdge) {

683 if (HasLiveReturn)

686 }

687 if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)

689

690

691

693}

694

695namespace {

696

697struct CheckFallThroughDiagnostics {

698 unsigned diag_FallThrough_HasNoReturn = 0;

699 unsigned diag_FallThrough_ReturnsNonVoid = 0;

700 unsigned diag_NeverFallThroughOrReturn = 0;

701 unsigned FunKind;

702 SourceLocation FuncLoc;

703

704 static CheckFallThroughDiagnostics MakeForFunction(Sema &S,

705 const Decl *Func) {

706 CheckFallThroughDiagnostics D;

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

708 D.diag_FallThrough_HasNoReturn = diag::warn_noreturn_has_return_expr;

709 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;

710

711

712

713 bool isVirtualMethod = false;

714 if (const CXXMethodDecl *Method = dyn_cast(Func))

715 isVirtualMethod = Method->isVirtual();

716

717

719 if (const FunctionDecl *Function = dyn_cast(Func)) {

723 D.diag_FallThrough_ReturnsNonVoid = diag::ext_main_no_return;

724 }

725 }

726

728 D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function;

729

730 D.FunKind = diag::FalloffFunctionKind::Function;

731 return D;

732 }

733

734 static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) {

735 CheckFallThroughDiagnostics D;

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

737 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;

738 D.FunKind = diag::FalloffFunctionKind::Coroutine;

739 return D;

740 }

741

742 static CheckFallThroughDiagnostics MakeForBlock() {

743 CheckFallThroughDiagnostics D;

744 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;

745 D.diag_FallThrough_ReturnsNonVoid = diag::err_falloff_nonvoid;

746 D.FunKind = diag::FalloffFunctionKind::Block;

747 return D;

748 }

749

750 static CheckFallThroughDiagnostics MakeForLambda() {

751 CheckFallThroughDiagnostics D;

752 D.diag_FallThrough_HasNoReturn = diag::err_noreturn_has_return_expr;

753 D.diag_FallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid;

754 D.FunKind = diag::FalloffFunctionKind::Lambda;

755 return D;

756 }

757

758 bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid,

759 bool HasNoReturn) const {

760 if (FunKind == diag::FalloffFunctionKind::Function) {

761 return (ReturnsVoid ||

762 D.isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&

763 (!HasNoReturn ||

764 D.isIgnored(diag::warn_noreturn_has_return_expr, FuncLoc)) &&

765 (!ReturnsVoid ||

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

767 }

768 if (FunKind == diag::FalloffFunctionKind::Coroutine) {

769 return (ReturnsVoid ||

770 D.isIgnored(diag::warn_falloff_nonvoid, FuncLoc)) &&

771 (!HasNoReturn);

772 }

773

774 return ReturnsVoid && !HasNoReturn;

775 }

776};

777

778}

779

780

781

782

783

786 const CheckFallThroughDiagnostics &CD,

788

789 bool ReturnsVoid = false;

790 bool HasNoReturn = false;

791

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

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

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

795 else

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

797 HasNoReturn = FD->isNoReturn() || FD->hasAttr();

798 }

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

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

801 HasNoReturn = MD->hasAttr();

802 }

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

807 ReturnsVoid = true;

808 if (FT->getNoReturnAttr())

809 HasNoReturn = true;

810 }

811 }

812

814

815

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

817 return;

819

820

822 return;

823

824

827 break;

828

831 if (HasNoReturn) {

832 if (CD.diag_FallThrough_HasNoReturn)

833 S.Diag(RBrace, CD.diag_FallThrough_HasNoReturn) << CD.FunKind;

834 } else if (!ReturnsVoid && CD.diag_FallThrough_ReturnsNonVoid) {

835

836

838 if (const auto *CS = dyn_cast(Body);

839 CS && !CS->body_empty()) {

840 const Stmt *LastStmt = CS->body_back();

841

842 if (const auto *EWC = dyn_cast(LastStmt)) {

843 LastStmt = EWC->getSubExpr();

844 }

845 if (const auto *CE = dyn_cast(LastStmt)) {

847 Callee && Callee->hasAttr()) {

848 return;

849 }

850 }

851

853 return;

854 }

855 }

856 }

857 bool NotInAllControlPaths = FallThroughType == MaybeFallThrough;

858 S.Diag(RBrace, CD.diag_FallThrough_ReturnsNonVoid)

859 << CD.FunKind << NotInAllControlPaths;

860 }

861 break;

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

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

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

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

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

868 } else {

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

870 }

871 }

872 break;

874 break;

875 }

876}

877

878

879

880

881

882namespace {

883

884

885

887 bool FoundReference;

888 const DeclRefExpr *Needle;

889

890public:

891 typedef ConstEvaluatedExprVisitor Inherited;

892

893 ContainsReference(ASTContext &Context, const DeclRefExpr *Needle)

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

895

896 void VisitExpr(const Expr *E) {

897

898 if (FoundReference)

899 return;

900

901 Inherited::VisitExpr(E);

902 }

903

904 void VisitDeclRefExpr(const DeclRefExpr *E) {

905 if (E == Needle)

906 FoundReference = true;

907 else

909 }

910

911 bool doesContainReference() const { return FoundReference; }

912};

913}

914

918 !VD->hasAttr()) {

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

922 return true;

923 }

924

925

927 return false;

928

929

931 return false;

932

934

935

937 if (Init.empty())

938 return false;

939

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

942 return true;

943}

944

945

946

948 const Stmt *Else, bool CondVal,

950 if (CondVal) {

951

954 if (Else) {

956 Fixit2 =

958 }

959 } else {

960

961 if (Else)

964 else

966 }

967}

968

969

970

972 bool IsCapturedByBlock) {

973 bool Diagnosed = false;

974

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

980 return;

981

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

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

990 return;

991

994

995

996 break;

997 }

998

999

1001 I != E; ++I) {

1003

1005 const Stmt *Term = I->Terminator;

1006

1007

1008 unsigned DiagKind;

1009 StringRef Str;

1011

1012

1013

1014

1015 int RemoveDiagKind = -1;

1016 const char *FixitStr =

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

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

1020

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

1022 default:

1023

1024

1025 continue;

1026

1027

1028 case Stmt::IfStmtClass: {

1030 DiagKind = 0;

1031 Str = "if";

1033 RemoveDiagKind = 0;

1035 I->Output, Fixit1, Fixit2);

1036 break;

1037 }

1038 case Stmt::ConditionalOperatorClass: {

1040 DiagKind = 0;

1041 Str = "?:";

1043 RemoveDiagKind = 0;

1045 I->Output, Fixit1, Fixit2);

1046 break;

1047 }

1048 case Stmt::BinaryOperatorClass: {

1051 continue;

1052 DiagKind = 0;

1055 RemoveDiagKind = 0;

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

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

1058

1061 else

1062

1064 break;

1065 }

1066

1067

1068 case Stmt::WhileStmtClass:

1069 DiagKind = 1;

1070 Str = "while";

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

1072 RemoveDiagKind = 1;

1074 break;

1075 case Stmt::ForStmtClass:

1076 DiagKind = 1;

1077 Str = "for";

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

1079 RemoveDiagKind = 1;

1080 if (I->Output)

1082 else

1084 break;

1085 case Stmt::CXXForRangeStmtClass:

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

1087

1088

1089

1090 continue;

1091 }

1092 DiagKind = 1;

1093 Str = "for";

1095 break;

1096

1097

1098 case Stmt::DoStmtClass:

1099 DiagKind = 2;

1100 Str = "do";

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

1102 RemoveDiagKind = 1;

1104 break;

1105

1106

1107 case Stmt::CaseStmtClass:

1108 DiagKind = 3;

1109 Str = "case";

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

1111 break;

1112 case Stmt::DefaultStmtClass:

1113 DiagKind = 3;

1114 Str = "default";

1116 break;

1117 }

1118

1119 S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)

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

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

1124 if (RemoveDiagKind != -1)

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

1127

1128 Diagnosed = true;

1129 }

1130

1131 if (!Diagnosed)

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

1135}

1136

1137

1144

1145

1152

1153

1154

1155

1156

1157

1160 bool alwaysReportSelfInit = false) {

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

1162

1163

1164

1165

1166

1167

1168

1169

1170

1171

1172

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

1175 return false;

1176

1177 ContainsReference CR(S.Context, DRE);

1179 if (CR.doesContainReference()) {

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

1183 }

1184 }

1185

1187 } else {

1191 diag::warn_uninit_byref_blockvar_captured_by_block)

1194 else

1196 }

1197

1198

1199

1200

1204

1206}

1207

1208namespace {

1210public:

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

1212 ShouldWalkTypesOfTypeLocs = false;

1213 }

1214

1215 bool foundSwitchStatements() const { return FoundSwitchStatements; }

1216

1217 void markFallthroughVisited(const AttributedStmt *Stmt) {

1218 bool Found = FallthroughStmts.erase(Stmt);

1221 }

1222

1223 typedef llvm::SmallPtrSet<const AttributedStmt *, 8> AttrStmts;

1224

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

1226

1227 void fillReachableBlocks(CFG *Cfg) {

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

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

1230

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

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

1233

1234

1235

1236

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

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

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

1240 BlockQueue.push_back(B);

1241 }

1242

1243 while (!BlockQueue.empty()) {

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

1245 BlockQueue.pop_front();

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

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

1248 BlockQueue.push_back(B);

1249 }

1250 }

1251 }

1252

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

1254 bool IsTemplateInstantiation) {

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

1256

1257 int UnannotatedCnt = 0;

1258 AnnotatedCnt = 0;

1259

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

1261 while (!BlockQueue.empty()) {

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

1263 BlockQueue.pop_front();

1264 if (!P)

1265 continue;

1266

1268 if (isa_and_nonnull(Term))

1269 continue;

1270

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

1273 continue;

1274

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

1277 continue;

1278

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

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

1281 if (std::optional CS = Elem.getAs()) {

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

1283

1284

1285

1286 if (!IsTemplateInstantiation)

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

1288 diag::warn_unreachable_fallthrough_attr);

1289 markFallthroughVisited(AS);

1290 ++AnnotatedCnt;

1291 break;

1292 }

1293

1294 }

1295 }

1296

1297

1298

1299

1300

1301

1302

1303

1304 continue;

1305 }

1306

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

1309 markFallthroughVisited(AS);

1310 ++AnnotatedCnt;

1311 continue;

1312 }

1313

1314 if (!LastStmt) {

1315

1317 std::back_inserter(BlockQueue));

1318 continue;

1319 }

1320

1321 ++UnannotatedCnt;

1322 }

1323 return !!UnannotatedCnt;

1324 }

1325

1326 bool VisitAttributedStmt(AttributedStmt *S) override {

1327 if (asFallThroughAttr(S))

1328 FallthroughStmts.insert(S);

1329 return true;

1330 }

1331

1332 bool VisitSwitchStmt(SwitchStmt *S) override {

1333 FoundSwitchStatements = true;

1334 return true;

1335 }

1336

1337

1338

1339 bool TraverseDecl(Decl *D) override { return true; }

1340

1341

1342 bool TraverseLambdaExpr(LambdaExpr *LE) override {

1343

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

1345 TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));

1346 return true;

1347 }

1348

1349 private:

1350

1351 static const AttributedStmt *asFallThroughAttr(const Stmt *S) {

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

1354 return AS;

1355 }

1356 return nullptr;

1357 }

1358

1359 static const Stmt *getLastStmt(const CFGBlock &B) {

1361 return Term;

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

1363 if (std::optional CS = Elem.getAs())

1364 return CS->getStmt();

1365

1366

1367

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

1371

1372 return nullptr;

1373 }

1374

1375 bool FoundSwitchStatements;

1376 AttrStmts FallthroughStmts;

1377 Sema &S;

1378 llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;

1379};

1380}

1381

1385 tok::l_square, tok::l_square,

1387 tok::r_square, tok::r_square

1388 };

1389

1390 TokenValue ClangFallthroughTokens[] = {

1393 tok::r_square, tok::r_square

1394 };

1395

1397

1398 StringRef MacroName;

1399 if (PreferClangAttr)

1401 if (MacroName.empty())

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

1405 if (MacroName.empty()) {

1406 if (!PreferClangAttr)

1407 MacroName = "[[fallthrough]]";

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

1410 else

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

1412 }

1413 return MacroName;

1414}

1415

1417 bool PerFunction) {

1418 FallthroughMapper FM(S);

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

1420

1421 if (!FM.foundSwitchStatements())

1422 return;

1423

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

1425 return;

1426

1428

1429 if (!Cfg)

1430 return;

1431

1432 FM.fillReachableBlocks(Cfg);

1433

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

1436

1437 if (!isa_and_nonnull(Label))

1438 continue;

1439

1440 int AnnotatedCnt;

1441

1442 bool IsTemplateInstantiation = false;

1443 if (const FunctionDecl *Function = dyn_cast(AC.getDecl()))

1444 IsTemplateInstantiation = Function->isTemplateInstantiation();

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

1446 IsTemplateInstantiation))

1447 continue;

1448

1450 PerFunction ? diag::warn_unannotated_fallthrough_per_function

1451 : diag::warn_unannotated_fallthrough);

1452

1453 if (!AnnotatedCnt) {

1456 continue;

1457

1459

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

1463 }

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

1468 TextToInsert += "; ";

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

1470 << AnnotationSpelling

1472 }

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

1475 }

1476 }

1477

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

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

1480}

1481

1483 const Stmt *S) {

1484 assert(S);

1485

1486 do {

1488 case Stmt::ForStmtClass:

1489 case Stmt::WhileStmtClass:

1490 case Stmt::CXXForRangeStmtClass:

1491 case Stmt::ObjCForCollectionStmtClass:

1492 return true;

1493 case Stmt::DoStmtClass: {

1496 return true;

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

1498 }

1499 default:

1500 break;

1501 }

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

1503

1504 return false;

1505}

1506

1509 const Decl *D,

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

1515 StmtUsesPair;

1516

1518

1520

1521

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

1524 I != E; ++I) {

1525 const WeakUseVector &Uses = I->second;

1526

1527

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

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

1530 if (UI->isUnsafe())

1531 break;

1532 }

1533

1534

1535 if (UI == UE)

1536 continue;

1537

1538

1539

1540

1541

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

1543 WeakUseVector::const_iterator UI2 = UI;

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

1545 if (UI2->isUnsafe())

1546 break;

1547

1548 if (UI2 == UE) {

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

1550 continue;

1551

1552 const WeakObjectProfileTy &Profile = I->first;

1553 if (!Profile.isExactProfile())

1554 continue;

1555

1558 Base = Profile.getProperty();

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

1560

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

1563 continue;

1564 }

1565 }

1566

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

1568 }

1569

1570 if (UsesByStmt.empty())

1571 return;

1572

1573

1575 llvm::sort(UsesByStmt,

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

1577 return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(),

1578 RHS.first->getBeginLoc());

1579 });

1580

1581

1582

1583

1584

1585

1586 enum {

1587 Function,

1588 Method,

1590 Lambda

1591 } FunctionKind;

1592

1594 FunctionKind = Block;

1596 FunctionKind = Lambda;

1598 FunctionKind = Method;

1599 else

1600 FunctionKind = Function;

1601

1602

1603 for (const auto &P : UsesByStmt) {

1604 const Stmt *FirstRead = P.first;

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

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

1607

1608

1609

1610

1611

1612

1613 unsigned DiagKind;

1614 if (Key.isExactProfile())

1615 DiagKind = diag::warn_arc_repeated_use_of_weak;

1616 else

1617 DiagKind = diag::warn_arc_possible_repeated_use_of_weak;

1618

1619

1620

1621

1622 enum {

1623 Variable,

1624 Property,

1625 ImplicitProperty,

1626 Ivar

1627 } ObjectKind;

1628

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

1631 ObjectKind = Variable;

1633 ObjectKind = Property;

1635 ObjectKind = ImplicitProperty;

1637 ObjectKind = Ivar;

1638 else

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

1640

1641

1642

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

1644 if (Prop->hasAttr())

1645 continue;

1646

1647

1649 << int(ObjectKind) << KeyProp << int(FunctionKind)

1651

1652

1653 for (const auto &Use : Uses) {

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

1655 continue;

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

1657 diag::note_arc_weak_also_accessed_here)

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

1659 }

1660 }

1661}

1662

1663namespace clang {

1664namespace {

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

1667typedef std::list DiagList;

1668

1669struct SortDiagBySourceLocation {

1670 SourceManager &SM;

1671 SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}

1672

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

1674

1675

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

1677 }

1678};

1679}

1680}

1681

1682namespace {

1684 Sema &S;

1685 typedef SmallVector<UninitUse, 2> UsesVec;

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

1687

1688

1689

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

1691 UsesMap uses;

1692

1693public:

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

1696

1697 MappedType &getUses(const VarDecl *vd) {

1698 MappedType &V = uses[vd];

1699 if (V.getPointer())

1700 V.setPointer(new UsesVec());

1701 return V;

1702 }

1703

1704 void handleUseOfUninitVariable(const VarDecl *vd,

1705 const UninitUse &use) override {

1706 getUses(vd).getPointer()->push_back(use);

1707 }

1708

1709 void handleSelfInit(const VarDecl *vd) override { getUses(vd).setInt(true); }

1710

1712 for (const auto &P : uses) {

1713 const VarDecl *vd = P.first;

1714 const MappedType &V = P.second;

1715

1716 UsesVec *vec = V.getPointer();

1717 bool hasSelfInit = V.getInt();

1718

1719 diagnoseUnitializedVar(vd, hasSelfInit, vec);

1720

1721

1722 delete vec;

1723 }

1724

1725 uses.clear();

1726 }

1727

1728private:

1729 static bool hasAlwaysUninitializedUse(const UsesVec* vec) {

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

1734 });

1735 }

1736

1737

1738

1739

1740 void diagnoseUnitializedVar(const VarDecl *vd, bool hasSelfInit,

1741 UsesVec *vec) {

1742

1743

1744

1745 if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {

1748 true),

1749 true))

1750 return;

1751 }

1752

1753

1754

1755

1756 llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {

1757

1758

1760 return b.isConstRefOrPtrUse();

1761

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

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

1765 });

1766

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

1770 return;

1773 return;

1774 } else {

1775

1776 UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;

1778 return;

1779 }

1780 }

1781 }

1782};

1783

1784

1785class CalledOnceInterProceduralData {

1786public:

1787

1788 void addDelayedWarning(const BlockDecl *Block,

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

1791 }

1792

1793 void flushWarnings(const BlockDecl *Block, Sema &S) {

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

1796

1797 discardWarnings(Block);

1798 }

1799

1800 void discardWarnings(const BlockDecl *Block) {

1801 DelayedBlockWarnings.erase(Block);

1802 }

1803

1804private:

1805 using DelayedDiagnostics = SmallVector<PartialDiagnosticAt, 2>;

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

1807};

1808

1810public:

1811 CalledOnceCheckReporter(Sema &S, CalledOnceInterProceduralData &Data)

1812 : S(S), Data(Data) {}

1813 void handleDoubleCall(const ParmVarDecl *Parameter, const Expr *Call,

1814 const Expr *PrevCall, bool IsCompletionHandler,

1815 bool Poised) override {

1816 auto DiagToReport = IsCompletionHandler

1817 ? diag::warn_completion_handler_called_twice

1818 : diag::warn_called_once_gets_called_twice;

1819 S.Diag(Call->getBeginLoc(), DiagToReport) << Parameter;

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

1821 << Poised;

1822 }

1823

1824 void handleNeverCalled(const ParmVarDecl *Parameter,

1825 bool IsCompletionHandler) override {

1826 auto DiagToReport = IsCompletionHandler

1827 ? diag::warn_completion_handler_never_called

1828 : diag::warn_called_once_never_called;

1829 S.Diag(Parameter->getBeginLoc(), DiagToReport)

1830 << Parameter << false;

1831 }

1832

1833 void handleNeverCalled(const ParmVarDecl *Parameter, const Decl *Function,

1835 bool IsCalledDirectly,

1836 bool IsCompletionHandler) override {

1837 auto DiagToReport = IsCompletionHandler

1838 ? diag::warn_completion_handler_never_called_when

1839 : diag::warn_called_once_never_called_when;

1842 << IsCalledDirectly

1843 << (unsigned)Reason);

1844

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

1846

1847 Data.addDelayedWarning(Block, std::move(Warning));

1848 } else {

1850 }

1851 }

1852

1853 void handleCapturedNeverCalled(const ParmVarDecl *Parameter,

1854 const Decl *Where,

1855 bool IsCompletionHandler) override {

1856 auto DiagToReport = IsCompletionHandler

1857 ? diag::warn_completion_handler_never_called

1858 : diag::warn_called_once_never_called;

1859 S.Diag(Where->getBeginLoc(), DiagToReport)

1860 << Parameter << true;

1861 }

1862

1863 void

1864 handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl *Block) override {

1865 Data.flushWarnings(Block, S);

1866 }

1867

1868 void handleBlockWithNoGuarantees(const BlockDecl *Block) override {

1869 Data.discardWarnings(Block);

1870 }

1871

1872private:

1873 Sema &S;

1874 CalledOnceInterProceduralData &Data;

1875};

1876

1877constexpr unsigned CalledOnceWarnings[] = {

1878 diag::warn_called_once_never_called,

1879 diag::warn_called_once_never_called_when,

1880 diag::warn_called_once_gets_called_twice};

1881

1882constexpr unsigned CompletionHandlerWarnings[]{

1883 diag::warn_completion_handler_never_called,

1884 diag::warn_completion_handler_never_called_when,

1885 diag::warn_completion_handler_called_twice};

1886

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

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

1892 });

1893}

1894

1895bool shouldAnalyzeCalledOnceConventions(const DiagnosticsEngine &Diags,

1897 return shouldAnalyzeCalledOnceImpl(CompletionHandlerWarnings, Diags, At);

1898}

1899

1900bool shouldAnalyzeCalledOnceParameters(const DiagnosticsEngine &Diags,

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

1903 shouldAnalyzeCalledOnceConventions(Diags, At);

1904}

1905}

1906

1907

1908

1909

1910namespace clang {

1912namespace {

1913class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {

1914 Sema &S;

1916 SourceLocation FunLocation, FunEndLocation;

1917

1918 const FunctionDecl *CurrentFunction;

1919 bool Verbose;

1920

1922 if (Verbose && CurrentFunction) {

1924 S.PDiag(diag::note_thread_warning_in_fun)

1925 << CurrentFunction);

1927 }

1929 }

1930

1933 if (Verbose && CurrentFunction) {

1935 S.PDiag(diag::note_thread_warning_in_fun)

1936 << CurrentFunction);

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

1938 }

1939 return ONS;

1940 }

1941

1945 ONS.push_back(Note1);

1946 ONS.push_back(Note2);

1947 if (Verbose && CurrentFunction) {

1949 S.PDiag(diag::note_thread_warning_in_fun)

1950 << CurrentFunction);

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

1952 }

1953 return ONS;

1954 }

1955

1956 OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {

1957 return LocLocked.isValid()

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

1960 : getNotes();

1961 }

1962

1963 OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,

1964 StringRef Kind) {

1965 return LocUnlocked.isValid()

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

1968 : getNotes();

1969 }

1970

1971 OptionalNotes makeManagedMismatchNoteForParam(SourceLocation DeclLoc) {

1972 return DeclLoc.isValid()

1974 DeclLoc,

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

1976 : getNotes();

1977 }

1978

1979 public:

1980 ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)

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

1983

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

1985

1986

1987

1988

1989

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

1992 for (const auto &Diag : Warnings) {

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

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

1995 S.Diag(Note.first, Note.second);

1996 }

1997 }

1998

1999 void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, SourceLocation DLoc,

2000 Name scopeName, StringRef Kind,

2001 Name expected, Name actual) override {

2003 S.PDiag(diag::warn_unmatched_underlying_mutexes)

2004 << Kind << scopeName << expected << actual);

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

2006 makeManagedMismatchNoteForParam(DLoc));

2007 }

2008

2009 void handleExpectMoreUnderlyingMutexes(SourceLocation Loc,

2010 SourceLocation DLoc, Name scopeName,

2011 StringRef Kind,

2012 Name expected) override {

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

2015 << Kind << scopeName << expected);

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

2017 makeManagedMismatchNoteForParam(DLoc));

2018 }

2019

2020 void handleExpectFewerUnderlyingMutexes(SourceLocation Loc,

2021 SourceLocation DLoc, Name scopeName,

2022 StringRef Kind,

2023 Name actual) override {

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

2026 << Kind << scopeName << actual);

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

2028 makeManagedMismatchNoteForParam(DLoc));

2029 }

2030

2031 void handleInvalidLockExp(SourceLocation Loc) override {

2033 << Loc);

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

2035 }

2036

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

2038 SourceLocation LocPreviousUnlock) override {

2040 Loc = FunLocation;

2042 << Kind << LockName);

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

2044 makeUnlockedHereNote(LocPreviousUnlock, Kind));

2045 }

2046

2047 void handleIncorrectUnlockKind(StringRef Kind, Name LockName,

2049 SourceLocation LocLocked,

2050 SourceLocation LocUnlock) override {

2052 LocUnlock = FunLocation;

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

2055 << Kind << LockName << Received << Expected);

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

2057 makeLockedHereNote(LocLocked, Kind));

2058 }

2059

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

2061 SourceLocation LocDoubleLock) override {

2063 LocDoubleLock = FunLocation;

2065 << Kind << LockName);

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

2067 makeLockedHereNote(LocLocked, Kind));

2068 }

2069

2070 void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,

2071 SourceLocation LocLocked,

2072 SourceLocation LocEndOfScope,

2074 bool ReentrancyMismatch) override {

2075 unsigned DiagID = 0;

2076 switch (LEK) {

2078 DiagID = diag::warn_lock_some_predecessors;

2079 break;

2081 DiagID = diag::warn_expecting_lock_held_on_loop;

2082 break;

2084 DiagID = diag::warn_no_unlock;

2085 break;

2087 DiagID = diag::warn_expecting_locked;

2088 break;

2089 }

2091 LocEndOfScope = FunEndLocation;

2092

2094 << Kind << LockName

2095 << ReentrancyMismatch);

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

2097 makeLockedHereNote(LocLocked, Kind));

2098 }

2099

2100 void handleExclusiveAndShared(StringRef Kind, Name LockName,

2101 SourceLocation Loc1,

2102 SourceLocation Loc2) override {

2104 S.PDiag(diag::warn_lock_exclusive_and_shared)

2105 << Kind << LockName);

2107 << Kind << LockName);

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

2109 }

2110

2112 AccessKind AK, SourceLocation Loc) override {

2113 unsigned DiagID = 0;

2114 switch (POK) {

2120 DiagID = diag::warn_variable_requires_any_lock;

2121 break;

2127 DiagID = diag::warn_var_deref_requires_any_lock;

2128 break;

2130 llvm_unreachable("Only works for variables");

2131 break;

2132 }

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

2136 }

2137

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

2140 LockKind LK, SourceLocation Loc,

2141 Name *PossibleMatch) override {

2142 unsigned DiagID = 0;

2143 if (PossibleMatch) {

2144 switch (POK) {

2146 DiagID = diag::warn_variable_requires_lock_precise;

2147 break;

2149 DiagID = diag::warn_var_deref_requires_lock_precise;

2150 break;

2152 DiagID = diag::warn_fun_requires_lock_precise;

2153 break;

2155 DiagID = diag::warn_guarded_pass_by_reference;

2156 break;

2158 DiagID = diag::warn_pt_guarded_pass_by_reference;

2159 break;

2161 DiagID = diag::warn_guarded_return_by_reference;

2162 break;

2164 DiagID = diag::warn_pt_guarded_return_by_reference;

2165 break;

2167 DiagID = diag::warn_guarded_pass_pointer;

2168 break;

2170 DiagID = diag::warn_pt_guarded_pass_pointer;

2171 break;

2173 DiagID = diag::warn_guarded_return_pointer;

2174 break;

2176 DiagID = diag::warn_pt_guarded_return_pointer;

2177 break;

2178 }

2180 << D

2181 << LockName << LK);

2183 << *PossibleMatch);

2186 S.PDiag(diag::note_guarded_by_declared_here)

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

2189 } else

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

2191 } else {

2192 switch (POK) {

2194 DiagID = diag::warn_variable_requires_lock;

2195 break;

2197 DiagID = diag::warn_var_deref_requires_lock;

2198 break;

2200 DiagID = diag::warn_fun_requires_lock;

2201 break;

2203 DiagID = diag::warn_guarded_pass_by_reference;

2204 break;

2206 DiagID = diag::warn_pt_guarded_pass_by_reference;

2207 break;

2209 DiagID = diag::warn_guarded_return_by_reference;

2210 break;

2212 DiagID = diag::warn_pt_guarded_return_by_reference;

2213 break;

2215 DiagID = diag::warn_guarded_pass_pointer;

2216 break;

2218 DiagID = diag::warn_pt_guarded_pass_pointer;

2219 break;

2221 DiagID = diag::warn_guarded_return_pointer;

2222 break;

2224 DiagID = diag::warn_pt_guarded_return_pointer;

2225 break;

2226 }

2228 << D

2229 << LockName << LK);

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

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

2234 } else

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

2236 }

2237 }

2238

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

2240 SourceLocation Loc) override {

2242 S.PDiag(diag::warn_acquire_requires_negative_cap)

2243 << Kind << LockName << Neg);

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

2245 }

2246

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

2248 SourceLocation Loc) override {

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

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

2252 }

2253

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

2255 SourceLocation Loc) override {

2257 << Kind << FunName << LockName);

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

2259 }

2260

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

2262 SourceLocation Loc) override {

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

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

2266 }

2267

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

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

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

2272 }

2273

2274 void enterFunction(const FunctionDecl* FD) override {

2275 CurrentFunction = FD;

2276 }

2277

2278 void leaveFunction(const FunctionDecl* FD) override {

2279 CurrentFunction = nullptr;

2280 }

2281};

2282}

2283}

2284}

2285

2286

2287

2288

2289

2290namespace clang {

2292namespace {

2294

2295 Sema &S;

2297

2298public:

2299

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

2301

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

2304 for (const auto &Diag : Warnings) {

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

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

2307 S.Diag(Note.first, Note.second);

2308 }

2309 }

2310

2311 void warnLoopStateMismatch(SourceLocation Loc,

2312 StringRef VariableName) override {

2314 VariableName);

2315

2317 }

2318

2319 void warnParamReturnTypestateMismatch(SourceLocation Loc,

2320 StringRef VariableName,

2321 StringRef ExpectedState,

2322 StringRef ObservedState) override {

2323

2325 diag::warn_param_return_typestate_mismatch) << VariableName <<

2326 ExpectedState << ObservedState);

2327

2329 }

2330

2331 void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,

2332 StringRef ObservedState) override {

2333

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

2336

2338 }

2339

2340 void warnReturnTypestateForUnconsumableType(SourceLocation Loc,

2341 StringRef TypeName) override {

2343 diag::warn_return_typestate_for_unconsumable_type) << TypeName);

2344

2346 }

2347

2348 void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,

2349 StringRef ObservedState) override {

2350

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

2353

2355 }

2356

2357 void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,

2358 SourceLocation Loc) override {

2359

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

2362

2364 }

2365

2366 void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,

2367 StringRef State, SourceLocation Loc) override {

2368

2370 MethodName << VariableName << State);

2371

2373 }

2374};

2375}

2376}

2377}

2378

2379

2380

2381

2382

2383namespace {

2385 Sema &S;

2386 bool SuggestSuggestions;

2387

2388

2389

2390 std::string listVariableGroupAsString(

2391 const VarDecl *VD, const ArrayRef<const VarDecl *> &VarGroupForVD) const {

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

2393 return "";

2394

2395 std::vector VarNames;

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

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

2398 };

2399

2400 for (auto *V : VarGroupForVD) {

2401 if (V == VD)

2402 continue;

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

2404 }

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

2406 return PutInQuotes(VarNames[0]);

2407 }

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

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

2410 }

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

2412 const unsigned N = VarNames.size() -

2413 2;

2414 std::string AllVars = "";

2415

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

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

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

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

2420 return AllVars;

2421 }

2422

2423public:

2424 UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions)

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

2426

2427 void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl,

2428 ASTContext &Ctx) override {

2429 SourceLocation Loc;

2430 SourceRange Range;

2431 unsigned MsgParam = 0;

2432 NamedDecl *D = nullptr;

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

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

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

2436 MsgParam = 2;

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

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

2440 Op == BO_SubAssign) {

2444 } else {

2447 }

2448 MsgParam = 1;

2449 }

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

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

2453 Op == UO_PostDec) {

2456 MsgParam = 1;

2457 }

2458 } else {

2460

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

2462 MsgParam = 3;

2464

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

2467 D = ME->getMemberDecl();

2468 MsgParam = 5;

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

2470 QualType destType = ECE->getType();

2471 bool destTypeComplete = true;

2472

2474 return;

2476 if (const auto *D = destType->getAsTagDecl())

2477 destTypeComplete = D->isCompleteDefinition();

2478

2479

2480

2481 if (destTypeComplete) {

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

2484

2486

2489

2490 if (sSize >= dSize)

2491 return;

2492 }

2493 if (const auto *CE = dyn_cast(

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

2495 D = CE->getMethodDecl();

2496 }

2497

2498 if (!D)

2499 return;

2500

2501 MsgParam = 4;

2502 }

2505 }

2506 if (IsRelatedToDecl) {

2507 assert(!SuggestSuggestions &&

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

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

2510 } else {

2511 if (D) {

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

2513 << MsgParam << D << Range;

2514 } else {

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

2516 }

2517 if (SuggestSuggestions) {

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

2519 }

2520 }

2521 }

2522

2523 void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo,

2524 ASTContext &Ctx,

2525 const Expr *UnsafeArg = nullptr) override {

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

2527 << Call->getDirectCallee()

2529 if (PrintfInfo > 0) {

2530 SourceRange R =

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

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

2533 << PrintfInfo << R;

2534 }

2535 }

2536

2537 void handleUnsafeOperationInContainer(const Stmt *Operation,

2538 bool IsRelatedToDecl,

2539 ASTContext &Ctx) override {

2540 SourceLocation Loc;

2541 SourceRange Range;

2542 unsigned MsgParam = 0;

2543

2544

2545

2547 Loc = CtorExpr->getLocation();

2548

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

2550 if (IsRelatedToDecl) {

2551 assert(!SuggestSuggestions &&

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

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

2554 }

2555 }

2556

2557 void handleUnsafeVariableGroup(const VarDecl *Variable,

2558 const VariableGroupsManager &VarGrpMgr,

2559 FixItList &&Fixes, const Decl *D,

2560 const FixitStrategy &VarTargetTypes) override {

2561 assert(!SuggestSuggestions &&

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

2563 S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable)

2564 << Variable << (Variable->getType()->isPointerType() ? 0 : 1)

2565 << Variable->getSourceRange();

2566 if (!Fixes.empty()) {

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

2570 bool BriefMsg = false;

2571

2572

2573

2574 const auto VarGroupForVD = VarGrpMgr.getGroupOfVar(Variable, &BriefMsg);

2575 unsigned FixItStrategy = 0;

2576 switch (VarTargetTypes.lookup(Variable)) {

2578 FixItStrategy = 0;

2579 break;

2581 FixItStrategy = 1;

2582 break;

2583 default:

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

2585 };

2586

2587 const auto &FD =

2588 S.Diag(Variable->getLocation(),

2589 BriefMsg ? diag::note_unsafe_buffer_variable_fixit_together

2590 : diag::note_unsafe_buffer_variable_fixit_group);

2591

2592 FD << Variable << FixItStrategy;

2593 FD << listVariableGroupAsString(Variable, VarGroupForVD)

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

2595 for (const auto &F : Fixes) {

2596 FD << F;

2597 }

2598 }

2599

2600#ifndef NDEBUG

2601 if (areDebugNotesRequested())

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

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

2604#endif

2605 }

2606

2607 void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node,

2608 bool IsRelatedToDecl,

2609 ASTContext &Ctx) override {

2610 SourceLocation Loc;

2611

2612 Loc = Node.get()->getBeginLoc();

2613 S.Diag(Loc, diag::warn_unsafe_buffer_usage_unique_ptr_array_access)

2615 }

2616

2617 bool isSafeBufferOptOut(const SourceLocation &Loc) const override {

2618 return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc);

2619 }

2620

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

2623 }

2624

2625 bool ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const override {

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

2627 }

2628

2629

2630

2631

2632 std::string

2633 getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,

2634 StringRef WSSuffix = "") const override {

2635 Preprocessor &PP = S.getPreprocessor();

2636 TokenValue ClangUnsafeBufferUsageTokens[] = {

2637 tok::l_square,

2638 tok::l_square,

2640 tok::coloncolon,

2642 tok::r_square,

2643 tok::r_square};

2644

2645 StringRef MacroName;

2646

2647

2649 if (MacroName.empty())

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

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

2652 }

2653};

2654}

2655

2656

2657

2658

2659

2660

2662 enableCheckFallThrough = 1;

2663 enableCheckUnreachable = 0;

2664 enableThreadSafetyAnalysis = 0;

2665 enableConsumedAnalysis = 0;

2666}

2667

2668

2669

2670

2671

2672

2673

2674

2675

2676

2677

2678

2680public:

2681

2682

2684};

2685

2686template <typename... Ts>

2688 Ts... Diags) {

2689 return (!D.isIgnored(Diags, Loc) || ...);

2690}

2691

2694 NumFunctionsAnalyzed(0), NumFunctionsWithBadCFGs(0), NumCFGBlocks(0),

2695 MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),

2696 NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),

2697 NumUninitAnalysisBlockVisits(0),

2698 MaxUninitAnalysisBlockVisitsPerFunction(0) {

2699}

2700

2701

2703

2706 using namespace diag;

2709

2710

2711

2712 P.enableCheckUnreachable =

2713 PolicyOverrides.enableCheckUnreachable ||

2714 areAnyEnabled(D, Loc, warn_unreachable, warn_unreachable_break,

2715 warn_unreachable_return, warn_unreachable_loop_increment);

2716

2717 P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||

2719

2720 P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||

2721 areAnyEnabled(D, Loc, warn_use_in_invalid_state);

2722 return P;

2723}

2724

2725void sema::AnalysisBasedWarnings::clearOverrides() {

2726 PolicyOverrides.enableCheckUnreachable = false;

2727 PolicyOverrides.enableConsumedAnalysis = false;

2728 PolicyOverrides.enableThreadSafetyAnalysis = false;

2729}

2730

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

2734}

2735

2736template

2738 std::pair<Iterator, Iterator> PUDs) {

2739

2740 if (PUDs.first == PUDs.second)

2741 return;

2742

2743 for (auto I = PUDs.first; I != PUDs.second; ++I) {

2744 for (const Stmt *S : I->Stmts)

2746 }

2747

2751

2752 for (auto I = PUDs.first; I != PUDs.second; ++I) {

2753 const auto &D = *I;

2754 if (llvm::all_of(D.Stmts, [&](const Stmt *St) {

2755 const CFGBlock *Block = AC.getBlockForRegisteredExpression(St);

2756

2757

2758

2759 if (Block && Analysis)

2760 if (!Analysis->isReachable(&AC.getCFG()->getEntry(), Block))

2761 return false;

2762 return true;

2763 })) {

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

2765 }

2766 }

2767 } else {

2768 for (auto I = PUDs.first; I != PUDs.second; ++I)

2769 S.Diag(I->Loc, I->PD);

2770 }

2771}

2772

2775 VarDeclPossiblyUnreachableDiags.emplace(VD, PUD);

2776}

2777

2780 if (!llvm::is_contained(VarDeclPossiblyUnreachableDiags, VD))

2781 return;

2782

2784

2792

2793 auto Range = VarDeclPossiblyUnreachableDiags.equal_range(VD);

2794 auto SecondRange =

2795 llvm::make_second_range(llvm::make_range(Range.first, Range.second));

2797 S, AC, std::make_pair(SecondRange.begin(), SecondRange.end()));

2798}

2799

2800

2801

2803private:

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

2805 const Module *const TUModule;

2806

2807public:

2809 const Module *const TUModule)

2810 : Callback(Callback), TUModule(TUModule) {

2813 }

2814

2816

2817

2818

2821 return true;

2822 }

2823

2826 return true;

2827

2828

2829

2831 Callback(Node);

2832 return true;

2833 }

2834

2837 return true;

2838 Callback(Node);

2839 return true;

2840 }

2841

2844 return true;

2846 Callback(Node);

2847 return true;

2848 }

2849

2853};

2854

2855namespace clang::lifetimes {

2856namespace {

2857class LifetimeSafetyReporterImpl : public LifetimeSafetyReporter {

2858

2859public:

2860 LifetimeSafetyReporterImpl(Sema &S) : S(S) {}

2861

2862 void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,

2863 SourceLocation FreeLoc, Confidence C) override {

2865 C == Confidence::Definite

2866 ? diag::warn_lifetime_safety_loan_expires_permissive

2867 : diag::warn_lifetime_safety_loan_expires_strict)

2869 S.Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);

2870 S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)

2872 }

2873

2874 void reportUseAfterReturn(const Expr *IssueExpr, const Expr *EscapeExpr,

2875 SourceLocation ExpiryLoc, Confidence C) override {

2877 C == Confidence::Definite

2878 ? diag::warn_lifetime_safety_return_stack_addr_permissive

2879 : diag::warn_lifetime_safety_return_stack_addr_strict)

2881

2882 S.Diag(EscapeExpr->getExprLoc(), diag::note_lifetime_safety_returned_here)

2884 }

2885

2886 void suggestAnnotation(const ParmVarDecl *PVD,

2887 const Expr *EscapeExpr) override {

2890 S.Diag(PVD->getBeginLoc(), diag::warn_lifetime_safety_suggest_lifetimebound)

2893 " [[clang::lifetimebound]]");

2895 diag::note_lifetime_safety_suggestion_returned_here)

2897 }

2898

2899private:

2900 Sema &S;

2901};

2902}

2903}

2904

2907 if (!TU)

2908 return;

2909

2911

2913

2914 return;

2915

2917

2918

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

2920 bool UnsafeBufferUsageShouldEmitSuggestions =

2921 UnsafeBufferUsageCanEmitSuggestions &&

2922 DiagOpts.ShowSafeBufferUsageSuggestions;

2923 bool UnsafeBufferUsageShouldSuggestSuggestions =

2924 UnsafeBufferUsageCanEmitSuggestions &&

2925 !DiagOpts.ShowSafeBufferUsageSuggestions;

2926 UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions);

2927

2928

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

2930 if (Node->hasAttr())

2931 return;

2932

2933

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

2935 Node->getBeginLoc()) ||

2936 !Diags.isIgnored(diag::warn_unsafe_buffer_variable,

2937 Node->getBeginLoc()) ||

2938 !Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container,

2939 Node->getBeginLoc()) ||

2940 !Diags.isIgnored(diag::warn_unsafe_buffer_libc_call,

2941 Node->getBeginLoc())) {

2943 UnsafeBufferUsageShouldEmitSuggestions);

2944 }

2945

2946

2947 };

2948

2949

2952 !Diags.isIgnored(diag::warn_unsafe_buffer_usage_in_container,

2955 S.getLangOpts().CPlusPlus )) {

2957 .TraverseTranslationUnitDecl(TU);

2958 }

2959}

2960

2964

2965

2966

2967

2968

2969

2970

2972

2973

2976 S.SourceMgr.isInSystemHeader(D->getLocation())))

2977 return;

2978

2979

2981 return;

2982

2983 if (S.hasUncompilableErrorOccurred()) {

2984

2986 return;

2987 }

2988

2990 assert(Body);

2991

2992

2994

2995

2996

3004

3005 bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety;

3006

3007 if (EnableLifetimeSafetyAnalysis)

3009

3010

3011

3012

3013

3014

3015

3016 if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||

3017 P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) {

3018

3020 } else {

3023 .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)

3029 }

3030

3031

3032 std::optional LEH;

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

3034 LEH.emplace(S);

3036 }

3037

3038

3041

3042

3043 if (P.enableCheckFallThrough) {

3044 const CheckFallThroughDiagnostics &CD =

3045 (isa(D) ? CheckFallThroughDiagnostics::MakeForBlock()

3049 ? CheckFallThroughDiagnostics::MakeForLambda()

3051 ? CheckFallThroughDiagnostics::MakeForCoroutine(D)

3052 : CheckFallThroughDiagnostics::MakeForFunction(S, D)));

3054 }

3055

3056

3057 if (P.enableCheckUnreachable) {

3058

3059

3060

3061

3067 }

3068

3069

3070 if (P.enableThreadSafetyAnalysis) {

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

3075 Reporter.setIssueBetaWarnings(true);

3077 Reporter.setVerbose(true);

3078

3080 &S.ThreadSafetyDeclCache);

3081 Reporter.emitDiagnostics();

3082 }

3083

3084

3085 if (P.enableConsumedAnalysis) {

3086 consumed::ConsumedWarningsHandler WarningHandler(S);

3088 Analyzer.run(AC);

3089 }

3090

3097 UninitValsDiagReporter reporter(S);

3101 reporter, stats);

3102

3104 ++NumUninitAnalysisFunctions;

3106 NumUninitAnalysisBlockVisits += stats.NumBlockVisits;

3107 MaxUninitAnalysisVariablesPerFunction =

3108 std::max(MaxUninitAnalysisVariablesPerFunction,

3110 MaxUninitAnalysisBlockVisitsPerFunction =

3111 std::max(MaxUninitAnalysisBlockVisitsPerFunction,

3113 }

3114 }

3115 }

3116

3117

3118

3119 if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {

3121 lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);

3123 }

3124 }

3125

3126 if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&

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

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

3131 AC, Reporter,

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

3133 }

3134 }

3135

3136 bool FallThroughDiagFull =

3138 bool FallThroughDiagPerFunction = !Diags.isIgnored(

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

3140 if (FallThroughDiagFull || FallThroughDiagPerFunction ||

3143 }

3144

3145 if (S.getLangOpts().ObjCWeak &&

3148

3149

3150

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

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

3155 }

3156 }

3157

3158

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

3163

3164

3165

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

3168 }

3169

3170

3171 clearOverrides();

3172

3173

3174 if (S.CollectStats && AC.isCFGBuilt()) {

3175 ++NumFunctionsAnalyzed;

3177

3178

3179 NumCFGBlocks += cfg->getNumBlockIDs();

3180 MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,

3181 cfg->getNumBlockIDs());

3182 } else {

3183 ++NumFunctionsWithBadCFGs;

3184 }

3185 }

3186}

3187

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

3190

3191 unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;

3192 unsigned AvgCFGBlocksPerFunction =

3193 !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;

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

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

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

3197 << " " << AvgCFGBlocksPerFunction

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

3199 << " " << MaxCFGBlocksPerFunction

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

3201

3202 unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0

3203 : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;

3204 unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0

3205 : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;

3206 llvm::errs() << NumUninitAnalysisFunctions

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

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

3209 << " " << AvgUninitVariablesPerFunction

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

3211 << " " << MaxUninitAnalysisVariablesPerFunction

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

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

3214 << " " << AvgUninitBlockVisitsPerFunction

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

3216 << " " << MaxUninitAnalysisBlockVisitsPerFunction

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

3218}

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

Definition AnalysisBasedWarnings.cpp:344

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

Definition AnalysisBasedWarnings.cpp:915

static bool isReferenceToNoReturn(const Expr *E)

Checks if the given expression is a reference to a function with 'noreturn' attribute.

Definition AnalysisBasedWarnings.cpp:404

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

Definition AnalysisBasedWarnings.cpp:1482

static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC)

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

Definition AnalysisBasedWarnings.cpp:563

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

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

Definition AnalysisBasedWarnings.cpp:784

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

Definition AnalysisBasedWarnings.cpp:2731

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

Definition AnalysisBasedWarnings.cpp:1507

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

Definition AnalysisBasedWarnings.cpp:362

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

Definition AnalysisBasedWarnings.cpp:1416

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

Definition AnalysisBasedWarnings.cpp:382

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.

Definition AnalysisBasedWarnings.cpp:947

static StringRef getFallthroughAttrSpelling(Preprocessor &PP, SourceLocation Loc)

Definition AnalysisBasedWarnings.cpp:1382

static void emitPossiblyUnreachableDiags(Sema &S, AnalysisDeclContext &AC, std::pair< Iterator, Iterator > PUDs)

Definition AnalysisBasedWarnings.cpp:2737

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

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

Definition AnalysisBasedWarnings.cpp:1158

static bool areAnyEnabled(DiagnosticsEngine &D, SourceLocation Loc, Ts... Diags)

Definition AnalysisBasedWarnings.cpp:2687

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

Definition AnalysisBasedWarnings.cpp:216

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.

Definition AnalysisBasedWarnings.cpp:308

static bool areAllValuesNoReturn(const VarDecl *VD, const CFGBlock &VarBlk, AnalysisDeclContext &AC)

Definition AnalysisBasedWarnings.cpp:474

static bool isNoexcept(const FunctionDecl *FD)

Definition AnalysisBasedWarnings.cpp:395

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

Diagnose uninitialized const reference usages.

Definition AnalysisBasedWarnings.cpp:1138

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.

Definition AnalysisBasedWarnings.cpp:971

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

Diagnose uninitialized const pointer usages.

Definition AnalysisBasedWarnings.cpp:1146

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

CheckUnreachable - Check for unreachable code.

Definition AnalysisBasedWarnings.cpp:125

ControlFlowKind

Definition AnalysisBasedWarnings.cpp:546

@ NeverFallThrough

Definition AnalysisBasedWarnings.cpp:548

@ UnknownFallThrough

Definition AnalysisBasedWarnings.cpp:547

@ NeverFallThroughOrReturn

Definition AnalysisBasedWarnings.cpp:551

@ MaybeFallThrough

Definition AnalysisBasedWarnings.cpp:549

@ AlwaysFallThrough

Definition AnalysisBasedWarnings.cpp:550

static bool isInitializedWithNoReturn(const VarDecl *VD)

Checks if the given variable, which is assumed to be a function pointer, is initialized with a functi...

Definition AnalysisBasedWarnings.cpp:413

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

Definition AnalysisBasedWarnings.cpp:280

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

Definition AnalysisBasedWarnings.cpp:244

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)

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)

llvm::DenseMap< Stmt *, Stmt * > MapTy

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, ...);.

static bool ignoreUnsafeBufferInContainer(const Stmt &Node, const UnsafeBufferUsageHandler *Handler)

TextDiagnosticBuffer::DiagList DiagList

__device__ __2f16 float __ockl_bool s

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

Definition AnalysisBasedWarnings.cpp:2808

bool VisitObjCMethodDecl(ObjCMethodDecl *Node) override

Definition AnalysisBasedWarnings.cpp:2842

bool TraverseDecl(Decl *Node) override

Definition AnalysisBasedWarnings.cpp:2815

bool VisitBlockDecl(BlockDecl *Node) override

Definition AnalysisBasedWarnings.cpp:2835

bool VisitFunctionDecl(FunctionDecl *Node) override

Definition AnalysisBasedWarnings.cpp:2824

bool VisitLambdaExpr(LambdaExpr *Node) override

Definition AnalysisBasedWarnings.cpp:2850

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.

void registerForcedBlockExpression(const Stmt *stmt)

ParentMap & getParentMap()

const Decl * getDecl() const

bool getAddEHEdges() const

CFGReverseBlockReachabilityAnalysis * getCFGReachablityAnalysis()

ASTContext & getASTContext() const

CFG::BuildOptions & getCFGBuildOptions()

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,...

BinaryOperatorKind Opcode

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

ElementList::const_reverse_iterator const_reverse_iterator

FilteredCFGBlockIterator< const_pred_iterator, true > filtered_pred_iterator

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...

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...

const Stmt * getStmt() const

bool PruneTriviallyFalseEdges

bool AddCXXDefaultInitExprInCtors

BuildOptions & setAllAlwaysAdd()

BuildOptions & setAlwaysAdd(Stmt::StmtClass stmtClass, bool val=true)

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.

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

const Expr * getSubExpr() const

SourceLocation getThrowLoc() const

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

ExprIterator arg_iterator

FunctionDecl * getDirectCallee()

If the callee is a FunctionDecl, return it. Otherwise return null.

static CharSourceRange getCharRange(SourceRange R)

SourceLocation getBegin() const

ConditionalOperator - The ?

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 ?

Expr * getTrueExpr() const

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

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

void enqueueBlock(const CFGBlock *Block)

const CFGBlock * dequeue()

bool isFunctionOrMethod() const

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...

Module * getOwningModule() const

Get the module that owns this declaration (for visibility purposes).

FunctionDecl * getAsFunction() LLVM_READONLY

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

SourceLocation getLocation() const

DeclContext * getDeclContext()

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.

virtual SourceRange getSourceRange() const LLVM_READONLY

Source range that this declaration covers.

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 isLastDiagnosticIgnored() const

Determine whether the previous diagnostic was ignored.

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

const T * get() const

Retrieve the stored node as type T.

SourceRange getSourceRange(bool IncludeQualifier=false) const

For nodes which represent textual entities in the source code, return their SourceRange.

virtual bool TraverseDecl(MaybeConst< Decl > *D)

bool ShouldVisitTemplateInstantiations

bool ShouldVisitImplicitCode

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.

FunctionDecl * getCanonicalDecl() override

Retrieves the "canonical" declaration of the given declaration.

bool doesThisDeclarationHaveABody() const

Returns whether this specific declaration of the function has a body.

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.

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

CXXMethodDecl * getCallOperator() const

Retrieve the function call operator associated with this lambda expression.

static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)

Computes the source location just past the end of the token at this source location.

Describes a module or submodule.

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::".

@ Type

A type, stored as a Type*.

ObjCMethodDecl - Represents an instance or class method declaration.

bool hasBody() const override

Determine whether this method has a body.

Represents one property declaration in an Objective-C interface.

Stmt * getParent(Stmt *) const

SourceRange getSourceRange() const override LLVM_READONLY

Source range that this declaration covers.

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

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.

bool isConstant(const ASTContext &Ctx) const

Qualifiers getQualifiers() const

Retrieve the set of qualifiers applied to this type.

QualType getCanonicalType() const

bool isConstQualified() const

Determine whether this type is const-qualified.

bool hasObjCLifetime() const

SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)

Emit a 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

SourceManager & getSourceManager() const

bool handlerCanCatch(QualType HandlerType, QualType ExceptionType)

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.

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

StmtVisitor - This class implements a simple visitor for Stmt subclasses.

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

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

bool isIntegerType() const

isIntegerType() does not include complex integers (a GCC extension).

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.

TagDecl * getAsTagDecl() const

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

const T * getAs() const

Member-template getAs'.

Expr * getSubExpr() const

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

bool isConstPtrUse() const

bool isConstRefOrPtrUse() const

bool isConstRefUse() 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.

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

Represents a variable declaration or definition.

SourceRange getSourceRange() const override LLVM_READONLY

Source range that this declaration covers.

VarDecl * getDefinition(ASTContext &)

Get the real (not just tentative) definition for this declaration.

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.

Policy()

Definition AnalysisBasedWarnings.cpp:2661

void issueWarningsForRegisteredVarDecl(VarDecl *VD)

Definition AnalysisBasedWarnings.cpp:2778

void PrintStats() const

Definition AnalysisBasedWarnings.cpp:3188

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

Definition AnalysisBasedWarnings.cpp:2961

void registerVarDeclWarning(VarDecl *VD, PossiblyUnreachableDiag PUD)

Definition AnalysisBasedWarnings.cpp:2773

AnalysisBasedWarnings(Sema &s)

Definition AnalysisBasedWarnings.cpp:2692

Policy getPolicyInEffectAt(SourceLocation Loc)

Definition AnalysisBasedWarnings.cpp:2705

Represents a simple identification of a weak object.

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

bool HasFallthroughStmt

Whether there is a fallthrough statement in this function.

SmallVector< WeakUseTy, 4 > WeakUseVector

Used to collect uses of a particular weak object in a function body.

SmallVector< PossiblyUnreachableDiag, 4 > PossiblyUnreachableDiags

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

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

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

const WeakObjectUseMap & getWeakObjectUses() const

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

Definition AnalysisBasedWarnings.cpp:2679

CalledOnceInterProceduralData CalledOnceData

Definition AnalysisBasedWarnings.cpp:2683

std::list< DelayedDiag > DiagList

std::pair< PartialDiagnosticAt, OptionalNotes > DelayedDiag

SmallVector< PartialDiagnosticAt, 1 > OptionalNotes

uint32_t Variable

Boolean variables are represented as positive integers.

bool LE(InterpState &S, CodePtr OpPC)

void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter)

The main entry point for the analysis.

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.

LockErrorKind

This enum distinguishes between different situations where we warn due to inconsistent locking.

@ LEK_NotLockedAtEndOfFunction

Expecting a capability to be held at the end of function.

@ LEK_LockedSomePredecessors

A capability is locked in some but not all predecessors of a CFGBlock.

@ LEK_LockedAtEndOfFunction

A capability is still locked at the end of a function.

@ LEK_LockedSomeLoopIterations

A capability is locked for some but not all loop iterations.

AccessKind

This enum distinguishes between different ways to access (read or write) a variable.

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_PassPointer

Passing pointer to a guarded variable.

@ 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_PtPassPointer

Passing a pt-guarded pointer.

@ POK_PtReturnPointer

Returning a pt-guarded pointer.

@ POK_VarAccess

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

@ POK_FunctionCall

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

@ POK_ReturnPointer

Returning pointer to a guarded variable.

@ POK_PtReturnByRef

Returning a pt-guarded variable by reference.

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

bool isa(CodeGen::Address addr)

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)

bool hasSpecificAttr(const Container &container)

@ If

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

nullptr

This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...

@ 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.

DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor

U cast(CodeGen::Address addr)

A worklist implementation for backward dataflow analysis.

void enqueuePredecessors(const CFGBlock *Block)

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

APValue Val

Val - This is the value the expression can be folded to.

unsigned NumVariablesAnalyzed