Home | History | Annotate | Download | only in Analysis
      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
      2 
      3 /***
      4 This file is for testing the path-sensitive notes for retain/release errors.
      5 Its goal is to have simple branch coverage of any path-based diagnostics,
      6 not to actually check all possible retain/release errors.
      7 
      8 This file includes notes that only appear in a ref-counted analysis. 
      9 GC-specific notes should go in retain-release-path-notes-gc.m.
     10 ***/
     11 
     12 @interface NSObject
     13 + (id)alloc;
     14 - (id)init;
     15 - (void)dealloc;
     16 
     17 - (Class)class;
     18 
     19 - (id)retain;
     20 - (void)release;
     21 - (void)autorelease;
     22 @end
     23 
     24 @interface Foo : NSObject
     25 - (id)methodWithValue;
     26 @property(retain) id propertyValue;
     27 @end
     28 
     29 typedef struct CFType *CFTypeRef;
     30 CFTypeRef CFRetain(CFTypeRef);
     31 void CFRelease(CFTypeRef);
     32 
     33 id NSMakeCollectable(CFTypeRef);
     34 CFTypeRef CFMakeCollectable(CFTypeRef);
     35 
     36 CFTypeRef CFCreateSomething();
     37 CFTypeRef CFGetSomething();
     38 
     39 
     40 void creationViaAlloc () {
     41   id leaked = [[NSObject alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
     42   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}}
     43 }
     44 
     45 void creationViaCFCreate () {
     46   CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
     47   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}}
     48 }
     49 
     50 void acquisitionViaMethod (Foo *foo) {
     51   id leaked = [foo methodWithValue]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +0 retain count}}
     52   [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
     53   [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}}
     54   [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}}
     55   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}}
     56 }
     57 
     58 void acquisitionViaProperty (Foo *foo) {
     59   id leaked = foo.propertyValue; // expected-warning{{leak}} expected-note{{Property returns an Objective-C object with a +0 retain count}}
     60   [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
     61   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}}
     62 }
     63 
     64 void acquisitionViaCFFunction () {
     65   CFTypeRef leaked = CFGetSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
     66   CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}}
     67   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}}
     68 }
     69 
     70 void explicitDealloc () {
     71   id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
     72   [object dealloc]; // expected-note{{Object released by directly sending the '-dealloc' message}}
     73   [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
     74 }
     75 
     76 void implicitDealloc () {
     77   id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
     78   [object release]; // expected-note{{Object released}}
     79   [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
     80 }
     81 
     82 void overAutorelease () {
     83   id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
     84   [object autorelease]; // expected-note{{Object sent -autorelease message}}
     85   [object autorelease]; // expected-note{{Object sent -autorelease message}} 
     86   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}} 
     87 }
     88 
     89 void autoreleaseUnowned (Foo *foo) {
     90   id object = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
     91   [object autorelease]; // expected-note{{Object sent -autorelease message}} 
     92   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}}
     93 }
     94 
     95 void makeCollectableIgnored () {
     96   CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
     97   CFMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument}}
     98   NSMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument}}
     99   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}}
    100 }
    101 
    102 CFTypeRef CFCopyRuleViolation () {
    103   CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain counte}}
    104   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}}
    105 }
    106 
    107 CFTypeRef CFGetRuleViolation () {
    108   CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain counte}}
    109   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}}
    110 }
    111 
    112 @implementation Foo (FundamentalMemoryManagementRules)
    113 - (id)copyViolation {
    114   id result = self.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
    115   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}}
    116 }
    117 
    118 - (id)getViolation {
    119   id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
    120   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}}
    121 }
    122 @end
    123