Jordy Rose | 17a38e2 | 2011-09-02 05:55:19 +0000 | [diff] [blame] | 1 | // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s |
Jordy Rose | 5b5402b | 2011-07-15 22:17:54 +0000 | [diff] [blame] | 2 | |
John McCall | 4b9c2d2 | 2011-11-06 09:01:30 +0000 | [diff] [blame] | 3 | // This actually still works after the pseudo-object refactor, it just |
| 4 | // uses messages that say 'method' instead of 'property'. Ted wanted |
| 5 | // this xfailed and filed as a bug. rdar://problem/10402993 |
John McCall | 4b9c2d2 | 2011-11-06 09:01:30 +0000 | [diff] [blame] | 6 | |
Jordy Rose | 5b5402b | 2011-07-15 22:17:54 +0000 | [diff] [blame] | 7 | /*** |
| 8 | This file is for testing the path-sensitive notes for retain/release errors. |
| 9 | Its goal is to have simple branch coverage of any path-based diagnostics, |
| 10 | not to actually check all possible retain/release errors. |
| 11 | |
| 12 | This file includes notes that only appear in a ref-counted analysis. |
| 13 | GC-specific notes should go in retain-release-path-notes-gc.m. |
| 14 | ***/ |
| 15 | |
| 16 | @interface NSObject |
| 17 | + (id)alloc; |
| 18 | - (id)init; |
| 19 | - (void)dealloc; |
| 20 | |
| 21 | - (Class)class; |
| 22 | |
| 23 | - (id)retain; |
| 24 | - (void)release; |
| 25 | - (void)autorelease; |
| 26 | @end |
| 27 | |
| 28 | @interface Foo : NSObject |
| 29 | - (id)methodWithValue; |
| 30 | @property(retain) id propertyValue; |
| 31 | @end |
| 32 | |
| 33 | typedef struct CFType *CFTypeRef; |
| 34 | CFTypeRef CFRetain(CFTypeRef); |
| 35 | void CFRelease(CFTypeRef); |
| 36 | |
| 37 | id NSMakeCollectable(CFTypeRef); |
| 38 | CFTypeRef CFMakeCollectable(CFTypeRef); |
| 39 | |
| 40 | CFTypeRef CFCreateSomething(); |
| 41 | CFTypeRef CFGetSomething(); |
| 42 | |
| 43 | |
| 44 | void creationViaAlloc () { |
| 45 | id leaked = [[NSObject alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}} |
| 46 | return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} |
| 47 | } |
| 48 | |
| 49 | void creationViaCFCreate () { |
| 50 | CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} |
| 51 | return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} |
| 52 | } |
| 53 | |
| 54 | void acquisitionViaMethod (Foo *foo) { |
| 55 | id leaked = [foo methodWithValue]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +0 retain count}} |
| 56 | [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} |
| 57 | [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}} |
| 58 | [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}} |
| 59 | return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} |
| 60 | } |
| 61 | |
| 62 | void acquisitionViaProperty (Foo *foo) { |
| 63 | id leaked = foo.propertyValue; // expected-warning{{leak}} expected-note{{Property returns an Objective-C object with a +0 retain count}} |
| 64 | [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} |
| 65 | return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} |
| 66 | } |
| 67 | |
| 68 | void acquisitionViaCFFunction () { |
| 69 | CFTypeRef leaked = CFGetSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}} |
| 70 | CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}} |
| 71 | return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} |
| 72 | } |
| 73 | |
| 74 | void explicitDealloc () { |
| 75 | id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} |
| 76 | [object dealloc]; // expected-note{{Object released by directly sending the '-dealloc' message}} |
| 77 | [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}} |
| 78 | } |
| 79 | |
| 80 | void implicitDealloc () { |
| 81 | id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} |
| 82 | [object release]; // expected-note{{Object released}} |
| 83 | [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}} |
| 84 | } |
| 85 | |
| 86 | void overAutorelease () { |
| 87 | id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} |
| 88 | [object autorelease]; // expected-note{{Object sent -autorelease message}} |
| 89 | [object autorelease]; // expected-note{{Object sent -autorelease message}} |
| 90 | return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count}} |
| 91 | } |
| 92 | |
| 93 | void autoreleaseUnowned (Foo *foo) { |
| 94 | id object = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} |
| 95 | [object autorelease]; // expected-note{{Object sent -autorelease message}} |
| 96 | return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count}} |
| 97 | } |
| 98 | |
| 99 | void makeCollectableIgnored () { |
| 100 | CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} |
| 101 | CFMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument}} |
| 102 | NSMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument}} |
| 103 | return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} |
| 104 | } |
| 105 | |
| 106 | CFTypeRef CFCopyRuleViolation () { |
Richard Trieu | 2fe9b7f | 2011-12-15 00:38:15 +0000 | [diff] [blame^] | 107 | CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}} |
Jordy Rose | 5b5402b | 2011-07-15 22:17:54 +0000 | [diff] [blame] | 108 | return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} |
| 109 | } |
| 110 | |
| 111 | CFTypeRef CFGetRuleViolation () { |
Richard Trieu | 2fe9b7f | 2011-12-15 00:38:15 +0000 | [diff] [blame^] | 112 | CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} |
Jordy Rose | 5b5402b | 2011-07-15 22:17:54 +0000 | [diff] [blame] | 113 | return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is return from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given the Memory Management Guide for Core Foundation}} |
| 114 | } |
| 115 | |
| 116 | @implementation Foo (FundamentalMemoryManagementRules) |
| 117 | - (id)copyViolation { |
| 118 | id result = self.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} |
| 119 | return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} |
| 120 | } |
| 121 | |
| 122 | - (id)getViolation { |
| 123 | id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}} |
| 124 | return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa}} |
| 125 | } |
| 126 | @end |