]> granicus.if.org Git - clang/commitdiff
[analyzer] [RetainSummaryManager] [NFC] Split one function into two, as it's really...
authorGeorge Karpenkov <ekarpenkov@apple.com>
Tue, 29 Jan 2019 19:29:45 +0000 (19:29 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Tue, 29 Jan 2019 19:29:45 +0000 (19:29 +0000)
Differential Revision: https://reviews.llvm.org/D57201

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

include/clang/Analysis/RetainSummaryManager.h
lib/Analysis/RetainSummaryManager.cpp

index 409f23caf3451b26ea30799e030485cdc9dc43a7..6773ea48ef51f6d70c6f2b755f423ae5b7f8b30b 100644 (file)
@@ -693,10 +693,22 @@ private:
   void updateSummaryFromAnnotations(const RetainSummary *&Summ,
                                     const FunctionDecl *FD);
 
-  void updateSummaryForCall(const RetainSummary *&Summ,
-                            AnyCall C,
-                            bool HasNonZeroCallbackArg,
-                            bool IsReceiverUnconsumedSelf);
+  const RetainSummary *updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
+                                                          AnyCall &C);
+
+  /// Special case '[super init];' and '[self init];'
+  ///
+  /// Even though calling '[super init]' without assigning the result to self
+  /// and checking if the parent returns 'nil' is a bad pattern, it is common.
+  /// Additionally, our Self Init checker already warns about it. To avoid
+  /// overwhelming the user with messages from both checkers, we model the case
+  /// of '[super init]' in cases when it is not consumed by another expression
+  /// as if the call preserves the value of 'self'; essentially, assuming it can
+  /// never fail and return 'nil'.
+  /// Note, we don't want to just stop tracking the value since we want the
+  /// RetainCount checker to report leaks and use-after-free if SelfInit checker
+  /// is turned off.
+  void updateSummaryForReceiverUnconsumedSelf(const RetainSummary *&S);
 
   /// Determine whether a declaration {@code D} of correspondent type (return
   /// type for functions/methods) {@code QT} has any of the given attributes,
index 96b5c9eea8628eccb13897d8d76e8fd07dcf7585..9a514efb7c301b93d8a04f85a266d8d158604e36 100644 (file)
@@ -557,64 +557,47 @@ static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
   llvm_unreachable("Unknown ArgEffect kind");
 }
 
-void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
-                                                AnyCall C,
-                                                bool HasNonZeroCallbackArg,
-                                                bool IsReceiverUnconsumedSelf) {
-
-  if (HasNonZeroCallbackArg) {
-    ArgEffect RecEffect =
-      getStopTrackingHardEquivalent(S->getReceiverEffect());
-    ArgEffect DefEffect =
-      getStopTrackingHardEquivalent(S->getDefaultArgEffect());
-
-    ArgEffects ScratchArgs(AF.getEmptyMap());
-    ArgEffects CustomArgEffects = S->getArgEffects();
-    for (ArgEffects::iterator I = CustomArgEffects.begin(),
-                              E = CustomArgEffects.end();
-         I != E; ++I) {
-      ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
-      if (Translated.getKind() != DefEffect.getKind())
-        ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
-    }
-
-    RetEffect RE = RetEffect::MakeNoRetHard();
-
-    // Special cases where the callback argument CANNOT free the return value.
-    // This can generally only happen if we know that the callback will only be
-    // called when the return value is already being deallocated.
-    if (C.getKind() == AnyCall::Function) {
-      if (const IdentifierInfo *Name = C.getIdentifier()) {
-        // When the CGBitmapContext is deallocated, the callback here will free
-        // the associated data buffer.
-        // The callback in dispatch_data_create frees the buffer, but not
-        // the data object.
-        if (Name->isStr("CGBitmapContextCreateWithData") ||
-            Name->isStr("dispatch_data_create"))
-          RE = S->getRetEffect();
-      }
-    }
+const RetainSummary *
+RetainSummaryManager::updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
+                                                         AnyCall &C) {
+  ArgEffect RecEffect = getStopTrackingHardEquivalent(S->getReceiverEffect());
+  ArgEffect DefEffect = getStopTrackingHardEquivalent(S->getDefaultArgEffect());
 
-    S = getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
+  ArgEffects ScratchArgs(AF.getEmptyMap());
+  ArgEffects CustomArgEffects = S->getArgEffects();
+  for (ArgEffects::iterator I = CustomArgEffects.begin(),
+                            E = CustomArgEffects.end();
+       I != E; ++I) {
+    ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
+    if (Translated.getKind() != DefEffect.getKind())
+      ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
   }
 
-  // Special case '[super init];' and '[self init];'
-  //
-  // Even though calling '[super init]' without assigning the result to self
-  // and checking if the parent returns 'nil' is a bad pattern, it is common.
-  // Additionally, our Self Init checker already warns about it. To avoid
-  // overwhelming the user with messages from both checkers, we model the case
-  // of '[super init]' in cases when it is not consumed by another expression
-  // as if the call preserves the value of 'self'; essentially, assuming it can
-  // never fail and return 'nil'.
-  // Note, we don't want to just stop tracking the value since we want the
-  // RetainCount checker to report leaks and use-after-free if SelfInit checker
-  // is turned off.
-  if (IsReceiverUnconsumedSelf) {
-    RetainSummaryTemplate ModifiableSummaryTemplate(S, *this);
-    ModifiableSummaryTemplate->setReceiverEffect(ArgEffect(DoNothing));
-    ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet());
+  RetEffect RE = RetEffect::MakeNoRetHard();
+
+  // Special cases where the callback argument CANNOT free the return value.
+  // This can generally only happen if we know that the callback will only be
+  // called when the return value is already being deallocated.
+  if (const IdentifierInfo *Name = C.getIdentifier()) {
+    // When the CGBitmapContext is deallocated, the callback here will free
+    // the associated data buffer.
+    // The callback in dispatch_data_create frees the buffer, but not
+    // the data object.
+    if (Name->isStr("CGBitmapContextCreateWithData") ||
+        Name->isStr("dispatch_data_create"))
+      RE = S->getRetEffect();
   }
+
+  return getPersistentSummary(RE, ScratchArgs, RecEffect, DefEffect);
+}
+
+void RetainSummaryManager::updateSummaryForReceiverUnconsumedSelf(
+    const RetainSummary *&S) {
+
+  RetainSummaryTemplate Template(S, *this);
+
+  Template->setReceiverEffect(ArgEffect(DoNothing));
+  Template->setRetEffect(RetEffect::MakeNoRet());
 }
 
 const RetainSummary *
@@ -647,8 +630,11 @@ RetainSummaryManager::getSummary(AnyCall C,
   }
   }
 
-  updateSummaryForCall(Summ, C, HasNonZeroCallbackArg,
-                       IsReceiverUnconsumedSelf);
+  if (HasNonZeroCallbackArg)
+    Summ = updateSummaryForNonZeroCallbackArg(Summ, C);
+
+  if (IsReceiverUnconsumedSelf)
+    updateSummaryForReceiverUnconsumedSelf(Summ);
 
   assert(Summ && "Unknown call type?");
   return Summ;