[analyzer] Find ObjC 'self' decl even when block captures local named 'self'.
authorDevin Coughlin <dcoughlin@apple.com>
Tue, 23 Feb 2016 22:26:04 +0000 (22:26 +0000)
committerDevin Coughlin <dcoughlin@apple.com>
Tue, 23 Feb 2016 22:26:04 +0000 (22:26 +0000)
When looking up the 'self' decl in block captures, make sure to find the actual
self declaration even when the block captures a local variable named 'self'.

rdar://problem/24751280

llvm-svn: 261703

clang/lib/Analysis/AnalysisDeclContext.cpp
clang/test/Analysis/blocks.m
clang/test/Analysis/lambdas.mm

index 94f753e..fe8021b 100644 (file)
@@ -135,6 +135,10 @@ bool AnalysisDeclContext::isBodyAutosynthesizedFromModelFile() const {
   return Tmp && Body->getLocStart().isValid();
 }
 
+/// Returns true if \param VD is an Objective-C implicit 'self' parameter.
+static bool isSelfDecl(const VarDecl *VD) {
+  return isa<ImplicitParamDecl>(VD) && VD->getName() == "self";
+}
 
 const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
   if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@@ -143,7 +147,7 @@ const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
     // See if 'self' was captured by the block.
     for (const auto &I : BD->captures()) {
       const VarDecl *VD = I.getVariable();
-      if (VD->getName() == "self")
+      if (isSelfDecl(VD))
         return dyn_cast<ImplicitParamDecl>(VD);
     }    
   }
@@ -161,7 +165,7 @@ const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
       continue;
 
     VarDecl *VD = LC.getCapturedVar();
-    if (VD->getName() == "self")
+    if (isSelfDecl(VD))
       return dyn_cast<ImplicitParamDecl>(VD);
   }
 
index 4dbe951..0b1c15a 100644 (file)
@@ -210,3 +210,25 @@ void testCallContainingWithSignature5()
   });
 }
 
+__attribute__((objc_root_class))
+@interface SuperClass
+- (void)someMethod;
+@end
+
+@interface SomeClass : SuperClass
+@end
+
+// Make sure to properly handle super-calls when a block captures
+// a local variable named 'self'.
+@implementation SomeClass
+-(void)foo; {
+  /*__weak*/ SomeClass *weakSelf = self;
+  (void)(^(void) {
+    SomeClass *self = weakSelf;
+    (void)(^(void) {
+      (void)self;
+      [super someMethod]; // no-warning
+    });
+  });
+}
+@end
index 6247f28..dc1a13e 100644 (file)
@@ -12,7 +12,6 @@ int clang_analyzer_eval(int);
 }
 @end
 
-
 @implementation Sub
 - (void)callMethodOnSuperInCXXLambda; {
   // Explicit capture.
@@ -26,6 +25,20 @@ int clang_analyzer_eval(int);
   }();
 }
 
+// Make sure to properly handle super-calls when a block captures
+// a local variable named 'self'.
+- (void)callMethodOnSuperInCXXLambdaWithRedefinedSelf; {
+  /*__weak*/ Sub *weakSelf = self;
+  // Implicit capture. (Sema outlaws explicit capture of a redefined self
+  // and a call to super [which uses the original self]).
+  [=]() {
+    Sub *self = weakSelf;
+    [=]() {
+      [super superMethod];
+    }();
+  }();
+}
+
 - (void)swapIvars {
   int tmp = _ivar1;
   _ivar1 = _ivar2;