]> granicus.if.org Git - clang/commitdiff
[analyzer] Handle calling ObjC super method from inside C++ lambda.
authorDevin Coughlin <dcoughlin@apple.com>
Sun, 15 Nov 2015 17:48:22 +0000 (17:48 +0000)
committerDevin Coughlin <dcoughlin@apple.com>
Sun, 15 Nov 2015 17:48:22 +0000 (17:48 +0000)
When calling a ObjC method on super from inside a C++ lambda, look at the
captures to find "self". This mirrors how the analyzer handles calling super in
an ObjC block and fixes an assertion failure.

rdar://problem/23550077

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

lib/Analysis/AnalysisDeclContext.cpp
test/Analysis/lambdas.mm [new file with mode: 0644]

index d7fb7e95d7586959cfc2e9ae43ee1e3747c7fc1a..52c7f2613654b30d2fefce8dd33e43d7554a9901 100644 (file)
@@ -148,6 +148,23 @@ const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
     }    
   }
 
+  auto *CXXMethod = dyn_cast<CXXMethodDecl>(D);
+  if (!CXXMethod)
+    return nullptr;
+
+  const CXXRecordDecl *parent = CXXMethod->getParent();
+  if (!parent->isLambda())
+    return nullptr;
+
+  for (const LambdaCapture &LC : parent->captures()) {
+    if (!LC.capturesVariable())
+      continue;
+
+    VarDecl *VD = LC.getCapturedVar();
+    if (VD->getName() == "self")
+      return dyn_cast<ImplicitParamDecl>(VD);
+  }
+
   return nullptr;
 }
 
diff --git a/test/Analysis/lambdas.mm b/test/Analysis/lambdas.mm
new file mode 100644 (file)
index 0000000..f2cd5ae
--- /dev/null
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-objc-root-class -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
+
+int clang_analyzer_eval(int);
+
+@interface Super
+- (void)superMethod;
+@end
+
+@interface Sub : Super {
+  int _ivar1;
+  int _ivar2;
+}
+@end
+
+
+@implementation Sub
+- (void)callMethodOnSuperInCXXLambda; {
+  // Explicit capture.
+  [self]() {
+    [super superMethod];
+  }();
+
+  // Implicit capture.
+  [=]() {
+    [super superMethod];
+  }();
+}
+
+- (void)swapIvars {
+  int tmp = _ivar1;
+  _ivar1 = _ivar2;
+  _ivar2 = tmp;
+}
+
+- (void)callMethodOnSelfInCXXLambda; {
+  _ivar1 = 7;
+  _ivar2 = 8;
+  [self]() {
+    [self swapIvars];
+  }();
+
+  clang_analyzer_eval(_ivar1 == 8); // expected-warning{{TRUE}}
+  clang_analyzer_eval(_ivar2 == 7); // expected-warning{{TRUE}}
+}
+
+@end