summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2014-01-10 20:06:06 +0000
committerJordan Rose <jordan_rose@apple.com>2014-01-10 20:06:06 +0000
commit1a866cd54b5c4b63d3be6f76ba6585bd262b99b7 (patch)
tree50157164678f435ae9993157e954e57773865451 /clang/test
parent26cb6d90b8dd184dbbe6ace171320871aac5f94b (diff)
downloadbcm5719-llvm-1a866cd54b5c4b63d3be6f76ba6585bd262b99b7.tar.gz
bcm5719-llvm-1a866cd54b5c4b63d3be6f76ba6585bd262b99b7.zip
[analyzer] Model getters of known-@synthesized Objective-C properties.
...by synthesizing their body to be "return self->_prop;", with an extra nudge to RetainCountChecker to still treat the value as +0 if we have no other information. This doesn't handle weak properties, but that's mostly correct anyway, since they can go to nil at any time. This also doesn't apply to properties whose implementations we can't see, since they may not be backed by an ivar at all. And finally, this doesn't handle properties of C++ class type, because we can't invoke the copy constructor. (Sema has actually done this work already, but the AST it synthesizes is one the analyzer doesn't quite handle -- it has an rvalue DeclRefExpr.) Modeling setters is likely to be more difficult (since it requires handling strong/copy), but not impossible. <rdar://problem/11956898> llvm-svn: 198953
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/Analysis/properties.m81
-rw-r--r--clang/test/Analysis/properties.mm80
2 files changed, 160 insertions, 1 deletions
diff --git a/clang/test/Analysis/properties.m b/clang/test/Analysis/properties.m
index ddd0068d369..b3e654f377a 100644
--- a/clang/test/Analysis/properties.m
+++ b/clang/test/Analysis/properties.m
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -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 %s
+
+void clang_analyzer_eval(int);
typedef signed char BOOL;
typedef unsigned int NSUInteger;
@@ -14,6 +16,7 @@ typedef struct _NSZone NSZone;
-(id)autorelease;
-(id)copy;
-(id)retain;
+-(oneway void)release;
@end
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
- (NSUInteger)length;
@@ -166,3 +169,79 @@ void rdar6611873() {
@end
+//------
+// Property accessor synthesis
+//------
+
+void testConsistency(Person *p) {
+ clang_analyzer_eval(p.name == p.name); // expected-warning{{TRUE}}
+
+ extern void doSomethingWithPerson(Person *p);
+ id origName = p.name;
+ clang_analyzer_eval(p.name == origName); // expected-warning{{TRUE}}
+ doSomethingWithPerson(p);
+ clang_analyzer_eval(p.name == origName); // expected-warning{{UNKNOWN}}
+}
+
+void testOverrelease(Person *p) {
+ [p.name release]; // expected-warning{{not owned}}
+}
+
+@interface IntWrapper
+@property int value;
+@end
+
+@implementation IntWrapper
+@synthesize value;
+@end
+
+void testConsistencyInt(IntWrapper *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 testConsistencyInt2(IntWrapper *w) {
+ if (w.value != 42)
+ return;
+
+ clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
+}
+
+typedef struct {
+ int value;
+} IntWrapperStruct;
+
+@interface StructWrapper
+@property IntWrapperStruct inner;
+@end
+
+@implementation StructWrapper
+@synthesize inner;
+@end
+
+void testConsistencyStruct(StructWrapper *w) {
+ clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{TRUE}}
+
+ int origValue = w.inner.value;
+ if (origValue != 42)
+ return;
+
+ clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}}
+}
+
+
+@interface OpaqueIntWrapper
+@property int value;
+@end
+
+// For now, don't assume a property is implemented using an ivar unless we can
+// actually see that it is.
+void testOpaqueConsistency(OpaqueIntWrapper *w) {
+ clang_analyzer_eval(w.value == w.value); // expected-warning{{UNKNOWN}}
+}
+
diff --git a/clang/test/Analysis/properties.mm b/clang/test/Analysis/properties.mm
new file mode 100644
index 00000000000..dd44219856f
--- /dev/null
+++ b/clang/test/Analysis/properties.mm
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
+
+void clang_analyzer_eval(bool);
+void clang_analyzer_checkInlined(bool);
+
+@interface IntWrapper
+@property (readonly) int &value;
+@end
+
+@implementation IntWrapper
+@synthesize value;
+@end
+
+void testReferenceConsistency(IntWrapper *w) {
+ clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&w.value == &w.value); // expected-warning{{TRUE}}
+
+ if (w.value != 42)
+ return;
+
+ clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
+}
+
+void testReferenceAssignment(IntWrapper *w) {
+ w.value = 42;
+ clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
+}
+
+
+// FIXME: Handle C++ structs, which need to go through the copy constructor.
+
+struct IntWrapperStruct {
+ int value;
+};
+
+@interface StructWrapper
+@property IntWrapperStruct inner;
+@end
+
+@implementation StructWrapper
+@synthesize inner;
+@end
+
+void testConsistencyStruct(StructWrapper *w) {
+ clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{UNKNOWN}}
+
+ int origValue = w.inner.value;
+ if (origValue != 42)
+ return;
+
+ clang_analyzer_eval(w.inner.value == 42); // expected-warning{{UNKNOWN}}
+}
+
+
+class CustomCopy {
+public:
+ CustomCopy() : value(0) {}
+ CustomCopy(const CustomCopy &other) {
+ clang_analyzer_checkInlined(false);
+ }
+ int value;
+};
+
+@interface CustomCopyWrapper
+@property CustomCopy inner;
+@end
+
+@implementation CustomCopyWrapper
+@synthesize inner;
+@end
+
+void testConsistencyCustomCopy(CustomCopyWrapper *w) {
+ clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{UNKNOWN}}
+
+ int origValue = w.inner.value;
+ if (origValue != 42)
+ return;
+
+ clang_analyzer_eval(w.inner.value == 42); // expected-warning{{UNKNOWN}}
+}
OpenPOWER on IntegriCloud