Index: clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp +++ clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp @@ -686,9 +686,59 @@ return RetEffect::MakeNotOwned(RetEffect::Generalized); } + if (const auto *MD = dyn_cast(D)) + for (const auto *PD : MD->overridden_methods()) + if (auto RE = getRetEffectFromAnnotations(RetTy, PD)) + return RE; + return None; } +/// Apply the annotation of {@code pd} in function {@code FD} +/// to the resulting summary stored in out-parameter {@code Template}. +/// Return whether an annotation was applied. +bool applyFunctionParamAnnotationEffect(const ParmVarDecl *pd, + unsigned parm_idx, + const FunctionDecl *FD, + ArgEffects::Factory &AF, + RetainSummaryTemplate &Template) { + if (pd->hasAttr()) { + Template->addArg(AF, parm_idx, DecRefMsg); + return true; + } else if (pd->hasAttr() || pd->hasAttr() || + hasRCAnnotation(pd, "rc_ownership_consumed")) { + Template->addArg(AF, parm_idx, DecRef); + return true; + } else if (pd->hasAttr() || + hasRCAnnotation(pd, "rc_ownership_returns_retained")) { + QualType PointeeTy = pd->getType()->getPointeeType(); + if (!PointeeTy.isNull()) { + if (coreFoundation::isCFObjectRef(PointeeTy)) { + Template->addArg(AF, parm_idx, RetainedOutParameter); + return true; + } + } + } else if (pd->hasAttr()) { + QualType PointeeTy = pd->getType()->getPointeeType(); + if (!PointeeTy.isNull()) { + if (coreFoundation::isCFObjectRef(PointeeTy)) { + Template->addArg(AF, parm_idx, UnretainedOutParameter); + return true; + } + } + } else { + if (const auto *MD = dyn_cast(FD)) { + for (const auto *OD : MD->overridden_methods()) { + const ParmVarDecl *OP = OD->parameters()[parm_idx]; + if (applyFunctionParamAnnotationEffect(OP, parm_idx, MD, AF, Template)) + return true; + } + } + } + + return false; +} + void RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, const FunctionDecl *FD) { @@ -703,29 +753,15 @@ for (auto pi = FD->param_begin(), pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) { const ParmVarDecl *pd = *pi; - if (pd->hasAttr()) { - Template->addArg(AF, parm_idx, DecRefMsg); - } else if (pd->hasAttr() || - pd->hasAttr() || - hasRCAnnotation(pd, "rc_ownership_consumed")) { - Template->addArg(AF, parm_idx, DecRef); - } else if (pd->hasAttr() || - hasRCAnnotation(pd, "rc_ownership_returns_retained")) { - QualType PointeeTy = pd->getType()->getPointeeType(); - if (!PointeeTy.isNull()) - if (coreFoundation::isCFObjectRef(PointeeTy)) - Template->addArg(AF, parm_idx, RetainedOutParameter); - } else if (pd->hasAttr()) { - QualType PointeeTy = pd->getType()->getPointeeType(); - if (!PointeeTy.isNull()) - if (coreFoundation::isCFObjectRef(PointeeTy)) - Template->addArg(AF, parm_idx, UnretainedOutParameter); - } + applyFunctionParamAnnotationEffect(pd, parm_idx, FD, AF, Template); } QualType RetTy = FD->getReturnType(); if (Optional RetE = getRetEffectFromAnnotations(RetTy, FD)) Template->setRetEffect(*RetE); + + if (FD->hasAttr()) + Template->setThisEffect(DecRef); } void Index: clang/test/Analysis/osobject-retain-release.cpp =================================================================== --- clang/test/Analysis/osobject-retain-release.cpp +++ clang/test/Analysis/osobject-retain-release.cpp @@ -21,12 +21,13 @@ unsigned int foo() { return 42; } + virtual OS_RETURNS_NOT_RETAINED OSObject *identity(); + static OSObject *generateObject(int); static OSObject *getObject(); static OSObject *GetObject(); - static void * operator new(size_t size); static const OSMetaClass * const metaClass; @@ -40,6 +41,11 @@ struct OSArray : public OSObject { unsigned int getCount(); + OSIterator * getIterator(); + + OSObject *identity() override; + + virtual void consumeReference(OS_CONSUME OSArray *other); static OSArray *generateArrayHasCode() { return new OSArray; } @@ -59,6 +65,12 @@ static const OSMetaClass * const metaClass; }; +struct MyArray : public OSArray { + void consumeReference(OSArray *other) override; + + OSObject *identity() override; +}; + struct OtherStruct { static void doNothingToArray(OSArray *array); OtherStruct(OSArray *arr); @@ -68,6 +80,26 @@ static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); }; +void check_param_attribute_propagation(MyArray *parent) { + OSArray *arr = new OSArray; + parent->consumeReference(arr); +} + +unsigned int check_attribute_propagation(OSArray *arr) { + OSObject *other = arr->identity(); + OSArray *casted = OSDynamicCast(OSArray, other); + if (casted) + return casted->getCount(); + return 0; +} + +unsigned int check_attribute_indirect_propagation(MyArray *arr) { + OSObject *other = arr->identity(); + OSArray *casted = OSDynamicCast(OSArray, other); + if (casted) + return casted->getCount(); + return 0; +} void check_free_no_error() { OSArray *arr = OSArray::withCapacity(10); arr->retain();