static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
const ObjCPropertyDecl *Prop) {
+ // First, find the backing ivar.
const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
if (!IVar)
return 0;
+
+ // Ignore weak variables, which have special behavior.
if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
return 0;
+ // Look to see if Sema has synthesized a body for us. This happens in
+ // Objective-C++ because the return value may be a C++ class type with a
+ // non-trivial copy constructor. We can only do this if we can find the
+ // @synthesize for this property, though (or if we know it's been auto-
+ // synthesized).
const ObjCImplementationDecl *ImplDecl =
IVar->getContainingInterface()->getImplementation();
if (ImplDecl) {
}
}
- if (IVar->getType().getCanonicalType() !=
- Prop->getType().getNonReferenceType().getCanonicalType())
+ // Sanity check that the property is the same type as the ivar, or a
+ // reference to it, and that it is either an object pointer or trivially
+ // copyable.
+ if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
+ Prop->getType().getNonReferenceType()))
+ return 0;
+ if (!IVar->getType()->isObjCLifetimeType() &&
+ !IVar->getType().isTriviallyCopyableType(Ctx))
return 0;
+ // Generate our body:
+ // return self->_ivar;
ASTMaker M(Ctx);
const VarDecl *selfVar = Prop->getGetterMethodDecl()->getSelfDecl();
return M.makeReturn(loadedIVar);
}
-Stmt *BodyFarm::getBody(const ObjCMethodDecl *D, const ObjCPropertyDecl *Prop) {
+Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
+ // We currently only know how to synthesize property accessors.
if (!D->isPropertyAccessor())
return 0;
return Val.getValue();
Val = 0;
- if (!Prop)
- Prop = D->findPropertyDecl();
+ const ObjCPropertyDecl *Prop = D->findPropertyDecl();
if (!Prop)
return 0;
+ // For now, we only synthesize getters.
if (D->param_size() != 0)
return 0;
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s
void clang_analyzer_eval(int);
@end
+#if !__has_feature(objc_arc)
+
@implementation Test1
@synthesize text;
return [result autorelease]; // expected-warning {{Object autoreleased too many times}}
}
+#endif
+
// rdar://6611873
NSString *_name;
}
@property (retain) NSString * name;
+@property (assign) id friend;
@end
@implementation Person
@synthesize name = _name;
@end
+#if !__has_feature(objc_arc)
void rdar6611873() {
Person *p = [[[Person alloc] init] autorelease];
p.name = [[NSString string] retain]; // expected-warning {{leak}}
p.name = [[NSString alloc] init]; // expected-warning {{leak}}
+
+ p.friend = [[Person alloc] init]; // expected-warning {{leak}}
}
+#endif
@interface SubPerson : Person
-(NSString *)foo;
}
@end
+
+#if !__has_feature(objc_arc)
// <rdar://problem/9241180> Static analyzer doesn't detect uninitialized variable issues for property accesses
@interface RDar9241180
@property (readwrite,assign) id x;
self.x = y; // expected-warning {{Argument for property setter is an uninitialized value}}
}
@end
+#endif
//------
// Property accessor synthesis
//------
-void testConsistency(Person *p) {
+void testConsistencyRetain(Person *p) {
clang_analyzer_eval(p.name == p.name); // expected-warning{{TRUE}}
extern void doSomethingWithPerson(Person *p);
clang_analyzer_eval(p.name == origName); // expected-warning{{UNKNOWN}}
}
-void testOverrelease(Person *p) {
- [p.name release]; // expected-warning{{not owned}}
+void testConsistencyAssign(Person *p) {
+ clang_analyzer_eval(p.friend == p.friend); // expected-warning{{TRUE}}
+
+ extern void doSomethingWithPerson(Person *p);
+ id origFriend = p.friend;
+ clang_analyzer_eval(p.friend == origFriend); // expected-warning{{TRUE}}
+ doSomethingWithPerson(p);
+ clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}}
+}
+
+#if !__has_feature(objc_arc)
+void testOverrelease(Person *p, int coin) {
+ if (coin)
+ [p.name release]; // expected-warning{{not owned}}
+ else
+ [p.friend release]; // expected-warning{{not owned}}
}
+#endif
@interface IntWrapper
@property int value;
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
}
+
+@interface IntWrapperAuto
+@property int value;
+@end
+
+@implementation IntWrapperAuto
+@end
+
+void testConsistencyIntAuto(IntWrapperAuto *w) {
+ clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
+
+ int origValue = w.value;
+ if (origValue != 42)
+ return;
+
+ clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
+}
+
+void testConsistencyIntAuto2(IntWrapperAuto *w) {
+ if (w.value != 42)
+ return;
+
+ clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
+}
+
+
typedef struct {
int value;
} IntWrapperStruct;
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
}
-// FIXME: Handle C++ structs, which need to go through the copy constructor.
-
struct IntWrapperStruct {
int value;
};
@end
@implementation CustomCopyWrapper
-@synthesize inner;
+//@synthesize inner;
@end
void testConsistencyCustomCopy(CustomCopyWrapper *w) {