summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Analysis/BodyFarm.cpp27
-rw-r--r--clang/lib/Analysis/BodyFarm.h2
-rw-r--r--clang/test/Analysis/properties.m60
-rw-r--r--clang/test/Analysis/properties.mm5
4 files changed, 82 insertions, 12 deletions
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index 6ec63c72217..737e15061e1 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -387,12 +387,20 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
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) {
@@ -410,10 +418,18 @@ static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
}
}
- 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();
@@ -431,7 +447,8 @@ static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
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;
@@ -442,11 +459,11 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D, const ObjCPropertyDecl *Prop) {
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;
diff --git a/clang/lib/Analysis/BodyFarm.h b/clang/lib/Analysis/BodyFarm.h
index c4f3d1599e7..2d200fb755c 100644
--- a/clang/lib/Analysis/BodyFarm.h
+++ b/clang/lib/Analysis/BodyFarm.h
@@ -36,7 +36,7 @@ public:
Stmt *getBody(const FunctionDecl *D);
/// Factory method for creating bodies for Objective-C properties.
- Stmt *getBody(const ObjCMethodDecl *D, const ObjCPropertyDecl *Prop = 0);
+ Stmt *getBody(const ObjCMethodDecl *D);
private:
typedef llvm::DenseMap<const Decl *, Optional<Stmt *> > BodyMap;
diff --git a/clang/test/Analysis/properties.m b/clang/test/Analysis/properties.m
index b3e654f377a..5ac20c18c94 100644
--- a/clang/test/Analysis/properties.m
+++ b/clang/test/Analysis/properties.m
@@ -1,4 +1,5 @@
// 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);
@@ -39,6 +40,8 @@ typedef struct _NSZone NSZone;
@end
+#if !__has_feature(objc_arc)
+
@implementation Test1
@synthesize text;
@@ -117,6 +120,8 @@ NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber)
return [result autorelease]; // expected-warning {{Object autoreleased too many times}}
}
+#endif
+
// rdar://6611873
@@ -124,18 +129,23 @@ NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber)
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;
@@ -147,6 +157,8 @@ void rdar6611873() {
}
@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;
@@ -167,13 +179,14 @@ void rdar6611873() {
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);
@@ -183,9 +196,24 @@ void testConsistency(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;
@@ -212,6 +240,32 @@ void testConsistencyInt2(IntWrapper *w) {
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;
diff --git a/clang/test/Analysis/properties.mm b/clang/test/Analysis/properties.mm
index 57aacd4f9d2..e49d034f265 100644
--- a/clang/test/Analysis/properties.mm
+++ b/clang/test/Analysis/properties.mm
@@ -1,4 +1,5 @@
// 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);
@@ -27,8 +28,6 @@ void testReferenceAssignment(IntWrapper *w) {
}
-// FIXME: Handle C++ structs, which need to go through the copy constructor.
-
struct IntWrapperStruct {
int value;
};
@@ -66,7 +65,7 @@ public:
@end
@implementation CustomCopyWrapper
-@synthesize inner;
+//@synthesize inner;
@end
void testConsistencyCustomCopy(CustomCopyWrapper *w) {
OpenPOWER on IntegriCloud