clang: lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
33#include "llvm/ADT/STLExtras.h"
34#include "llvm/ADT/SmallString.h"
35#include "llvm/ADT/StringMap.h"
36#include "llvm/Support/raw_ostream.h"
37#include
38
39using namespace clang;
40using namespace ento;
41using namespace llvm;
42
43namespace {
44class APIMisuse : public BugType {
45public:
46 APIMisuse(const CheckerBase *checker, const char *name)
48};
49}
50
51
52
53
54
57 return ID->getIdentifier()->getName();
58 return StringRef();
59}
60
71
73 bool IncludeSuperclasses = true) {
74 static llvm::StringMap Classes;
75 if (Classes.empty()) {
83 }
84
85
86 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
87 if (result == FC_None && IncludeSuperclasses)
90
91 return result;
92}
93
94
95
96
97
98namespace {
99class NilArgChecker : public Checker<check::PreObjCMessage,
100 check::PostStmt,
101 check::PostStmt,
102 EventDispatcher> {
103 mutable std::unique_ptr BT;
104
105 mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
106 mutable Selector ArrayWithObjectSel;
107 mutable Selector AddObjectSel;
108 mutable Selector InsertObjectAtIndexSel;
109 mutable Selector ReplaceObjectAtIndexWithObjectSel;
110 mutable Selector SetObjectAtIndexedSubscriptSel;
111 mutable Selector ArrayByAddingObjectSel;
112 mutable Selector DictionaryWithObjectForKeySel;
113 mutable Selector SetObjectForKeySel;
114 mutable Selector SetObjectForKeyedSubscriptSel;
115 mutable Selector RemoveObjectForKeySel;
116
118
120 FoundationClass Class, bool CanBeSubscript = false) const;
121
124
125public:
129};
130}
131
132void NilArgChecker::warnIfNilExpr(const Expr *E,
133 const char *Msg,
135 auto Location = C.getSVal(E).getAs<Loc>();
136 if (!Location)
137 return;
138
139 auto [NonNull, Null] = C.getState()->assume(*Location);
140
141
145 return;
146 }
147 }
148
149
150 if (Null) {
151
152 if (ExplodedNode *N = C.generateSink(Null, C.getPredecessor())) {
153 dispatchEvent({*Location, false, N, &C.getBugReporter(),
154 false});
155 }
157 }
158}
159
162 unsigned int Arg,
164 bool CanBeSubscript) const {
165
167 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
168 return;
169
170
171
172
173
174
177 llvm::raw_svector_ostream os(sbuf);
178
180
182 os << "Array element cannot be nil";
184 if (Arg == 0) {
185 os << "Value stored into '";
187 } else {
188 assert(Arg == 1);
190 }
191 } else
192 llvm_unreachable("Missing foundation class for the subscript expr");
193
194 } else {
196 if (Arg == 0)
197 os << "Value argument ";
198 else {
199 assert(Arg == 1);
200 os << "Key argument ";
201 }
202 os << "to '";
204 os << "' cannot be nil";
205 } else {
208 os << "' cannot be nil";
209 }
210 }
211
214 }
215}
216
217void NilArgChecker::generateBugReport(ExplodedNode *N,
218 StringRef Msg,
222 if (!BT)
223 BT.reset(new APIMisuse(this, "nil argument"));
224
225 auto R = std::make_unique(*BT, Msg, N);
226 R->addRange(Range);
228 C.emitReport(std::move(R));
229}
230
231void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
234 if (!ID)
235 return;
236
238
239 static const unsigned InvalidArgIndex = UINT_MAX;
240 unsigned Arg = InvalidArgIndex;
241 bool CanBeSubscript = false;
242
245
246 if (S.isUnarySelector())
247 return;
248
249 if (StringSelectors.empty()) {
262 };
263 for (Selector KnownSel : Sels)
264 StringSelectors[KnownSel] = 0;
265 }
266 auto I = StringSelectors.find(S);
267 if (I == StringSelectors.end())
268 return;
269 Arg = I->second;
272
273 if (S.isUnarySelector())
274 return;
275
276 if (ArrayWithObjectSel.isNull()) {
280 InsertObjectAtIndexSel =
282 ReplaceObjectAtIndexWithObjectSel =
284 SetObjectAtIndexedSubscriptSel =
286 ArrayByAddingObjectSel = getKeywordSelector(Ctx, "arrayByAddingObject");
287 }
288
289 if (S == ArrayWithObjectSel || S == AddObjectSel ||
290 S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
291 Arg = 0;
292 } else if (S == SetObjectAtIndexedSubscriptSel) {
293 Arg = 0;
294 CanBeSubscript = true;
295 } else if (S == ReplaceObjectAtIndexWithObjectSel) {
296 Arg = 1;
297 }
300
301 if (S.isUnarySelector())
302 return;
303
304 if (DictionaryWithObjectForKeySel.isNull()) {
306 DictionaryWithObjectForKeySel =
309 SetObjectForKeyedSubscriptSel =
311 RemoveObjectForKeySel = getKeywordSelector(Ctx, "removeObjectForKey");
312 }
313
314 if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
315 Arg = 0;
316 warnIfNilArg(C, msg, 1, Class);
317 } else if (S == SetObjectForKeyedSubscriptSel) {
318 CanBeSubscript = true;
319 Arg = 1;
320 } else if (S == RemoveObjectForKeySel) {
321 Arg = 0;
322 }
323 }
324
325
326 if ((Arg != InvalidArgIndex))
327 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
328}
329
333 for (unsigned i = 0; i < NumOfElements; ++i) {
334 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
335 }
336}
337
341 for (unsigned i = 0; i < NumOfElements; ++i) {
343 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
344 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
345 }
346}
347
348
349
350
351
352namespace {
353class CFNumberChecker : public Checker< check::PreStmt > {
354 mutable std::unique_ptr BT;
355 mutable IdentifierInfo *ICreate = nullptr, *IGetValue = nullptr;
356public:
357 CFNumberChecker() = default;
358
360};
361}
362
381
383 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
384
386 return FixedSize[i-1];
387
389
390 switch (i) {
401
402 default:
403 return std::nullopt;
404 }
405
407}
408
409#if 0
410static const char* GetCFNumberTypeStr(uint64_t i) {
411 static const char* Names[] = {
412 "kCFNumberSInt8Type",
413 "kCFNumberSInt16Type",
414 "kCFNumberSInt32Type",
415 "kCFNumberSInt64Type",
416 "kCFNumberFloat32Type",
417 "kCFNumberFloat64Type",
418 "kCFNumberCharType",
419 "kCFNumberShortType",
420 "kCFNumberIntType",
421 "kCFNumberLongType",
422 "kCFNumberLongLongType",
423 "kCFNumberFloatType",
424 "kCFNumberDoubleType",
425 "kCFNumberCFIndexType",
426 "kCFNumberNSIntegerType",
427 "kCFNumberCGFloatType"
428 };
429
431}
432#endif
433
434void CFNumberChecker::checkPreStmt(const CallExpr *CE,
438 if (!FD)
439 return;
440
442 if (!ICreate) {
443 ICreate = &Ctx.Idents.get("CFNumberCreate");
444 IGetValue = &Ctx.Idents.get("CFNumberGetValue");
445 }
448 return;
449
450
451 SVal TheTypeVal = C.getSVal(CE->getArg(1));
452
453
454
455 std::optionalnonloc::ConcreteInt V =
456 dyn_castnonloc::ConcreteInt(TheTypeVal);
457 if ()
458 return;
459
460 uint64_t NumberKind = V->getValue()->getLimitedValue();
461 std::optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
462
463
464 if (!OptCFNumberSize)
465 return;
466
467 uint64_t CFNumberSize = *OptCFNumberSize;
468
469
470
471
472 SVal TheValueExpr = C.getSVal(CE->getArg(2));
473
474
475
477 if (!LV)
478 return;
479
480 const TypedValueRegion* R = dyn_cast(LV->stripCasts());
481 if (!R)
482 return;
483
485
486
487
488
490 return;
491
493
494 if (PrimitiveTypeSize == CFNumberSize)
495 return;
496
497
498
500 if (N) {
502 llvm::raw_svector_ostream os(sbuf);
503 bool isCreate = (FD->getIdentifier() == ICreate);
504
505 if (isCreate) {
506 os << (PrimitiveTypeSize == 8 ? "An " : "A ")
507 << PrimitiveTypeSize << "-bit integer is used to initialize a "
508 << "CFNumber object that represents "
509 << (CFNumberSize == 8 ? "an " : "a ")
510 << CFNumberSize << "-bit integer; ";
511 } else {
512 os << "A CFNumber object that represents "
513 << (CFNumberSize == 8 ? "an " : "a ")
514 << CFNumberSize << "-bit integer is used to initialize "
515 << (PrimitiveTypeSize == 8 ? "an " : "a ")
516 << PrimitiveTypeSize << "-bit integer; ";
517 }
518
519 if (PrimitiveTypeSize < CFNumberSize)
520 os << (CFNumberSize - PrimitiveTypeSize)
521 << " bits of the CFNumber value will "
522 << (isCreate ? "be garbage." : "overwrite adjacent storage.");
523 else
524 os << (PrimitiveTypeSize - CFNumberSize)
525 << " bits of the integer value will be "
526 << (isCreate ? "lost." : "garbage.");
527
528 if (!BT)
529 BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs"));
530
531 auto report = std::make_unique(*BT, os.str(), N);
533 C.emitReport(std::move(report));
534 }
535}
536
537
538
539
540
541namespace {
542class CFRetainReleaseChecker : public Checkercheck::PreCall {
543 mutable APIMisuse BT{this, "null passed to CF memory management function"};
545 {CDM::CLibrary, {"CFRetain"}, 1},
546 {CDM::CLibrary, {"CFRelease"}, 1},
547 {CDM::CLibrary, {"CFMakeCollectable"}, 1},
548 {CDM::CLibrary, {"CFAutorelease"}, 1},
549 };
550
551public:
553};
554}
555
556void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
558
559 if (!ModelledCalls.contains(Call))
560 return;
561
562
563 SVal ArgVal = Call.getArgSVal(0);
564 std::optional DefArgVal = ArgVal.getAs<DefinedSVal>();
565 if (!DefArgVal)
566 return;
567
568
571 std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal);
572
573 if (!stateNonNull) {
574 ExplodedNode *N = C.generateErrorNode(stateNull);
575 if (!N)
576 return;
577
579 raw_svector_ostream OS(Str);
580 OS << "Null pointer argument in call to "
581 << cast(Call.getDecl())->getName();
582
583 auto report = std::make_unique(BT, OS.str(), N);
584 report->addRange(Call.getArgSourceRange(0));
586 C.emitReport(std::move(report));
587 return;
588 }
589
590
591 C.addTransition(stateNonNull);
592}
593
594
595
596
597
598namespace {
599class ClassReleaseChecker : public Checkercheck::PreObjCMessage {
602 mutable Selector autoreleaseS;
604 mutable std::unique_ptr BT;
605
606public:
608};
609}
610
611void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
613 if (!BT) {
614 BT.reset(new APIMisuse(
615 this, "message incorrectly sent to class instead of class instance"));
616
622 }
623
625 return;
627 assert(Class);
628
630 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
631 return;
632
633 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
635 llvm::raw_svector_ostream os(buf);
636
637 os << "The '";
638 S.print(os);
639 os << "' message should be sent to instances "
640 "of class '" << Class->getName()
641 << "' and not the class directly";
642
643 auto report = std::make_unique(*BT, os.str(), N);
645 C.emitReport(std::move(report));
646 }
647}
648
649
650
651
652
653
654namespace {
655class VariadicMethodTypeChecker : public Checkercheck::PreObjCMessage {
656 mutable Selector arrayWithObjectsS;
657 mutable Selector dictionaryWithObjectsAndKeysS;
658 mutable Selector setWithObjectsS;
659 mutable Selector orderedSetWithObjectsS;
660 mutable Selector initWithObjectsS;
661 mutable Selector initWithObjectsAndKeysS;
662 mutable std::unique_ptr BT;
663
664 bool isVariadicMessage(const ObjCMethodCall &msg) const;
665
666public:
668};
669}
670
671
672
673bool
674VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
676
678 return false;
679
681
683
684
685
686
687
688
690
695 return S == initWithObjectsS;
697 return S == initWithObjectsAndKeysS;
698 default:
699 return false;
700 }
701 } else {
703
706 return S == arrayWithObjectsS;
708 return S == orderedSetWithObjectsS;
710 return S == setWithObjectsS;
712 return S == dictionaryWithObjectsAndKeysS;
713 default:
714 return false;
715 }
716 }
717}
718
719void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
721 if (!BT) {
722 BT.reset(new APIMisuse(this,
723 "Arguments passed to variadic method aren't all "
724 "Objective-C pointer types"));
725
727 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
728 dictionaryWithObjectsAndKeysS =
731 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
732
734 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
735 }
736
737 if (!isVariadicMessage(msg))
738 return;
739
740
741
743
744
745
746 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
747
748 if (variadicArgsEnd <= variadicArgsBegin)
749 return;
750
751
752 std::optional<ExplodedNode *> errorNode;
753
754 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
757 continue;
758
759
761 continue;
762
763
764 if (isaloc::ConcreteInt(msg.getArgSVal(I)))
765 continue;
766
767
768 if (C.getASTContext().isObjCNSObjectType(ArgTy))
769 continue;
770
771
773 continue;
774
775
776 if (!errorNode)
777 errorNode = C.generateNonFatalErrorNode();
778
779 if (!*errorNode)
780 continue;
781
783 llvm::raw_svector_ostream os(sbuf);
784
787 os << "Argument to '" << TypeName << "' method '";
788 else
789 os << "Argument to method '";
790
792 os << "' should be an Objective-C pointer type, not '";
793 ArgTy.print(os, C.getLangOpts());
794 os << "'";
795
796 auto R =
797 std::make_unique(*BT, os.str(), *errorNode);
799 C.emitReport(std::move(R));
800 }
801}
802
803
804
805
806
807
808
811
812namespace {
813class ObjCLoopChecker
814 : public Checker<check::PostStmt,
815 check::PostObjCMessage,
816 check::DeadSymbols,
817 check::PointerEscape > {
819
820 bool isCollectionCountMethod(const ObjCMethodCall &M,
822
823public:
824 ObjCLoopChecker() = default;
832};
833}
834
837 if (!PT)
838 return false;
839
841 if (!ID)
842 return false;
843
850 return true;
851 default:
852 return false;
853 }
854}
855
856
857
858
859
863 if (!State)
864 return nullptr;
865
867 std::optional KnownCollection =
869 if (!KnownCollection)
870 return State;
871
873 std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
874 if (StNil && !StNonNil) {
875
876 return nullptr;
877 }
878
879 return StNonNil;
880}
881
882
883
884
885
889 if (!State)
890 return nullptr;
891
892
894 return State;
895
898
899
900 std::optional ElementLoc;
901 if (const DeclStmt *DS = dyn_cast(Element)) {
902 const VarDecl *ElemDecl = cast(DS->getSingleDecl());
903 assert(ElemDecl->getInit() == nullptr);
904 ElementLoc = State->getLValue(ElemDecl, LCtx);
905 } else {
906 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
907 }
908
909 if (!ElementLoc)
910 return State;
911
912
913 SVal Val = State->getSVal(*ElementLoc);
914 return State->assume(cast(Val), true);
915}
916
917
918
921 SymbolRef CollectionS, bool Assumption) {
922 if (!State || !CollectionS)
923 return State;
924
925 const SymbolRef *CountS = State->get(CollectionS);
926 if (!CountS) {
927 const bool *KnownNonEmpty = State->get(CollectionS);
928 if (!KnownNonEmpty)
929 return State->set(CollectionS, Assumption);
930 return (Assumption == *KnownNonEmpty) ? State : nullptr;
931 }
932
933 SValBuilder &SvalBuilder = C.getSValBuilder();
934 SVal CountGreaterThanZeroVal =
935 SvalBuilder.evalBinOp(State, BO_GT,
937 SvalBuilder.makeIntVal(0, (*CountS)->getType()),
939 std::optional CountGreaterThanZero =
941 if (!CountGreaterThanZero) {
942
943
944 return State;
945 }
946
947 return State->assume(*CountGreaterThanZero, Assumption);
948}
949
953 bool Assumption) {
954 if (!State)
955 return nullptr;
956
959}
960
961
964 if (!N)
965 return false;
966
968 if (std::optional BE = P.getAs<BlockEdge>()) {
969 return BE->getSrc()->getLoopTarget() == FCS;
970 }
971
972
975 return true;
976 }
977
978 return false;
979}
980
984
985
989
990
991 } else {
995 }
996
997 if (!State)
998 C.generateSink(C.getState(), C.getPredecessor());
999 else if (State != C.getState())
1000 C.addTransition(State);
1001}
1002
1003bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1006
1007 if (!CountSelectorII)
1008 CountSelectorII = &C.getASTContext().Idents.get("count");
1009
1010
1011 return S.isUnarySelector() &&
1012 (S.getIdentifierInfoForSlot(0) == CountSelectorII);
1013}
1014
1015void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1018 return;
1019
1021 if (!ClassID)
1022 return;
1023
1029 return;
1030
1032 if (!ContainerS)
1033 return;
1034
1035
1036
1037 if (!isCollectionCountMethod(M, C))
1038 return;
1039
1041 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1042 if (CountS) {
1044
1045 C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1046 State = State->set(ContainerS, CountS);
1047
1048 if (const bool *NonEmpty = State->get(ContainerS)) {
1049 State = State->remove(ContainerS);
1051 }
1052
1053 C.addTransition(State);
1054 }
1055}
1056
1058 const ObjCMethodCall *Message = dyn_cast_or_null(Call);
1059 if (!Message)
1060 return nullptr;
1061
1063 if (!MD)
1064 return nullptr;
1065
1068
1069
1070
1071 StaticClass = Message->getOriginExpr()->getReceiverInterface();
1072 } else {
1074 }
1075
1076 if (!StaticClass)
1077 return nullptr;
1078
1079 switch (findKnownClass(StaticClass, false)) {
1081 return nullptr;
1089 break;
1090 }
1091
1092 return Message->getReceiverSVal().getAsSymbol();
1093}
1094
1096ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1101
1102
1104
1105
1106
1107
1108 if (Sym == ImmutableReceiver)
1109 continue;
1110
1111
1112
1113 State = State->remove(Sym);
1114 State = State->remove(Sym);
1115 }
1116 return State;
1117}
1118
1119void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1122
1123
1124 ContainerCountMapTy Tracked = State->get();
1125 for (SymbolRef Sym : llvm::make_first_range(Tracked)) {
1126 if (SymReaper.isDead(Sym)) {
1127 State = State->remove(Sym);
1128 State = State->remove(Sym);
1129 }
1130 }
1131
1132 C.addTransition(State);
1133}
1134
1135namespace {
1136
1137
1138
1139class ObjCNonNilReturnValueChecker
1140 : public Checker<check::PostObjCMessage,
1141 check::PostStmt,
1142 check::PostStmt,
1143 check::PostStmt > {
1145 mutable Selector ObjectAtIndex;
1146 mutable Selector ObjectAtIndexedSubscript;
1147 mutable Selector NullSelector;
1148
1149public:
1150 ObjCNonNilReturnValueChecker() = default;
1151
1156 C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1157 }
1158
1160 assumeExprIsNonNull(E, C);
1161 }
1163 assumeExprIsNonNull(E, C);
1164 }
1166 assumeExprIsNonNull(E, C);
1167 }
1168
1170};
1171}
1172
1174ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1177 SVal Val = C.getSVal(NonNullExpr);
1178 if (std::optional DV =
1180 return State->assume(*DV, true);
1181 return State;
1182}
1183
1184void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1186 const {
1188
1192 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1194 }
1195
1196
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207 if (.inTopFrame() && M.getDecl() &&
1210 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1211 }
1212
1214
1215
1216
1217
1220 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1221
1222 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1223 }
1224 }
1225
1226
1229
1230 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1231 }
1232 }
1233 }
1234 C.addTransition(State);
1235}
1236
1237
1238
1239
1240
1241void ento::registerNilArgChecker(CheckerManager &mgr) {
1243}
1244
1245bool ento::shouldRegisterNilArgChecker(const CheckerManager &mgr) {
1246 return true;
1247}
1248
1249void ento::registerCFNumberChecker(CheckerManager &mgr) {
1251}
1252
1253bool ento::shouldRegisterCFNumberChecker(const CheckerManager &mgr) {
1254 return true;
1255}
1256
1257void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1259}
1260
1261bool ento::shouldRegisterCFRetainReleaseChecker(const CheckerManager &mgr) {
1262 return true;
1263}
1264
1265void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1267}
1268
1269bool ento::shouldRegisterClassReleaseChecker(const CheckerManager &mgr) {
1270 return true;
1271}
1272
1273void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1275}
1276
1277bool ento::shouldRegisterVariadicMethodTypeChecker(const CheckerManager &mgr) {
1278 return true;
1279}
1280
1281void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1283}
1284
1285bool ento::shouldRegisterObjCLoopChecker(const CheckerManager &mgr) {
1286 return true;
1287}
1288
1289void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1291}
1292
1293bool ento::shouldRegisterObjCNonNilReturnValueChecker(const CheckerManager &mgr) {
1294 return true;
1295}
Defines the clang::ASTContext interface.
static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N, const ObjCForCollectionStmt *FCS)
If the fist block edge is a back edge, we are reentering the loop.
static ProgramStateRef checkCollectionNonNil(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS)
Assumes that the collection is non-nil.
static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID, bool IncludeSuperclasses=true)
static bool isKnownNonNilCollectionType(QualType T)
static ProgramStateRef assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State, SymbolRef CollectionS, bool Assumption)
Returns NULL state if the collection is known to contain elements (or is known not to contain element...
static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call)
static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg)
static std::optional< uint64_t > GetCFNumberSize(ASTContext &Ctx, uint64_t i)
static ProgramStateRef checkElementNonNil(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS)
Assumes that the collection elements are non-nil.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Defines the Objective-C statement AST node classes.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
DeclContext * getDeclContext()
The return type of classify().
This represents one expression.
Represents a function declaration or definition.
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp,...
Expr * getElement(unsigned Index)
getElement - Return the Element at the specified index.
unsigned getNumElements() const
getNumElements - Return number of elements of objective-c array literal.
ObjCBoxedExpr - used for generalized expression boxing.
ObjCDictionaryLiteral - AST node to represent objective-c dictionary literals; as in:"name" : NSUserN...
unsigned getNumElements() const
getNumElements - Return number of elements of objective-c dictionary literal.
ObjCDictionaryElement getKeyValueElement(unsigned Index) const
Represents Objective-C's collection statement.
Represents an ObjC class declaration.
ObjCMethodDecl - Represents an instance or class method declaration.
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
ObjCInterfaceDecl * getClassInterface()
Represents a pointer to an Objective C object.
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface.
A (possibly-)qualified type.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
Smart pointer class that efficiently represents Objective-C method names.
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
unsigned getNumArgs() const
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
bool isBlockPointerType() const
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
bool isObjCObjectPointerType() const
const T * getAs() const
Member-template getAs'.
Represents a variable declaration or definition.
const Expr * getInit() const
An immutable set of CallDescriptions.
Represents an abstract call to a function or method along a particular path.
virtual SourceRange getArgSourceRange(unsigned Index) const
Returns the source range for errors associated with this argument.
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
static bool hasMoreIteration(ProgramStateRef State, const ObjCForCollectionStmt *O, const LocationContext *LC)
Represents any expression that calls an Objective-C method.
const ObjCMethodDecl * getDecl() const override
Returns the declaration of the function or method that will be called.
bool isInstanceMessage() const
const Expr * getArgExpr(unsigned Index) const override
Returns the expression associated with a given argument.
ObjCMessageKind getMessageKind() const
Returns how the message was written in the source (property access, subscript, or explicit message se...
unsigned getNumArgs() const override
Returns the number of arguments (explicit and implicit).
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
SourceRange getSourceRange() const override
Returns a source range for the entire call, suitable for outputting in diagnostics.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
bool isReceiverSelfOrSuper() const
Checks if the receiver refers to 'self' or 'super'.
Selector getSelector() const
A Range represents the closed range [from, to].
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
QualType getConditionType() const
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
TypedValueRegion - An abstract class representing regions having a typed value.
virtual QualType getValueType() const =0
Represents symbolic expression that isn't a location.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
const char *const AppleAPIMisuse
bool isCFObjectRef(QualType T)
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Descriptor *Desc)
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
The JSON file list parser is used to communicate input to InstallAPI.
static Selector getKeywordSelector(ASTContext &Ctx, const IdentifierInfos *...IIs)
@ NonNull
Values of this type can never be null.
Selector GetUnarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing an unary selector.
Selector GetNullarySelector(StringRef name, ASTContext &Ctx)
Utility function for constructing a nullary selector.
const FunctionProtoType * T
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
@ Class
The "class" keyword introduces the elaborated-type-specifier.
Diagnostic wrappers for TextAPI types for error reporting.
An element in an Objective-C dictionary literal.