[analyzer] When looking for a known class, only traverse the hierarchy once.

This has a small hit in the case where only one class is interesting
(NilArgChecker) but is a big improvement when looking for one of several
interesting classes (VariadicMethodTypeChecker), in which the most common
case is that there is no match.

llvm-svn: 158318
This commit is contained in:
Jordan Rose 2012-06-11 16:40:37 +00:00
parent 697067fae9
commit 3ba8ae3fd9
1 changed files with 50 additions and 48 deletions

View File

@ -29,6 +29,7 @@
#include "clang/AST/ExprObjC.h" #include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
using namespace clang; using namespace clang;
using namespace ento; using namespace ento;
@ -50,15 +51,34 @@ static const char* GetReceiverNameType(const ObjCMessage &msg) {
return 0; return 0;
} }
static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID, enum FoundationClass {
StringRef ClassName) { FC_None,
if (ID->getIdentifier()->getName() == ClassName) FC_NSArray,
return true; FC_NSDictionary,
FC_NSEnumerator,
FC_NSOrderedSet,
FC_NSSet,
FC_NSString
};
if (const ObjCInterfaceDecl *Super = ID->getSuperClass()) static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
return isReceiverClassOrSuperclass(Super, ClassName); static llvm::StringMap<FoundationClass> Classes;
if (Classes.empty()) {
Classes["NSArray"] = FC_NSArray;
Classes["NSDictionary"] = FC_NSDictionary;
Classes["NSEnumerator"] = FC_NSEnumerator;
Classes["NSOrderedSet"] = FC_NSOrderedSet;
Classes["NSSet"] = FC_NSSet;
Classes["NSString"] = FC_NSString;
}
return false; // FIXME: Should we cache this at all?
FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
if (result == FC_None)
if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
return findKnownClass(Super);
return result;
} }
static inline bool isNil(SVal X) { static inline bool isNil(SVal X) {
@ -106,7 +126,7 @@ void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
if (!ID) if (!ID)
return; return;
if (isReceiverClassOrSuperclass(ID, "NSString")) { if (findKnownClass(ID) == FC_NSString) {
Selector S = msg.getSelector(); Selector S = msg.getSelector();
if (S.isUnarySelector()) if (S.isUnarySelector())
@ -517,50 +537,32 @@ VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
// gains that this analysis gives. // gains that this analysis gives.
const ObjCInterfaceDecl *Class = MD->getClassInterface(); const ObjCInterfaceDecl *Class = MD->getClassInterface();
// -[NSArray initWithObjects:] switch (findKnownClass(Class)) {
if (isReceiverClassOrSuperclass(Class, "NSArray") && case FC_NSArray:
S == initWithObjectsS) case FC_NSOrderedSet:
return true; case FC_NSSet:
return S == initWithObjectsS;
// -[NSDictionary initWithObjectsAndKeys:] case FC_NSDictionary:
if (isReceiverClassOrSuperclass(Class, "NSDictionary") && return S == initWithObjectsAndKeysS;
S == initWithObjectsAndKeysS) default:
return true; return false;
}
// -[NSSet initWithObjects:]
if (isReceiverClassOrSuperclass(Class, "NSSet") &&
S == initWithObjectsS)
return true;
// -[NSOrderedSet initWithObjects:]
if (isReceiverClassOrSuperclass(Class, "NSOrderedSet") &&
S == initWithObjectsS)
return true;
} else { } else {
const ObjCInterfaceDecl *Class = msg.getReceiverInterface(); const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
// -[NSArray arrayWithObjects:] switch (findKnownClass(Class)) {
if (isReceiverClassOrSuperclass(Class, "NSArray") && case FC_NSArray:
S == arrayWithObjectsS) return S == arrayWithObjectsS;
return true; case FC_NSOrderedSet:
return S == orderedSetWithObjectsS;
// -[NSDictionary dictionaryWithObjectsAndKeys:] case FC_NSSet:
if (isReceiverClassOrSuperclass(Class, "NSDictionary") && return S == setWithObjectsS;
S == dictionaryWithObjectsAndKeysS) case FC_NSDictionary:
return true; return S == dictionaryWithObjectsAndKeysS;
default:
// -[NSSet setWithObjects:] return false;
if (isReceiverClassOrSuperclass(Class, "NSSet") && }
S == setWithObjectsS)
return true;
// -[NSOrderedSet orderedSetWithObjects:]
if (isReceiverClassOrSuperclass(Class, "NSOrderedSet") &&
S == orderedSetWithObjectsS)
return true;
} }
return false;
} }
void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg, void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,