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