[analyzer] Update CheckObjCDealloc diagnostic for missing -dealloc.
authorDevin Coughlin <dcoughlin@apple.com>
Tue, 1 Mar 2016 00:39:04 +0000 (00:39 +0000)
committerDevin Coughlin <dcoughlin@apple.com>
Tue, 1 Mar 2016 00:39:04 +0000 (00:39 +0000)
Update the diagnostic for classes missing -dealloc to mention an instance
variable that needs to be released.

llvm-svn: 262277

clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
clang/test/Analysis/MissingDealloc.m

index ea64d9b..c09924c 100644 (file)
@@ -190,23 +190,27 @@ void ObjCDeallocChecker::checkASTDecl(const ObjCImplementationDecl *D,
   initIdentifierInfoAndSelectors(Mgr.getASTContext());
 
   const ObjCInterfaceDecl *ID = D->getClassInterface();
+  // If the class is known to have a lifecycle with a separate teardown method
+  // then it may not require a -dealloc method.
+  if (classHasSeparateTeardown(ID))
+    return;
 
   // Does the class contain any synthesized properties that are retainable?
   // If not, skip the check entirely.
-  bool containsRetainedSynthesizedProperty = false;
+  const ObjCPropertyImplDecl *PropImplRequiringRelease = nullptr;
+  bool HasOthers = false;
   for (const auto *I : D->property_impls()) {
     if (getDeallocReleaseRequirement(I) == ReleaseRequirement::MustRelease) {
-      containsRetainedSynthesizedProperty = true;
-      break;
+      if (!PropImplRequiringRelease)
+        PropImplRequiringRelease = I;
+      else {
+        HasOthers = true;
+        break;
+      }
     }
   }
 
-  if (!containsRetainedSynthesizedProperty)
-    return;
-
-  // If the class is known to have a lifecycle with a separate teardown method
-  // then it may not require a -dealloc method.
-  if (classHasSeparateTeardown(ID))
+  if (!PropImplRequiringRelease)
     return;
 
   const ObjCMethodDecl *MD = nullptr;
@@ -224,8 +228,12 @@ void ObjCDeallocChecker::checkASTDecl(const ObjCImplementationDecl *D,
 
     std::string Buf;
     llvm::raw_string_ostream OS(Buf);
-    OS << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method";
+    OS << "'" << *D << "' lacks a 'dealloc' instance method but "
+       << "must release '" << *PropImplRequiringRelease->getPropertyIvarDecl()
+       << "'";
 
+    if (HasOthers)
+      OS << " and others";
     PathDiagnosticLocation DLoc =
         PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
 
index ae88054..2dbec92 100644 (file)
@@ -1,5 +1,12 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks %s 2>&1 | FileCheck -check-prefix=CHECK %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks -triple x86_64-apple-darwin10 -fobjc-arc %s 2>&1 | FileCheck -check-prefix=CHECK-ARC -allow-empty '--implicit-check-not=error:' '--implicit-check-not=warning:' %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc -fblocks -verify -triple x86_64-apple-darwin10 -fobjc-arc %s
+
+#define NON_ARC !__has_feature(objc_arc)
+
+// No diagnostics expected under ARC.
+#if !NON_ARC
+  // expected-no-diagnostics
+#endif
 
 typedef signed char BOOL;
 @protocol NSObject
@@ -51,7 +58,9 @@ typedef struct objc_selector *SEL;
 @property (copy) NSObject *ivar;
 @end
 
-// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithCopyProperty' lacks a 'dealloc' instance method
+#if NON_ARC
+// expected-warning@+2{{'MissingDeallocWithCopyProperty' lacks a 'dealloc' instance method but must release '_ivar'}}
+#endif
 @implementation MissingDeallocWithCopyProperty
 @end
 
@@ -59,17 +68,32 @@ typedef struct objc_selector *SEL;
 @property (retain) NSObject *ivar;
 @end
 
-// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithRetainProperty' lacks a 'dealloc' instance method
+#if NON_ARC
+// expected-warning@+2{{'MissingDeallocWithRetainProperty' lacks a 'dealloc' instance method but must release '_ivar'}}
+#endif
 @implementation MissingDeallocWithRetainProperty
 @end
 
+@interface MissingDeallocWithMultipleProperties : NSObject
+@property (retain) NSObject *ivar1;
+@property (retain) NSObject *ivar2;
+@end
+
+#if NON_ARC
+// expected-warning@+2{{'MissingDeallocWithMultipleProperties' lacks a 'dealloc' instance method but must release '_ivar1' and others}}
+#endif
+@implementation MissingDeallocWithMultipleProperties
+@end
+
 @interface MissingDeallocWithIVarAndRetainProperty : NSObject {
   NSObject *_ivar2;
 }
 @property (retain) NSObject *ivar1;
 @end
 
-// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithIVarAndRetainProperty' lacks a 'dealloc' instance method
+#if NON_ARC
+// expected-warning@+2{{'MissingDeallocWithIVarAndRetainProperty' lacks a 'dealloc' instance method but must release '_ivar1'}}
+#endif
 @implementation MissingDeallocWithIVarAndRetainProperty
 @end
 
@@ -77,7 +101,9 @@ typedef struct objc_selector *SEL;
 @property (readonly,retain) NSObject *ivar;
 @end
 
-// CHECK: MissingDealloc.m:[[@LINE+1]]:1: warning: Objective-C class 'MissingDeallocWithReadOnlyRetainedProperty' lacks a 'dealloc' instance method
+#if NON_ARC
+// expected-warning@+2{{'MissingDeallocWithReadOnlyRetainedProperty' lacks a 'dealloc' instance method but must release '_ivar'}}
+#endif
 @implementation MissingDeallocWithReadOnlyRetainedProperty
 @end