forked from OSchip/llvm-project
[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:
parent
697067fae9
commit
3ba8ae3fd9
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue