Teach the static analyzer's interpretation of Cocoa conventions to

obey the objc_method_family attribute when provided. Fixes
<rdar://problem/9726279>.

llvm-svn: 134493
This commit is contained in:
Douglas Gregor 2011-07-06 16:00:34 +00:00
parent e443ba736b
commit 5c70b06feb
4 changed files with 39 additions and 8 deletions

View File

@ -17,15 +17,19 @@
#include "clang/AST/Type.h"
namespace clang {
class ObjCMethodDecl;
namespace ento {
namespace cocoa {
enum NamingConvention { NoConvention, CreateRule, InitRule };
NamingConvention deriveNamingConvention(Selector S);
NamingConvention deriveNamingConvention(Selector S, const ObjCMethodDecl *MD);
static inline bool followsFundamentalRule(Selector S) {
return deriveNamingConvention(S) == CreateRule;
static inline bool followsFundamentalRule(Selector S,
const ObjCMethodDecl *MD) {
return deriveNamingConvention(S, MD) == CreateRule;
}
bool isRefType(QualType RetTy, llvm::StringRef Prefix,

View File

@ -36,8 +36,10 @@ using llvm::StringRef;
// not release it."
//
cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
switch (S.getMethodFamily()) {
cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
const ObjCMethodDecl *MD) {
switch (MD && MD->hasAttr<ObjCMethodFamilyAttr>()? MD->getMethodFamily()
: S.getMethodFamily()) {
case OMF_None:
case OMF_autorelease:
case OMF_dealloc:

View File

@ -1349,7 +1349,7 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
if (cocoa::isCocoaObjectRef(RetTy)) {
// EXPERIMENTAL: assume the Cocoa conventions for all objects returned
// by instance methods.
RetEffect E = cocoa::followsFundamentalRule(S)
RetEffect E = cocoa::followsFundamentalRule(S, MD)
? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC);
return getPersistentSummary(E, ReceiverEff, MayEscape);
@ -1357,7 +1357,7 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
// Look for methods that return an owned core foundation object.
if (cocoa::isCFObjectRef(RetTy)) {
RetEffect E = cocoa::followsFundamentalRule(S)
RetEffect E = cocoa::followsFundamentalRule(S, MD)
? RetEffect::MakeOwned(RetEffect::CF, true)
: RetEffect::MakeNotOwned(RetEffect::CF);
@ -1428,7 +1428,7 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S,
assert(ScratchArgs.isEmpty());
// "initXXX": pass-through for receiver.
if (cocoa::deriveNamingConvention(S) == cocoa::InitRule)
if (cocoa::deriveNamingConvention(S, MD) == cocoa::InitRule)
Summ = getInitMethodSummary(RetTy);
else
Summ = getCommonMethodSummary(MD, S, RetTy);

View File

@ -1462,3 +1462,28 @@ extern void rdar_9234108_helper(void *key, void * CF_CONSUMED value);
void rdar_9234108() {
rdar_9234108_helper(0, CFStringCreate());
}
// <rdar://problem/9726279> - Make sure that objc_method_family works
// to override naming conventions.
struct TwoDoubles {
double one;
double two;
};
typedef struct TwoDoubles TwoDoubles;
@interface NSValue (Mine)
- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles __attribute__((objc_method_family(init)));
@end
@implementation NSValue (Mine)
- (id)_prefix_initWithTwoDoubles:(TwoDoubles)twoDoubles
{
return [self init];
}
@end
void rdar9726279() {
TwoDoubles twoDoubles = { 0.0, 0.0 };
NSValue *value = [[NSValue alloc] _prefix_initWithTwoDoubles:twoDoubles];
[value release];
}