diff options
| author | Jordan Rose <jordan_rose@apple.com> | 2014-01-10 20:06:06 +0000 |
|---|---|---|
| committer | Jordan Rose <jordan_rose@apple.com> | 2014-01-10 20:06:06 +0000 |
| commit | 1a866cd54b5c4b63d3be6f76ba6585bd262b99b7 (patch) | |
| tree | 50157164678f435ae9993157e954e57773865451 /clang/test | |
| parent | 26cb6d90b8dd184dbbe6ace171320871aac5f94b (diff) | |
| download | bcm5719-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.m | 81 | ||||
| -rw-r--r-- | clang/test/Analysis/properties.mm | 80 |
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}} +} |

