diff options
author | Ted Kremenek <kremenek@apple.com> | 2011-01-27 06:54:14 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2011-01-27 06:54:14 +0000 |
commit | 12b9434d5bf801e24242b1f6fd04899f8a7fa92c (patch) | |
tree | 0ec00000d3d8b704bc4ed229fec30fa3b64b1865 | |
parent | eb7a779365c08f8f363e679a9f9fa389f22c7982 (diff) |
Hook up attribute ns_consumes_self in the ObjC retain/release checker in the static analyzer.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124360 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-rw-r--r-- | lib/StaticAnalyzer/CFRefCount.cpp | 9 | ||||
-rw-r--r-- | test/Analysis/retain-release.m | 19 | ||||
-rw-r--r-- | www/analyzer/annotations.html | 33 |
4 files changed, 61 insertions, 1 deletions
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 7727eafd73..c7233344f4 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -536,6 +536,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("attribute_ext_vector_type", true) .Case("attribute_ns_returns_not_retained", true) .Case("attribute_ns_returns_retained", true) + .Case("attribute_ns_consumes_self", true) .Case("attribute_objc_ivar_unused", true) .Case("attribute_overloadable", true) .Case("attribute_unavailable_with_message", true) diff --git a/lib/StaticAnalyzer/CFRefCount.cpp b/lib/StaticAnalyzer/CFRefCount.cpp index 473b7313bb..546687a7a2 100644 --- a/lib/StaticAnalyzer/CFRefCount.cpp +++ b/lib/StaticAnalyzer/CFRefCount.cpp @@ -467,6 +467,10 @@ public: /// terminate the path. bool isEndPath() const { return EndPath; } + + /// Sets the effect on the receiver of the message. + void setReceiverEffect(ArgEffect e) { Receiver = e; } + /// getReceiverEffect - Returns the effect on the receiver of the call. /// This is only meaningful if the summary applies to an ObjCMessageExpr*. ArgEffect getReceiverEffect() const { return Receiver; } @@ -1219,6 +1223,11 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, bool isTrackedLoc = false; + // Effects on the receiver. + if (MD->getAttr<NSConsumesSelfAttr>()) { + Summ.setReceiverEffect(DecRefMsg); + } + // Determine if there is a special return effect for this method. if (cocoa::isCocoaObjectRef(MD->getResultType())) { if (MD->getAttr<NSReturnsRetainedAttr>()) { diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index eefd132282..e68e4d7e75 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -13,6 +13,9 @@ #if __has_feature(attribute_cf_returns_not_retained) #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) #endif +#if __has_feature(attribute_ns_consumes_self) +#define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) +#endif //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from Mac OS X headers: @@ -1211,6 +1214,7 @@ typedef NSString* MyStringTy; - (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning - (NSString*) newStringNoAttr; - (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}} +- (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED; @end static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}} @@ -1228,6 +1232,19 @@ void test_attr1c(TestOwnershipAttr *X) { NSString *str2 = [X newStringNoAttr]; // expected-warning{{leak}} } +void testattr2_a() { + TestOwnershipAttr *x = [TestOwnershipAttr alloc]; // expected-warning{{leak}} +} + +void testattr2_b() { + TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // expected-warning{{leak}} +} + +void testattr2_c() { + TestOwnershipAttr *x = [[TestOwnershipAttr alloc] pseudoInit]; // no-warning + [x release]; +} + @interface MyClassTestCFAttr : NSObject {} - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED; - (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED; @@ -1401,7 +1418,7 @@ static void rdar_8724287(CFErrorRef error) while (error_to_dump != ((void*)0)) { CFDictionaryRef info; - info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1404 and stored into 'info'}} + info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1421 and stored into 'info'}} if (info != ((void*)0)) { } diff --git a/www/analyzer/annotations.html b/www/analyzer/annotations.html index f43e361cca..b2182eb934 100644 --- a/www/analyzer/annotations.html +++ b/www/analyzer/annotations.html @@ -56,6 +56,7 @@ recognized by GCC. Their use can be conditioned using preprocessor macros <li><a href="#attr_ns_returns_not_retained">Attribute 'ns_returns_not_retained'</a></li> <li><a href="#attr_cf_returns_retained">Attribute 'cf_returns_retained'</a></li> <li><a href="#attr_cf_returns_not_retained">Attribute 'cf_returns_not_retained'</a></li> + <li><a href="#attr_ns_consumes_self">Attribute 'ns_consumes_self'</a></li> </ul> </li> </ul> @@ -350,6 +351,38 @@ its availability, as it is not available in earlier versions of the analyzer:</p #endif </pre> +<h4 id="attr_ns_consumes_self">Attribute 'ns_consumes_self' +(Clang-specific)</h4> + +<p>The 'ns_consumes_self' attribute can be placed only on an Objective-C method declaration. + It indicates that the receiver of the message is "consumed" (a single reference count decremented) + after the message is sent. This matches the semantics of all "init" methods. +</p> + +<p>One use of this attribute is declare your own init-like methods that do not follow the + standard Cocoa naming conventions. For example:</p> + +<pre class="code_example"> +#ifndef __has_feature +#define __has_Feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef NS_CONSUMES_SELF +#if __has_feature((attribute_ns_consumes_self)) +#else +#define NS_CONSUMES_SELF +#endif +#endif + +@interface MyClass : NSObject +- initWith:(MyClass *)x; +- nonstandardInitWith:(MyClass *)x NS_CONSUMES_SELF NS_RETURNS_RETAINED; +@end +</pre> + +<p>In this example, <tt>nonstandardInitWith:</tt> has the same ownership semantics as the init method <tt>initWith:</tt>. + The static analyzer will observe that the method consumes the receiver, and then returns an object with a +1 retain count.</p> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <h2 id="custom_assertions">Custom Assertion Handlers</h2> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> |