]> granicus.if.org Git - clang/commitdiff
[analyzer] [RetainCountChecker] [NFC] Refactor the way attributes are handled
authorGeorge Karpenkov <ekarpenkov@apple.com>
Thu, 10 Jan 2019 18:14:51 +0000 (18:14 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Thu, 10 Jan 2019 18:14:51 +0000 (18:14 +0000)
Make sure all checks for attributes go through a centralized function,
which checks whether attribute handling is enabled, and performs
validation.  The type of the attribute is returned.

Sadly, metaprogramming is required as attributes have no sensible static
getters.

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@350862 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/RetainSummaryManager.h
lib/StaticAnalyzer/Core/RetainSummaryManager.cpp

index 809789c2314088955434bb904f8cc0ffc6cc8167..65648e44d489f53dce44a2e911a41b8cd5c5a4f5 100644 (file)
@@ -741,16 +741,18 @@ public:
 
   RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
 
-  /// \return True if the declaration has an attribute {@code T},
-  /// AND we are tracking that attribute. False otherwise.
+  /// Determine whether a declaration {@code D} of correspondent type (return
+  /// type for functions/methods) {@code QT} has any of the given attributes,
+  /// provided they pass necessary validation checks AND tracking the given
+  /// attribute is enabled.
+  /// Returns the object kind corresponding to the present attribute, or None,
+  /// if none of the specified attributes are present.
+  /// Crashes if passed an attribute which is not explicitly handled.
   template <class T>
-  bool hasEnabledAttr(const Decl *D) {
-    return isAttrEnabled<T>() && D->hasAttr<T>();
-  }
+  Optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT);
 
-  /// Check whether we are tracking properties specified by the attributes.
-  template <class T>
-  bool isAttrEnabled();
+  template <class T1, class T2, class... Others>
+  Optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT);
 
   friend class RetainSummaryTemplate;
 };
index 51fa760ab5548ba6a8e7a99b2a3f69540f58ac45..a0fe2fefde821f2e91a7df6f79b67a4452e16866 100644 (file)
@@ -36,17 +36,79 @@ constexpr static bool isOneOf() {
   return std::is_same<T, P>::value || isOneOf<T, ToCompare...>();
 }
 
-template <class T> bool RetainSummaryManager::isAttrEnabled() {
+namespace {
+
+struct GeneralizedReturnsRetainedAttr {
+  static bool classof(const Attr *A) {
+    if (auto AA = dyn_cast<AnnotateAttr>(A))
+      return AA->getAnnotation() == "rc_ownership_returns_retained";
+    return false;
+  }
+};
+
+struct GeneralizedReturnsNotRetainedAttr {
+  static bool classof(const Attr *A) {
+    if (auto AA = dyn_cast<AnnotateAttr>(A))
+      return AA->getAnnotation() == "rc_ownership_returns_not_retained";
+    return false;
+  }
+};
+
+struct GeneralizedConsumedAttr {
+  static bool classof(const Attr *A) {
+    if (auto AA = dyn_cast<AnnotateAttr>(A))
+      return AA->getAnnotation() == "rc_ownership_consumed";
+    return false;
+  }
+};
+
+}
+
+template <class T>
+Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
+                                                            QualType QT) {
+  ObjKind K;
   if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr,
-              CFReturnsNotRetainedAttr, NSConsumedAttr, NSConsumesSelfAttr,
-              NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr,
-              NSReturnsNotRetainedAttr>()) {
-    return TrackObjCAndCFObjects;
+              CFReturnsNotRetainedAttr>()) {
+    if (!TrackObjCAndCFObjects)
+      return None;
+
+    K = ObjKind::CF;
+  } else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr,
+                     NSReturnsAutoreleasedAttr, NSReturnsRetainedAttr,
+                     NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) {
+
+    if (!TrackObjCAndCFObjects)
+      return None;
+
+    if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr,
+                NSReturnsNotRetainedAttr>() &&
+        !cocoa::isCocoaObjectRef(QT))
+      return None;
+    K = ObjKind::ObjC;
   } else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr,
                      OSReturnsNotRetainedAttr, OSReturnsRetainedAttr>()) {
-    return TrackOSObjects;
+    if (!TrackOSObjects)
+      return None;
+    K = ObjKind::OS;
+  } else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr,
+                     GeneralizedReturnsRetainedAttr,
+                     GeneralizedConsumedAttr>()) {
+    K = ObjKind::Generalized;
+  } else {
+    llvm_unreachable("Unexpected attribute");
   }
-  llvm_unreachable("Unexpected attribute passed");
+  if (D->hasAttr<T>())
+    return K;
+  return None;
+}
+
+template <class T1, class T2, class... Others>
+Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
+                                                            QualType QT) {
+  if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT))
+    return Out;
+  return hasAnyEnabledAttrOf<T2, Others...>(D, QT);
 }
 
 const RetainSummary *
@@ -727,33 +789,18 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
 Optional<RetEffect>
 RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
                                                   const Decl *D) {
-  if (TrackObjCAndCFObjects && cocoa::isCocoaObjectRef(RetTy)) {
-    if (D->hasAttr<NSReturnsRetainedAttr>())
-      return ObjCAllocRetE;
-
-    if (D->hasAttr<NSReturnsNotRetainedAttr>() ||
-        D->hasAttr<NSReturnsAutoreleasedAttr>())
-      return RetEffect::MakeNotOwned(ObjKind::ObjC);
-
-  } else if (!RetTy->isPointerType()) {
-    return None;
-  }
+  if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy))
+    return ObjCAllocRetE;
 
-  if (hasEnabledAttr<CFReturnsRetainedAttr>(D)) {
-    return RetEffect::MakeOwned(ObjKind::CF);
-  } else if (hasEnabledAttr<OSReturnsRetainedAttr>(D)) {
-    return RetEffect::MakeOwned(ObjKind::OS);
-  } else if (hasRCAnnotation(D, "rc_ownership_returns_retained")) {
-    return RetEffect::MakeOwned(ObjKind::Generalized);
-  }
+  if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr, OSReturnsRetainedAttr,
+                                   GeneralizedReturnsRetainedAttr>(D, RetTy))
+    return RetEffect::MakeOwned(*K);
 
-  if (hasEnabledAttr<CFReturnsNotRetainedAttr>(D)) {
-    return RetEffect::MakeNotOwned(ObjKind::CF);
-  } else if (hasEnabledAttr<OSReturnsNotRetainedAttr>(D)) {
-    return RetEffect::MakeNotOwned(ObjKind::OS);
-  } else if (hasRCAnnotation(D, "rc_ownership_returns_not_retained")) {
-    return RetEffect::MakeNotOwned(ObjKind::Generalized);
-  }
+  if (auto K = hasAnyEnabledAttrOf<
+          CFReturnsNotRetainedAttr, OSReturnsNotRetainedAttr,
+          GeneralizedReturnsNotRetainedAttr, NSReturnsNotRetainedAttr,
+          NSReturnsAutoreleasedAttr>(D, RetTy))
+    return RetEffect::MakeNotOwned(*K);
 
   if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
     for (const auto *PD : MD->overridden_methods())
@@ -766,37 +813,20 @@ RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
 bool RetainSummaryManager::applyFunctionParamAnnotationEffect(
     const ParmVarDecl *pd, unsigned parm_idx, const FunctionDecl *FD,
     RetainSummaryTemplate &Template) {
-  if (hasEnabledAttr<NSConsumedAttr>(pd)) {
-    Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::ObjC));
+  QualType QT = pd->getType();
+  if (auto K =
+          hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr,
+                              GeneralizedConsumedAttr>(pd, QT)) {
+    Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K));
     return true;
-  } else if (hasEnabledAttr<CFConsumedAttr>(pd)) {
-    Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::CF));
+  } else if (auto K =
+                 hasAnyEnabledAttrOf<CFReturnsRetainedAttr,
+                                     GeneralizedReturnsRetainedAttr>(pd, QT)) {
+    Template->addArg(AF, parm_idx, ArgEffect(RetainedOutParameter, *K));
     return true;
-  } else if (hasEnabledAttr<OSConsumedAttr>(pd)) {
-    Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::OS));
+  } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr>(pd, QT)) {
+    Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K));
     return true;
-  } else if (hasRCAnnotation(pd, "rc_ownership_consumed")) {
-    Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::Generalized));
-    return true;
-  } else if (hasEnabledAttr<CFReturnsRetainedAttr>(pd) ||
-             hasRCAnnotation(pd, "rc_ownership_returns_retained")) {
-    QualType PointeeTy = pd->getType()->getPointeeType();
-    if (!PointeeTy.isNull()) {
-      if (coreFoundation::isCFObjectRef(PointeeTy)) {
-        Template->addArg(AF, parm_idx, ArgEffect(RetainedOutParameter,
-                                                 ObjKind::CF));
-        return true;
-      }
-    }
-  } else if (hasEnabledAttr<CFReturnsNotRetainedAttr>(pd)) {
-    QualType PointeeTy = pd->getType()->getPointeeType();
-    if (!PointeeTy.isNull()) {
-      if (coreFoundation::isCFObjectRef(PointeeTy)) {
-        Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter,
-                                                 ObjKind::CF));
-        return true;
-      }
-    }
   } else {
     if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
       for (const auto *OD : MD->overridden_methods()) {
@@ -831,7 +861,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
   if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
     Template->setRetEffect(*RetE);
 
-  if (hasEnabledAttr<OSConsumesThisAttr>(FD))
+  if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy))
     Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS));
 }
 
@@ -845,35 +875,25 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
   RetainSummaryTemplate Template(Summ, *this);
 
   // Effects on the receiver.
-  if (MD->hasAttr<NSConsumesSelfAttr>())
+  if (hasAnyEnabledAttrOf<NSConsumesSelfAttr>(MD, MD->getReturnType()))
     Template->setReceiverEffect(ArgEffect(DecRef, ObjKind::ObjC));
 
   // Effects on the parameters.
   unsigned parm_idx = 0;
-  for (auto pi=MD->param_begin(), pe=MD->param_end();
-       pi != pe; ++pi, ++parm_idx) {
+  for (auto pi = MD->param_begin(), pe = MD->param_end(); pi != pe;
+       ++pi, ++parm_idx) {
     const ParmVarDecl *pd = *pi;
-    if (pd->hasAttr<NSConsumedAttr>()) {
-      Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::ObjC));
-    } else if (pd->hasAttr<CFConsumedAttr>()) {
-      Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::CF));
-    } else if (pd->hasAttr<OSConsumedAttr>()) {
-      Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::OS));
-    } else if (pd->hasAttr<CFReturnsRetainedAttr>()) {
-      QualType PointeeTy = pd->getType()->getPointeeType();
-      if (!PointeeTy.isNull())
-        if (coreFoundation::isCFObjectRef(PointeeTy))
-          Template->addArg(AF, parm_idx,
-                           ArgEffect(RetainedOutParameter, ObjKind::CF));
-    } else if (pd->hasAttr<CFReturnsNotRetainedAttr>()) {
-      QualType PointeeTy = pd->getType()->getPointeeType();
-      if (!PointeeTy.isNull())
-        if (coreFoundation::isCFObjectRef(PointeeTy))
-          Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter,
-                                                   ObjKind::CF));
+    QualType QT = pd->getType();
+    if (auto K =
+            hasAnyEnabledAttrOf<NSConsumedAttr, CFConsumedAttr, OSConsumedAttr>(
+                pd, QT)) {
+      Template->addArg(AF, parm_idx, ArgEffect(DecRef, *K));
+    } else if (auto K = hasAnyEnabledAttrOf<CFReturnsRetainedAttr>(pd, QT)) {
+      Template->addArg(AF, parm_idx, ArgEffect(RetainedOutParameter, *K));
+    } else if (auto K = hasAnyEnabledAttrOf<CFReturnsNotRetainedAttr>(pd, QT)) {
+      Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter, *K));
     }
   }
-
   QualType RetTy = MD->getReturnType();
   if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
     Template->setRetEffect(*RetE);