return RetEffect::MakeNotOwned(RetEffect::Generalized);
}
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(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<NSConsumedAttr>()) {
+ Template->addArg(AF, parm_idx, DecRefMsg);
+ return true;
+ } else if (pd->hasAttr<CFConsumedAttr>() || pd->hasAttr<OSConsumedAttr>() ||
+ hasRCAnnotation(pd, "rc_ownership_consumed")) {
+ Template->addArg(AF, parm_idx, DecRef);
+ return true;
+ } else if (pd->hasAttr<CFReturnsRetainedAttr>() ||
+ 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<CFReturnsNotRetainedAttr>()) {
+ 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<CXXMethodDecl>(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) {
for (auto pi = FD->param_begin(),
pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) {
const ParmVarDecl *pd = *pi;
- if (pd->hasAttr<NSConsumedAttr>()) {
- Template->addArg(AF, parm_idx, DecRefMsg);
- } else if (pd->hasAttr<CFConsumedAttr>() ||
- pd->hasAttr<OSConsumedAttr>() ||
- hasRCAnnotation(pd, "rc_ownership_consumed")) {
- Template->addArg(AF, parm_idx, DecRef);
- } else if (pd->hasAttr<CFReturnsRetainedAttr>() ||
- 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<CFReturnsNotRetainedAttr>()) {
- 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();
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;
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;
}
return nullptr;
}
- OSIterator * getIterator();
-
static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
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);
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();