[analyzer] Attribute for RetainCountChecker for OSObject should propagate with inheri...
authorGeorge Karpenkov <ekarpenkov@apple.com>
Wed, 5 Dec 2018 18:34:54 +0000 (18:34 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Wed, 5 Dec 2018 18:34:54 +0000 (18:34 +0000)
rdar://46388388

Differential Revision: https://reviews.llvm.org/D55154

llvm-svn: 348396

clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
clang/test/Analysis/osobject-retain-release.cpp

index b42e0c1..2bdfd2d 100644 (file)
@@ -686,9 +686,59 @@ RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
     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) {
@@ -703,24 +753,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
   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();
index 1b54008..398857f 100644 (file)
@@ -21,12 +21,13 @@ struct OSObject {
 
   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,12 @@ struct OSIterator : public OSObject {
 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;
   }
@@ -51,14 +58,18 @@ struct OSArray : public OSObject {
     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);
@@ -68,6 +79,27 @@ struct OSMetaClassBase {
   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();