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