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

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