diff options
author | Anders Carlsson <andersca@mac.com> | 2011-03-08 20:05:26 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2011-03-08 20:05:26 +0000 |
commit | b62bdce3e981ea4f357126bc391be1cbc1efa4df (patch) | |
tree | f57dc58e4b33142176c982f1e9020f5aac22c53f | |
parent | b77cab97f17f946744c920629ca17271308d8ebf (diff) |
Make the Objective-C checker look for subclasses of NSString instead of just NSString and NSMutableString.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127268 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp | 27 | ||||
-rw-r--r-- | test/Analysis/NSString.m | 7 |
2 files changed, 21 insertions, 13 deletions
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index e002a29379..f7a1ebe386 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -41,20 +41,21 @@ public: // Utility functions. //===----------------------------------------------------------------------===// -static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) { +static const char* GetReceiverNameType(const ObjCMessage &msg) { if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface()) - return ID->getTypeForDecl()->getAs<ObjCInterfaceType>(); - return NULL; + return ID->getIdentifier()->getNameStart(); + return 0; } -static const char* GetReceiverNameType(const ObjCMessage &msg) { - if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg)) - return ReceiverType->getDecl()->getIdentifier()->getNameStart(); - return NULL; -} +static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID, + llvm::StringRef ClassName) { + if (ID->getIdentifier()->getName() == ClassName) + return true; + + if (const ObjCInterfaceDecl *Super = ID->getSuperClass()) + return isReceiverClassOrSuperclass(Super, ClassName); -static bool isNSString(llvm::StringRef ClassName) { - return ClassName == "NSString" || ClassName == "NSMutableString"; + return false; } static inline bool isNil(SVal X) { @@ -98,11 +99,11 @@ void NilArgChecker::WarnNilArg(CheckerContext &C, void NilArgChecker::checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const { - const ObjCInterfaceType *ReceiverType = GetReceiverType(msg); - if (!ReceiverType) + const ObjCInterfaceDecl *ID = msg.getReceiverInterface(); + if (!ID) return; - if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) { + if (isReceiverClassOrSuperclass(ID, "NSString")) { Selector S = msg.getSelector(); if (S.isUnarySelector()) diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m index 16b527fcc7..76bf4a1471 100644 --- a/test/Analysis/NSString.m +++ b/test/Analysis/NSString.m @@ -190,6 +190,13 @@ void f13(void) { CFRelease(ref); // expected-warning{{Reference-counted object is used after it is released}} } +@interface MyString : NSString +@end + +void f14(MyString *s) { + [s compare:0]; // expected-warning {{Argument to 'MyString' method 'compare:' cannot be nil.}} +} + // Test regular use of -autorelease @interface TestAutorelease -(NSString*) getString; |