Index: include/clang/StaticAnalyzer/Core/RetainSummaryManager.h =================================================================== --- include/clang/StaticAnalyzer/Core/RetainSummaryManager.h +++ include/clang/StaticAnalyzer/Core/RetainSummaryManager.h @@ -369,8 +369,12 @@ /// This is only meaningful if the summary applies to an ObjCMessageExpr*. ArgEffect getReceiverEffect() const { return Receiver; } + /// \return the effect on the "this" receiver of the method call. ArgEffect getThisEffect() const { return This; } + /// Set the effect of the method on "this". + void setThisEffect(ArgEffect e) { This = e; } + bool isNoop() const { return Ret == RetEffect::MakeNoRet() && Receiver == DoNothing && DefaultArgEffect == MayEscape && This == DoNothing Index: lib/StaticAnalyzer/Core/RetainSummaryManager.cpp =================================================================== --- lib/StaticAnalyzer/Core/RetainSummaryManager.cpp +++ lib/StaticAnalyzer/Core/RetainSummaryManager.cpp @@ -759,6 +759,9 @@ QualType RetTy = FD->getReturnType(); if (Optional RetE = getRetEffectFromAnnotations(RetTy, FD)) Template->setRetEffect(*RetE); + + if (FD->hasAttr()) + Template->setThisEffect(DecRef); } void Index: test/Analysis/osobject-retain-release.cpp =================================================================== --- test/Analysis/osobject-retain-release.cpp +++ test/Analysis/osobject-retain-release.cpp @@ -5,6 +5,7 @@ #define OS_CONSUME __attribute__((os_consumed)) #define OS_RETURNS_RETAINED __attribute__((os_returns_retained)) #define OS_RETURNS_NOT_RETAINED __attribute__((os_returns_not_retained)) +#define OS_CONSUMES_THIS __attribute__((os_consumes_this)) #define OSTypeID(type) (type::metaClass) @@ -49,6 +50,11 @@ virtual void consumeReference(OS_CONSUME OSArray *other); + void putIntoArray(OSArray *array) OS_CONSUMES_THIS; + + template + void putIntoT(T *owner) OS_CONSUMES_THIS; + static OSArray *generateArrayHasCode() { return new OSArray; } @@ -112,6 +118,16 @@ return 0; } +void check_consumes_this(OSArray *owner) { + OSArray *arr = new OSArray; + arr->putIntoArray(owner); +} + +void check_consumes_this_with_template(OSArray *owner) { + OSArray *arr = new OSArray; + arr->putIntoT(owner); +} + void check_free_no_error() { OSArray *arr = OSArray::withCapacity(10); arr->retain();