clang 23.0.0git
BasicObjCFoundationChecks.cpp
Go to the documentation of this file.
1//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines BasicObjCFoundationChecks, a class that encapsulates
10// a set of simple checks to run on Objective-C code using Apple's Foundation
11// classes.
12//
13//===----------------------------------------------------------------------===//
14
16#include "clang/AST/DeclObjC.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/ExprObjC.h"
19#include "clang/AST/StmtObjC.h"
33#include "llvm/ADT/STLExtras.h"
34#include "llvm/ADT/StringMap.h"
35#include "llvm/Support/raw_ostream.h"
36#include <optional>
37
38using namespace clang;
39using namespace ento;
40using namespace llvm;
41
42namespace {
43class APIMisuse : public BugType {
44public:
45 APIMisuse(const CheckerBase *checker, const char *name)
46 : BugType(checker, name, categories::AppleAPIMisuse) {}
47};
48} // end anonymous namespace
49
50//===----------------------------------------------------------------------===//
51// Utility functions.
52//===----------------------------------------------------------------------===//
53
54static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
55 if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
56 return ID->getIdentifier()->getName();
57 return StringRef();
58}
59
70
72 bool IncludeSuperclasses = true) {
73 static const llvm::StringMap<FoundationClass> Classes{
74 {"NSArray", FC_NSArray}, {"NSDictionary", FC_NSDictionary},
75 {"NSEnumerator", FC_NSEnumerator}, {"NSNull", FC_NSNull},
76 {"NSOrderedSet", FC_NSOrderedSet}, {"NSSet", FC_NSSet},
77 {"NSString", FC_NSString},
78 };
79
80 // FIXME: Should we cache this at all?
81 FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
82 if (result == FC_None && IncludeSuperclasses)
83 if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
84 return findKnownClass(Super);
85
86 return result;
87}
88
89//===----------------------------------------------------------------------===//
90// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
91//===----------------------------------------------------------------------===//
92
93namespace {
94class NilArgChecker : public Checker<check::PreObjCMessage,
95 check::PostStmt<ObjCDictionaryLiteral>,
96 check::PostStmt<ObjCArrayLiteral>,
97 EventDispatcher<ImplicitNullDerefEvent>> {
98 const APIMisuse BT{this, "nil argument"};
99
100 mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
101 mutable Selector ArrayWithObjectSel;
102 mutable Selector AddObjectSel;
103 mutable Selector InsertObjectAtIndexSel;
104 mutable Selector ReplaceObjectAtIndexWithObjectSel;
105 mutable Selector SetObjectAtIndexedSubscriptSel;
106 mutable Selector ArrayByAddingObjectSel;
107 mutable Selector DictionaryWithObjectForKeySel;
108 mutable Selector SetObjectForKeySel;
109 mutable Selector SetObjectForKeyedSubscriptSel;
110 mutable Selector RemoveObjectForKeySel;
111
112 void warnIfNilExpr(const Expr *E, const char *Msg, CheckerContext &C) const;
113
114 void warnIfNilArg(CheckerContext &C, const ObjCMethodCall &msg, unsigned Arg,
115 FoundationClass Class, bool CanBeSubscript = false) const;
116
117 void generateBugReport(ExplodedNode *N, StringRef Msg, SourceRange Range,
118 const Expr *Expr, CheckerContext &C) const;
119
120public:
121 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
122 void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const;
123 void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const;
124};
125} // end anonymous namespace
126
127void NilArgChecker::warnIfNilExpr(const Expr *E,
128 const char *Msg,
129 CheckerContext &C) const {
130 auto Location = C.getSVal(E).getAs<Loc>();
131 if (!Location)
132 return;
133
134 auto [NonNull, Null] = C.getState()->assume(*Location);
135
136 // If it's known to be null.
137 if (!NonNull && Null) {
138 if (ExplodedNode *N = C.generateErrorNode()) {
139 generateBugReport(N, Msg, E->getSourceRange(), E, C);
140 return;
141 }
142 }
143
144 // If it might be null, assume that it cannot after this operation.
145 if (Null) {
146 // One needs to make sure the pointer is non-null to be used here.
147 if (ExplodedNode *N = C.generateSink(Null, C.getPredecessor())) {
148 dispatchEvent({*Location, /*IsLoad=*/false, N, &C.getBugReporter(),
149 /*IsDirectDereference=*/false});
150 }
151 C.addTransition(NonNull);
152 }
153}
154
155void NilArgChecker::warnIfNilArg(CheckerContext &C,
156 const ObjCMethodCall &msg,
157 unsigned int Arg,
159 bool CanBeSubscript) const {
160 // Check if the argument is nil.
161 ProgramStateRef State = C.getState();
162 if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
163 return;
164
165 // NOTE: We cannot throw non-fatal errors from warnIfNilExpr,
166 // because it's called multiple times from some callers, so it'd cause
167 // an unwanted state split if two or more non-fatal errors are thrown
168 // within the same checker callback. For now we don't want to, but
169 // it'll need to be fixed if we ever want to.
170 if (ExplodedNode *N = C.generateErrorNode()) {
171 SmallString<128> sbuf;
172 llvm::raw_svector_ostream os(sbuf);
173
174 if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
175
176 if (Class == FC_NSArray) {
177 os << "Array element cannot be nil";
178 } else if (Class == FC_NSDictionary) {
179 if (Arg == 0) {
180 os << "Value stored into '";
181 os << GetReceiverInterfaceName(msg) << "' cannot be nil";
182 } else {
183 assert(Arg == 1);
184 os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
185 }
186 } else
187 llvm_unreachable("Missing foundation class for the subscript expr");
188
189 } else {
190 if (Class == FC_NSDictionary) {
191 if (Arg == 0)
192 os << "Value argument ";
193 else {
194 assert(Arg == 1);
195 os << "Key argument ";
196 }
197 os << "to '";
198 msg.getSelector().print(os);
199 os << "' cannot be nil";
200 } else {
201 os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
202 msg.getSelector().print(os);
203 os << "' cannot be nil";
204 }
205 }
206
207 generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
208 msg.getArgExpr(Arg), C);
209 }
210}
211
212void NilArgChecker::generateBugReport(ExplodedNode *N,
213 StringRef Msg,
214 SourceRange Range,
215 const Expr *E,
216 CheckerContext &C) const {
217 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
218 R->addRange(Range);
220 C.emitReport(std::move(R));
221}
222
223void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
224 CheckerContext &C) const {
225 const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
226 if (!ID)
227 return;
228
230
231 static const unsigned InvalidArgIndex = UINT_MAX;
232 unsigned Arg = InvalidArgIndex;
233 bool CanBeSubscript = false;
234
235 if (Class == FC_NSString) {
236 Selector S = msg.getSelector();
237
238 if (S.isUnarySelector())
239 return;
240
241 if (StringSelectors.empty()) {
242 ASTContext &Ctx = C.getASTContext();
243 Selector Sels[] = {
244 getKeywordSelector(Ctx, "caseInsensitiveCompare"),
245 getKeywordSelector(Ctx, "compare"),
246 getKeywordSelector(Ctx, "compare", "options"),
247 getKeywordSelector(Ctx, "compare", "options", "range"),
248 getKeywordSelector(Ctx, "compare", "options", "range", "locale"),
249 getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet"),
250 getKeywordSelector(Ctx, "initWithFormat"),
251 getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare"),
252 getKeywordSelector(Ctx, "localizedCompare"),
253 getKeywordSelector(Ctx, "localizedStandardCompare"),
254 };
255 for (Selector KnownSel : Sels)
256 StringSelectors[KnownSel] = 0;
257 }
258 auto I = StringSelectors.find(S);
259 if (I == StringSelectors.end())
260 return;
261 Arg = I->second;
262 } else if (Class == FC_NSArray) {
263 Selector S = msg.getSelector();
264
265 if (S.isUnarySelector())
266 return;
267
268 if (ArrayWithObjectSel.isNull()) {
269 ASTContext &Ctx = C.getASTContext();
270 ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject");
271 AddObjectSel = getKeywordSelector(Ctx, "addObject");
272 InsertObjectAtIndexSel =
273 getKeywordSelector(Ctx, "insertObject", "atIndex");
274 ReplaceObjectAtIndexWithObjectSel =
275 getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject");
276 SetObjectAtIndexedSubscriptSel =
277 getKeywordSelector(Ctx, "setObject", "atIndexedSubscript");
278 ArrayByAddingObjectSel = getKeywordSelector(Ctx, "arrayByAddingObject");
279 }
280
281 if (S == ArrayWithObjectSel || S == AddObjectSel ||
282 S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
283 Arg = 0;
284 } else if (S == SetObjectAtIndexedSubscriptSel) {
285 Arg = 0;
286 CanBeSubscript = true;
287 } else if (S == ReplaceObjectAtIndexWithObjectSel) {
288 Arg = 1;
289 }
290 } else if (Class == FC_NSDictionary) {
291 Selector S = msg.getSelector();
292
293 if (S.isUnarySelector())
294 return;
295
296 if (DictionaryWithObjectForKeySel.isNull()) {
297 ASTContext &Ctx = C.getASTContext();
298 DictionaryWithObjectForKeySel =
299 getKeywordSelector(Ctx, "dictionaryWithObject", "forKey");
300 SetObjectForKeySel = getKeywordSelector(Ctx, "setObject", "forKey");
301 SetObjectForKeyedSubscriptSel =
302 getKeywordSelector(Ctx, "setObject", "forKeyedSubscript");
303 RemoveObjectForKeySel = getKeywordSelector(Ctx, "removeObjectForKey");
304 }
305
306 if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
307 Arg = 0;
308 warnIfNilArg(C, msg, /* Arg */1, Class);
309 } else if (S == SetObjectForKeyedSubscriptSel) {
310 CanBeSubscript = true;
311 Arg = 1;
312 } else if (S == RemoveObjectForKeySel) {
313 Arg = 0;
314 }
315 }
316
317 // If argument is '0', report a warning.
318 if ((Arg != InvalidArgIndex))
319 warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
320}
321
322void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
323 CheckerContext &C) const {
324 unsigned NumOfElements = AL->getNumElements();
325 for (unsigned i = 0; i < NumOfElements; ++i) {
326 warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
327 }
328}
329
330void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
331 CheckerContext &C) const {
332 unsigned NumOfElements = DL->getNumElements();
333 for (unsigned i = 0; i < NumOfElements; ++i) {
334 ObjCDictionaryElement Element = DL->getKeyValueElement(i);
335 warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
336 warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
337 }
338}
339
340//===----------------------------------------------------------------------===//
341// Checking for mismatched types passed to CFNumberCreate/CFNumberGetValue.
342//===----------------------------------------------------------------------===//
343
344namespace {
345class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > {
346 const APIMisuse BT{this, "Bad use of CFNumber APIs"};
347 mutable IdentifierInfo *ICreate = nullptr, *IGetValue = nullptr;
348public:
349 CFNumberChecker() = default;
350
351 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
352};
353} // end anonymous namespace
354
373
374static std::optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
375 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
376
377 if (i < kCFNumberCharType)
378 return FixedSize[i-1];
379
380 QualType T;
381
382 switch (i) {
383 case kCFNumberCharType: T = Ctx.CharTy; break;
384 case kCFNumberShortType: T = Ctx.ShortTy; break;
385 case kCFNumberIntType: T = Ctx.IntTy; break;
386 case kCFNumberLongType: T = Ctx.LongTy; break;
387 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
388 case kCFNumberFloatType: T = Ctx.FloatTy; break;
389 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
393 // FIXME: We need a way to map from names to Type*.
394 default:
395 return std::nullopt;
396 }
397
398 return Ctx.getTypeSize(T);
399}
400
401#if 0
402static const char* GetCFNumberTypeStr(uint64_t i) {
403 static const char* Names[] = {
404 "kCFNumberSInt8Type",
405 "kCFNumberSInt16Type",
406 "kCFNumberSInt32Type",
407 "kCFNumberSInt64Type",
408 "kCFNumberFloat32Type",
409 "kCFNumberFloat64Type",
410 "kCFNumberCharType",
411 "kCFNumberShortType",
412 "kCFNumberIntType",
413 "kCFNumberLongType",
414 "kCFNumberLongLongType",
415 "kCFNumberFloatType",
416 "kCFNumberDoubleType",
417 "kCFNumberCFIndexType",
418 "kCFNumberNSIntegerType",
419 "kCFNumberCGFloatType"
420 };
421
422 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
423}
424#endif
425
426void CFNumberChecker::checkPreStmt(const CallExpr *CE,
427 CheckerContext &C) const {
428 ProgramStateRef state = C.getState();
429 const FunctionDecl *FD = C.getCalleeDecl(CE);
430 if (!FD)
431 return;
432
433 ASTContext &Ctx = C.getASTContext();
434 if (!ICreate) {
435 ICreate = &Ctx.Idents.get("CFNumberCreate");
436 IGetValue = &Ctx.Idents.get("CFNumberGetValue");
437 }
438 if (!(FD->getIdentifier() == ICreate || FD->getIdentifier() == IGetValue) ||
439 CE->getNumArgs() != 3)
440 return;
441
442 // Get the value of the "theType" argument.
443 SVal TheTypeVal = C.getSVal(CE->getArg(1));
444
445 // FIXME: We really should allow ranges of valid theType values, and
446 // bifurcate the state appropriately.
447 std::optional<nonloc::ConcreteInt> V =
448 dyn_cast<nonloc::ConcreteInt>(TheTypeVal);
449 if (!V)
450 return;
451
452 uint64_t NumberKind = V->getValue()->getLimitedValue();
453 std::optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
454
455 // FIXME: In some cases we can emit an error.
456 if (!OptCFNumberSize)
457 return;
458
459 uint64_t CFNumberSize = *OptCFNumberSize;
460
461 // Look at the value of the integer being passed by reference. Essentially
462 // we want to catch cases where the value passed in is not equal to the
463 // size of the type being created.
464 SVal TheValueExpr = C.getSVal(CE->getArg(2));
465
466 // FIXME: Eventually we should handle arbitrary locations. We can do this
467 // by having an enhanced memory model that does low-level typing.
468 std::optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
469 if (!LV)
470 return;
471
472 const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
473 if (!R)
474 return;
475
476 QualType T = Ctx.getCanonicalType(R->getValueType());
477
478 // FIXME: If the pointee isn't an integer type, should we flag a warning?
479 // People can do weird stuff with pointers.
480
482 return;
483
484 uint64_t PrimitiveTypeSize = Ctx.getTypeSize(T);
485
486 if (PrimitiveTypeSize == CFNumberSize)
487 return;
488
489 // FIXME: We can actually create an abstract "CFNumber" object that has
490 // the bits initialized to the provided values.
491 ExplodedNode *N = C.generateNonFatalErrorNode();
492 if (N) {
493 SmallString<128> sbuf;
494 llvm::raw_svector_ostream os(sbuf);
495 bool isCreate = (FD->getIdentifier() == ICreate);
496
497 if (isCreate) {
498 os << (PrimitiveTypeSize == 8 ? "An " : "A ")
499 << PrimitiveTypeSize << "-bit integer is used to initialize a "
500 << "CFNumber object that represents "
501 << (CFNumberSize == 8 ? "an " : "a ")
502 << CFNumberSize << "-bit integer; ";
503 } else {
504 os << "A CFNumber object that represents "
505 << (CFNumberSize == 8 ? "an " : "a ")
506 << CFNumberSize << "-bit integer is used to initialize "
507 << (PrimitiveTypeSize == 8 ? "an " : "a ")
508 << PrimitiveTypeSize << "-bit integer; ";
509 }
510
511 if (PrimitiveTypeSize < CFNumberSize)
512 os << (CFNumberSize - PrimitiveTypeSize)
513 << " bits of the CFNumber value will "
514 << (isCreate ? "be garbage." : "overwrite adjacent storage.");
515 else
516 os << (PrimitiveTypeSize - CFNumberSize)
517 << " bits of the integer value will be "
518 << (isCreate ? "lost." : "garbage.");
519
520 auto report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
521 report->addRange(CE->getArg(2)->getSourceRange());
522 C.emitReport(std::move(report));
523 }
524}
525
526//===----------------------------------------------------------------------===//
527// CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
528//===----------------------------------------------------------------------===//
529
530namespace {
531class CFRetainReleaseChecker : public Checker<check::PreCall> {
532 const APIMisuse BT{this, "null passed to CF memory management function"};
533 const CallDescriptionSet ModelledCalls = {
534 {CDM::CLibrary, {"CFRetain"}, 1},
535 {CDM::CLibrary, {"CFRelease"}, 1},
536 {CDM::CLibrary, {"CFMakeCollectable"}, 1},
537 {CDM::CLibrary, {"CFAutorelease"}, 1},
538 };
539
540public:
541 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
542};
543} // end anonymous namespace
544
545void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
546 CheckerContext &C) const {
547 // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
548 if (!ModelledCalls.contains(Call))
549 return;
550
551 // Get the argument's value.
552 SVal ArgVal = Call.getArgSVal(0);
553 std::optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
554 if (!DefArgVal)
555 return;
556
557 // Is it null?
558 ProgramStateRef state = C.getState();
559 ProgramStateRef stateNonNull, stateNull;
560 std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal);
561
562 if (!stateNonNull) {
563 ExplodedNode *N = C.generateErrorNode(stateNull);
564 if (!N)
565 return;
566
567 SmallString<64> Str;
568 raw_svector_ostream OS(Str);
569 OS << "Null pointer argument in call to "
570 << cast<FunctionDecl>(Call.getDecl())->getName();
571
572 auto report = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
573 report->addRange(Call.getArgSourceRange(0));
574 bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report);
575 C.emitReport(std::move(report));
576 return;
577 }
578
579 // From here on, we know the argument is non-null.
580 C.addTransition(stateNonNull);
581}
582
583//===----------------------------------------------------------------------===//
584// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
585//===----------------------------------------------------------------------===//
586
587namespace {
588class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
589 mutable Selector releaseS;
590 mutable Selector retainS;
591 mutable Selector autoreleaseS;
592 mutable Selector drainS;
593 const APIMisuse BT{
594 this, "message incorrectly sent to class instead of class instance"};
595
596public:
597 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
598};
599} // end anonymous namespace
600
601void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
602 CheckerContext &C) const {
603 if (releaseS.isNull()) {
604 ASTContext &Ctx = C.getASTContext();
605 releaseS = GetNullarySelector("release", Ctx);
606 retainS = GetNullarySelector("retain", Ctx);
607 autoreleaseS = GetNullarySelector("autorelease", Ctx);
608 drainS = GetNullarySelector("drain", Ctx);
609 }
610
611 if (msg.isInstanceMessage())
612 return;
613 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
614 assert(Class);
615
616 Selector S = msg.getSelector();
617 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
618 return;
619
620 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
621 SmallString<200> buf;
622 llvm::raw_svector_ostream os(buf);
623
624 os << "The '";
625 S.print(os);
626 os << "' message should be sent to instances "
627 "of class '" << Class->getName()
628 << "' and not the class directly";
629
630 auto report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
631 report->addRange(msg.getSourceRange());
632 C.emitReport(std::move(report));
633 }
634}
635
636//===----------------------------------------------------------------------===//
637// Check for passing non-Objective-C types to variadic methods that expect
638// only Objective-C types.
639//===----------------------------------------------------------------------===//
640
641namespace {
642class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
643 mutable Selector arrayWithObjectsS;
644 mutable Selector dictionaryWithObjectsAndKeysS;
645 mutable Selector setWithObjectsS;
646 mutable Selector orderedSetWithObjectsS;
647 mutable Selector initWithObjectsS;
648 mutable Selector initWithObjectsAndKeysS;
649 const APIMisuse BT{this, "Arguments passed to variadic method aren't all "
650 "Objective-C pointer types"};
651
652 bool isVariadicMessage(const ObjCMethodCall &msg) const;
653
654public:
655 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
656};
657} // end anonymous namespace
658
659/// isVariadicMessage - Returns whether the given message is a variadic message,
660/// where all arguments must be Objective-C types.
661bool
662VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
663 const ObjCMethodDecl *MD = msg.getDecl();
664
665 if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
666 return false;
667
668 Selector S = msg.getSelector();
669
670 if (msg.isInstanceMessage()) {
671 // FIXME: Ideally we'd look at the receiver interface here, but that's not
672 // useful for init, because alloc returns 'id'. In theory, this could lead
673 // to false positives, for example if there existed a class that had an
674 // initWithObjects: implementation that does accept non-Objective-C pointer
675 // types, but the chance of that happening is pretty small compared to the
676 // gains that this analysis gives.
677 const ObjCInterfaceDecl *Class = MD->getClassInterface();
678
679 switch (findKnownClass(Class)) {
680 case FC_NSArray:
681 case FC_NSOrderedSet:
682 case FC_NSSet:
683 return S == initWithObjectsS;
684 case FC_NSDictionary:
685 return S == initWithObjectsAndKeysS;
686 default:
687 return false;
688 }
689 } else {
690 const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
691
692 switch (findKnownClass(Class)) {
693 case FC_NSArray:
694 return S == arrayWithObjectsS;
695 case FC_NSOrderedSet:
696 return S == orderedSetWithObjectsS;
697 case FC_NSSet:
698 return S == setWithObjectsS;
699 case FC_NSDictionary:
700 return S == dictionaryWithObjectsAndKeysS;
701 default:
702 return false;
703 }
704 }
705}
706
707void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
708 CheckerContext &C) const {
709 if (arrayWithObjectsS.isNull()) {
710 ASTContext &Ctx = C.getASTContext();
711 arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
712 dictionaryWithObjectsAndKeysS =
713 GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
714 setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
715 orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
716
717 initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
718 initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
719 }
720
721 if (!isVariadicMessage(msg))
722 return;
723
724 // We are not interested in the selector arguments since they have
725 // well-defined types, so the compiler will issue a warning for them.
726 unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
727
728 // We're not interested in the last argument since it has to be nil or the
729 // compiler would have issued a warning for it elsewhere.
730 unsigned variadicArgsEnd = msg.getNumArgs() - 1;
731
732 if (variadicArgsEnd <= variadicArgsBegin)
733 return;
734
735 // Verify that all arguments have Objective-C types.
736 std::optional<ExplodedNode *> errorNode;
737
738 for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
739 QualType ArgTy = msg.getArgExpr(I)->getType();
740 if (ArgTy->isObjCObjectPointerType())
741 continue;
742
743 // Block pointers are treaded as Objective-C pointers.
744 if (ArgTy->isBlockPointerType())
745 continue;
746
747 // Ignore pointer constants.
749 continue;
750
751 // Ignore pointer types annotated with 'NSObject' attribute.
752 if (C.getASTContext().isObjCNSObjectType(ArgTy))
753 continue;
754
755 // Ignore CF references, which can be toll-free bridged.
757 continue;
758
759 // Generate only one error node to use for all bug reports.
760 if (!errorNode)
761 errorNode = C.generateNonFatalErrorNode();
762
763 if (!*errorNode)
764 continue;
765
766 SmallString<128> sbuf;
767 llvm::raw_svector_ostream os(sbuf);
768
769 StringRef TypeName = GetReceiverInterfaceName(msg);
770 if (!TypeName.empty())
771 os << "Argument to '" << TypeName << "' method '";
772 else
773 os << "Argument to method '";
774
775 msg.getSelector().print(os);
776 os << "' should be an Objective-C pointer type, not '";
777 ArgTy.print(os, C.getLangOpts());
778 os << "'";
779
780 auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), *errorNode);
781 R->addRange(msg.getArgSourceRange(I));
782 C.emitReport(std::move(R));
783 }
784}
785
786//===----------------------------------------------------------------------===//
787// Improves the modeling of loops over Cocoa collections.
788//===----------------------------------------------------------------------===//
789
790// The map from container symbol to the container count symbol.
791// We currently will remember the last container count symbol encountered.
793REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
794
795namespace {
796class ObjCLoopChecker
797 : public Checker<check::PostStmt<ObjCForCollectionStmt>,
798 check::PostObjCMessage,
799 check::DeadSymbols,
800 check::PointerEscape > {
801 mutable IdentifierInfo *CountSelectorII = nullptr;
802
803 bool isCollectionCountMethod(const ObjCMethodCall &M,
804 CheckerContext &C) const;
805
806public:
807 ObjCLoopChecker() = default;
808 void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
809 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
810 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
811 ProgramStateRef checkPointerEscape(ProgramStateRef State,
812 const InvalidatedSymbols &Escaped,
813 const CallEvent *Call,
814 PointerEscapeKind Kind) const;
815};
816} // end anonymous namespace
817
820 if (!PT)
821 return false;
822
823 const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
824 if (!ID)
825 return false;
826
827 switch (findKnownClass(ID)) {
828 case FC_NSArray:
829 case FC_NSDictionary:
830 case FC_NSEnumerator:
831 case FC_NSOrderedSet:
832 case FC_NSSet:
833 return true;
834 default:
835 return false;
836 }
837}
838
839/// Assumes that the collection is non-nil.
840///
841/// If the collection is known to be nil, returns NULL to indicate an infeasible
842/// path.
844 ProgramStateRef State,
845 const ObjCForCollectionStmt *FCS) {
846 if (!State)
847 return nullptr;
848
849 SVal CollectionVal = C.getSVal(FCS->getCollection());
850 std::optional<DefinedSVal> KnownCollection =
851 CollectionVal.getAs<DefinedSVal>();
852 if (!KnownCollection)
853 return State;
854
855 ProgramStateRef StNonNil, StNil;
856 std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
857 if (StNil && !StNonNil) {
858 // The collection is nil. This path is infeasible.
859 return nullptr;
860 }
861
862 return StNonNil;
863}
864
865/// Assumes that the collection elements are non-nil.
866///
867/// This only applies if the collection is one of those known not to contain
868/// nil values.
870 ProgramStateRef State,
871 const ObjCForCollectionStmt *FCS) {
872 if (!State)
873 return nullptr;
874
875 // See if the collection is one where we /know/ the elements are non-nil.
877 return State;
878
879 const LocationContext *LCtx = C.getLocationContext();
880 const Stmt *Element = FCS->getElement();
881
882 // FIXME: Copied from ExprEngineObjC.
883 std::optional<Loc> ElementLoc;
884 if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
885 const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
886 assert(ElemDecl->getInit() == nullptr);
887 ElementLoc = State->getLValue(ElemDecl, LCtx);
888 } else {
889 ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
890 }
891
892 if (!ElementLoc)
893 return State;
894
895 // Go ahead and assume the value is non-nil.
896 SVal Val = State->getSVal(*ElementLoc);
897 return State->assume(cast<DefinedOrUnknownSVal>(Val), true);
898}
899
900/// Returns NULL state if the collection is known to contain elements
901/// (or is known not to contain elements if the Assumption parameter is false.)
902static ProgramStateRef
904 SymbolRef CollectionS, bool Assumption) {
905 if (!State || !CollectionS)
906 return State;
907
908 const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
909 if (!CountS) {
910 const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
911 if (!KnownNonEmpty)
912 return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
913 return (Assumption == *KnownNonEmpty) ? State : nullptr;
914 }
915
916 SValBuilder &SvalBuilder = C.getSValBuilder();
917 SVal CountGreaterThanZeroVal =
918 SvalBuilder.evalBinOp(State, BO_GT,
919 nonloc::SymbolVal(*CountS),
920 SvalBuilder.makeIntVal(0, (*CountS)->getType()),
921 SvalBuilder.getConditionType());
922 std::optional<DefinedSVal> CountGreaterThanZero =
923 CountGreaterThanZeroVal.getAs<DefinedSVal>();
924 if (!CountGreaterThanZero) {
925 // The SValBuilder cannot construct a valid SVal for this condition.
926 // This means we cannot properly reason about it.
927 return State;
928 }
929
930 return State->assume(*CountGreaterThanZero, Assumption);
931}
932
933static ProgramStateRef
935 const ObjCForCollectionStmt *FCS,
936 bool Assumption) {
937 if (!State)
938 return nullptr;
939
940 SymbolRef CollectionS = C.getSVal(FCS->getCollection()).getAsSymbol();
941 return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
942}
943
944/// If the fist block edge is a back edge, we are reentering the loop.
946 const ObjCForCollectionStmt *FCS) {
947 if (!N)
948 return false;
949
950 ProgramPoint P = N->getLocation();
951 if (std::optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
952 return BE->getSrc()->getLoopTarget() == FCS;
953 }
954
955 // Keep looking for a block edge.
956 for (const ExplodedNode *N : N->preds()) {
958 return true;
959 }
960
961 return false;
962}
963
964void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
965 CheckerContext &C) const {
966 ProgramStateRef State = C.getState();
967
968 // Check if this is the branch for the end of the loop.
969 if (!ExprEngine::hasMoreIteration(State, FCS, C.getLocationContext())) {
970 if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
971 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
972
973 // Otherwise, this is a branch that goes through the loop body.
974 } else {
975 State = checkCollectionNonNil(C, State, FCS);
976 State = checkElementNonNil(C, State, FCS);
977 State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
978 }
979
980 if (!State)
981 C.generateSink(C.getState(), C.getPredecessor());
982 else if (State != C.getState())
983 C.addTransition(State);
984}
985
986bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
987 CheckerContext &C) const {
988 Selector S = M.getSelector();
989 // Initialize the identifiers on first use.
990 if (!CountSelectorII)
991 CountSelectorII = &C.getASTContext().Idents.get("count");
992
993 // If the method returns collection count, record the value.
994 return S.isUnarySelector() &&
995 (S.getIdentifierInfoForSlot(0) == CountSelectorII);
996}
997
998void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
999 CheckerContext &C) const {
1000 if (!M.isInstanceMessage())
1001 return;
1002
1003 const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1004 if (!ClassID)
1005 return;
1006
1008 if (Class != FC_NSDictionary &&
1009 Class != FC_NSArray &&
1010 Class != FC_NSSet &&
1012 return;
1013
1014 SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1015 if (!ContainerS)
1016 return;
1017
1018 // If we are processing a call to "count", get the symbolic value returned by
1019 // a call to "count" and add it to the map.
1020 if (!isCollectionCountMethod(M, C))
1021 return;
1022
1023 const Expr *MsgExpr = M.getOriginExpr();
1024 SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1025 if (CountS) {
1026 ProgramStateRef State = C.getState();
1027
1028 C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1029 State = State->set<ContainerCountMap>(ContainerS, CountS);
1030
1031 if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1032 State = State->remove<ContainerNonEmptyMap>(ContainerS);
1033 State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1034 }
1035
1036 C.addTransition(State);
1037 }
1038}
1039
1041 const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1042 if (!Message)
1043 return nullptr;
1044
1045 const ObjCMethodDecl *MD = Message->getDecl();
1046 if (!MD)
1047 return nullptr;
1048
1049 const ObjCInterfaceDecl *StaticClass;
1051 // We can't find out where the method was declared without doing more work.
1052 // Instead, see if the receiver is statically typed as a known immutable
1053 // collection.
1054 StaticClass = Message->getOriginExpr()->getReceiverInterface();
1055 } else {
1056 StaticClass = MD->getClassInterface();
1057 }
1058
1059 if (!StaticClass)
1060 return nullptr;
1061
1062 switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1063 case FC_None:
1064 return nullptr;
1065 case FC_NSArray:
1066 case FC_NSDictionary:
1067 case FC_NSEnumerator:
1068 case FC_NSNull:
1069 case FC_NSOrderedSet:
1070 case FC_NSSet:
1071 case FC_NSString:
1072 break;
1073 }
1074
1075 return Message->getReceiverSVal().getAsSymbol();
1076}
1077
1079ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1080 const InvalidatedSymbols &Escaped,
1081 const CallEvent *Call,
1082 PointerEscapeKind Kind) const {
1084
1085 // Remove the invalidated symbols from the collection count map.
1086 for (SymbolRef Sym : Escaped) {
1087 // Don't invalidate this symbol's count if we know the method being called
1088 // is declared on an immutable class. This isn't completely correct if the
1089 // receiver is also passed as an argument, but in most uses of NSArray,
1090 // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1091 if (Sym == ImmutableReceiver)
1092 continue;
1093
1094 // The symbol escaped. Pessimistically, assume that the count could have
1095 // changed.
1096 State = State->remove<ContainerCountMap>(Sym);
1097 State = State->remove<ContainerNonEmptyMap>(Sym);
1098 }
1099 return State;
1100}
1101
1102void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1103 CheckerContext &C) const {
1104 ProgramStateRef State = C.getState();
1105
1106 // Remove the dead symbols from the collection count map.
1107 ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1108 for (SymbolRef Sym : llvm::make_first_range(Tracked)) {
1109 if (SymReaper.isDead(Sym)) {
1110 State = State->remove<ContainerCountMap>(Sym);
1111 State = State->remove<ContainerNonEmptyMap>(Sym);
1112 }
1113 }
1114
1115 C.addTransition(State);
1116}
1117
1118namespace {
1119/// \class ObjCNonNilReturnValueChecker
1120/// The checker restricts the return values of APIs known to
1121/// never (or almost never) return 'nil'.
1122class ObjCNonNilReturnValueChecker
1123 : public Checker<check::PostObjCMessage,
1124 check::PostStmt<ObjCArrayLiteral>,
1125 check::PostStmt<ObjCDictionaryLiteral>,
1126 check::PostStmt<ObjCBoxedExpr> > {
1127 mutable bool Initialized = false;
1128 mutable Selector ObjectAtIndex;
1129 mutable Selector ObjectAtIndexedSubscript;
1130 mutable Selector NullSelector;
1131
1132public:
1133 ObjCNonNilReturnValueChecker() = default;
1134
1135 ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1136 ProgramStateRef State,
1137 CheckerContext &C) const;
1138 void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1139 C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1140 }
1141
1142 void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1143 assumeExprIsNonNull(E, C);
1144 }
1145 void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1146 assumeExprIsNonNull(E, C);
1147 }
1148 void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1149 assumeExprIsNonNull(E, C);
1150 }
1151
1152 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1153};
1154} // end anonymous namespace
1155
1157ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1158 ProgramStateRef State,
1159 CheckerContext &C) const {
1160 SVal Val = C.getSVal(NonNullExpr);
1161 if (std::optional<DefinedOrUnknownSVal> DV =
1162 Val.getAs<DefinedOrUnknownSVal>())
1163 return State->assume(*DV, true);
1164 return State;
1165}
1166
1167void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1168 CheckerContext &C)
1169 const {
1170 ProgramStateRef State = C.getState();
1171
1172 if (!Initialized) {
1173 ASTContext &Ctx = C.getASTContext();
1174 ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1175 ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1176 NullSelector = GetNullarySelector("null", Ctx);
1177 }
1178
1179 // Check the receiver type.
1180 if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1181
1182 // Assume that object returned from '[self init]' or '[super init]' is not
1183 // 'nil' if we are processing an inlined function/method.
1184 //
1185 // A defensive callee will (and should) check if the object returned by
1186 // '[super init]' is 'nil' before doing it's own initialization. However,
1187 // since 'nil' is rarely returned in practice, we should not warn when the
1188 // caller to the defensive constructor uses the object in contexts where
1189 // 'nil' is not accepted.
1190 if (!C.inTopFrame() && M.getDecl() &&
1191 M.getDecl()->getMethodFamily() == OMF_init &&
1193 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1194 }
1195
1197
1198 // Objects returned from
1199 // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1200 // are never 'nil'.
1201 if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
1202 Selector Sel = M.getSelector();
1203 if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
1204 // Go ahead and assume the value is non-nil.
1205 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1206 }
1207 }
1208
1209 // Objects returned from [NSNull null] are not nil.
1210 if (Cl == FC_NSNull) {
1211 if (M.getSelector() == NullSelector) {
1212 // Go ahead and assume the value is non-nil.
1213 State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1214 }
1215 }
1216 }
1217 C.addTransition(State);
1218}
1219
1220//===----------------------------------------------------------------------===//
1221// Check registration.
1222//===----------------------------------------------------------------------===//
1223
1224void ento::registerNilArgChecker(CheckerManager &mgr) {
1225 mgr.registerChecker<NilArgChecker>();
1226}
1227
1228bool ento::shouldRegisterNilArgChecker(const CheckerManager &mgr) {
1229 return true;
1230}
1231
1232void ento::registerCFNumberChecker(CheckerManager &mgr) {
1233 mgr.registerChecker<CFNumberChecker>();
1234}
1235
1236bool ento::shouldRegisterCFNumberChecker(const CheckerManager &mgr) {
1237 return true;
1238}
1239
1240void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1241 mgr.registerChecker<CFRetainReleaseChecker>();
1242}
1243
1244bool ento::shouldRegisterCFRetainReleaseChecker(const CheckerManager &mgr) {
1245 return true;
1246}
1247
1248void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1249 mgr.registerChecker<ClassReleaseChecker>();
1250}
1251
1252bool ento::shouldRegisterClassReleaseChecker(const CheckerManager &mgr) {
1253 return true;
1254}
1255
1256void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1257 mgr.registerChecker<VariadicMethodTypeChecker>();
1258}
1259
1260bool ento::shouldRegisterVariadicMethodTypeChecker(const CheckerManager &mgr) {
1261 return true;
1262}
1263
1264void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1265 mgr.registerChecker<ObjCLoopChecker>();
1266}
1267
1268bool ento::shouldRegisterObjCLoopChecker(const CheckerManager &mgr) {
1269 return true;
1270}
1271
1272void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1273 mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1274}
1275
1276bool ento::shouldRegisterObjCNonNilReturnValueChecker(const CheckerManager &mgr) {
1277 return true;
1278}
Defines the clang::ASTContext interface.
#define V(N, I)
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.
Expr::Classification Cl
#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 ...
Definition ASTContext.h:226
CanQualType LongTy
static CanQualType getCanonicalType(QualType T)
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
CanQualType FloatTy
CanQualType DoubleTy
IdentifierTable & Idents
Definition ASTContext.h:797
CanQualType CharTy
CanQualType IntTy
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CanQualType ShortTy
CanQualType LongLongTy
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3150
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3137
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1623
DeclContext * getDeclContext()
Definition DeclBase.h:448
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
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.
Definition Decl.h:295
Expr * getElement(unsigned Index)
getElement - Return the Element at the specified index.
Definition ExprObjC.h:230
unsigned getNumElements() const
getNumElements - Return number of elements of objective-c array literal.
Definition ExprObjC.h:227
unsigned getNumElements() const
getNumElements - Return number of elements of objective-c dictionary literal.
Definition ExprObjC.h:358
ObjCDictionaryElement getKeyValueElement(unsigned Index) const
Definition ExprObjC.h:360
Represents Objective-C's collection statement.
Definition StmtObjC.h:23
Represents an ObjC class declaration.
Definition DeclObjC.h:1154
ObjCInterfaceDecl * getSuperClass() const
Definition DeclObjC.cpp:349
ObjCMethodDecl - Represents an instance or class method declaration.
Definition DeclObjC.h:140
bool isVariadic() const
Definition DeclObjC.h:431
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
ObjCInterfaceDecl * getClassInterface()
Represents a pointer to an Objective C object.
Definition TypeBase.h:7967
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface.
Definition TypeBase.h:8019
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
Definition TypeBase.h:937
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
const IdentifierInfo * getIdentifierInfoForSlot(unsigned argIndex) const
Retrieve the identifier at a given position in the selector.
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
bool isUnarySelector() const
bool isNull() const
Determine whether this is the empty selector.
unsigned getNumArgs() const
Stmt - This represents one statement.
Definition Stmt.h:86
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
bool isBlockPointerType() const
Definition TypeBase.h:8606
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition TypeBase.h:9074
bool isObjCObjectPointerType() const
Definition TypeBase.h:8765
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9179
Represents a variable declaration or definition.
Definition Decl.h:926
const Expr * getInit() const
Definition Decl.h:1368
bool contains(const CallEvent &Call) const
Represents an abstract call to a function or method along a particular path.
Definition CallEvent.h:153
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)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:553
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.
Definition CallEvent.h:1261
const ObjCMethodDecl * getDecl() const override
Returns the declaration of the function or method that will be called.
Definition CallEvent.h:1291
const Expr * getArgExpr(unsigned Index) const override
Returns the expression associated with a given argument.
Definition CallEvent.h:1297
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).
Definition CallEvent.h:1295
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
Definition CallEvent.h:1287
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.
Definition CallEvent.h:1320
bool isReceiverSelfOrSuper() const
Checks if the receiver refers to 'self' or 'super'.
Selector getSelector() const
Definition CallEvent.h:1309
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.
Definition SVals.h:56
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition SVals.cpp:103
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:87
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
virtual QualType getValueType() const =0
Represents symbolic expression that isn't a location.
Definition SVals.h:279
#define UINT_MAX
Definition limits.h:64
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.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition Store.h:51
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Descriptor *Desc)
Definition Interp.h:2811
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)
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ NonNull
Values of this type can never be null.
Definition Specifiers.h:350
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.
U cast(CodeGen::Address addr)
Definition Address.h:327
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
Definition TypeBase.h:5880
@ Class
The "class" keyword introduces the elaborated-type-specifier.
Definition TypeBase.h:5886
unsigned long uint64_t
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
Expr * Value
The value of the dictionary element.
Definition ExprObjC.h:265
Expr * Key
The key for the dictionary element.
Definition ExprObjC.h:262