summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-11-13 00:48:20 +0000
committerAnna Zaks <ganna@apple.com>2012-11-13 00:48:20 +0000
commitd490d5d5b7f761892905bae2c779a6331aafb9e4 (patch)
tree1839494bdb8729b7f4c0bb38865ab826f4676b32
parent00454e0c6baabd759a0ecea6332bf8b9ca3a7396 (diff)
[analyzer] Follow up to r167762 - precisely determine the adjustment
conditions. The adjustment is needed only in case of dynamic dispatch performed by the analyzer - when the runtime declaration is different from the static one. Document this explicitly in the code (by adding a helper). Also, use canonical Decls to avoid matching against the case where the definition is different from found declaration. This fix suppresses the testcase I added in r167762, so add another testcase to make sure we do test commit r167762. git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_32@167797 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp17
-rw-r--r--test/Analysis/inlining/InlineObjCInstanceMethod.m39
2 files changed, 52 insertions, 4 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 5b88a45495..3ead0817f7 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -191,6 +191,16 @@ void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC,
currBldrCtx = 0;
}
+static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
+ const StackFrameContext *calleeCtx) {
+ const Decl *RuntimeCallee = calleeCtx->getDecl();
+ const Decl *StaticDecl = Call->getDecl();
+ assert(RuntimeCallee);
+ if (!StaticDecl)
+ return true;
+ return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl();
+}
+
/// The call exit is simulated with a sequence of nodes, which occur between
/// CallExitBegin and CallExitEnd. The following operations occur between the
/// two program points:
@@ -230,9 +240,10 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
const LocationContext *LCtx = CEBNode->getLocationContext();
SVal V = state->getSVal(RS, LCtx);
- const Decl *Callee = calleeCtx->getDecl();
- if (Callee != Call->getDecl()) {
- QualType ReturnedTy = CallEvent::getDeclaredResultType(Callee);
+ // Ensure that the return type matches the type of the returned Expr.
+ if (wasDifferentDeclUsedForInlining(Call, calleeCtx)) {
+ QualType ReturnedTy =
+ CallEvent::getDeclaredResultType(calleeCtx->getDecl());
if (!ReturnedTy.isNull()) {
if (const Expr *Ex = dyn_cast<Expr>(CE)) {
V = adjustReturnValue(V, Ex->getType(), ReturnedTy,
diff --git a/test/Analysis/inlining/InlineObjCInstanceMethod.m b/test/Analysis/inlining/InlineObjCInstanceMethod.m
index 21ce8576a4..f6aa50a248 100644
--- a/test/Analysis/inlining/InlineObjCInstanceMethod.m
+++ b/test/Analysis/inlining/InlineObjCInstanceMethod.m
@@ -1,15 +1,32 @@
-// RUN: %clang --analyze -Xanalyzer -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -Xclang -verify %s
+// RUN: %clang --analyze -Xanalyzer -analyzer-checker=osx.cocoa.IncompatibleMethodTypes,osx.coreFoundation.CFRetainRelease -Xclang -verify %s
#include "InlineObjCInstanceMethod.h"
+typedef const struct __CFString * CFStringRef;
+typedef const void * CFTypeRef;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+extern CFStringRef getString(void);
+
// Method is defined in the parent; called through self.
@interface MyParent : NSObject
- (int)getInt;
+- (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained));
@end
@implementation MyParent
- (int)getInt {
return 0;
}
+
+- (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) {
+ CFStringRef Str = ((void*)0);
+ Str = getString();
+ if (Str) {
+ CFRetain(Str);
+ }
+ return Str;
+}
+
@end
@interface MyClass : MyParent
@@ -88,12 +105,22 @@ void randomlyMessageAnObject(MyClass *arr[], int i) {
@interface EvilChild : MyParent
- (id)getInt;
+- (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained));
@end
@implementation EvilChild
- (id)getInt { // expected-warning {{types are incompatible}}
return self;
}
+- (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) {
+ CFStringRef Str = ((void*)0);
+ Str = getString();
+ if (Str) {
+ CFRetain(Str);
+ }
+ return Str;
+}
+
@end
int testNonCovariantReturnType() {
@@ -109,3 +136,13 @@ int testNonCovariantReturnType() {
[obj release];
return 5/(x-1); // no-warning
}
+
+int testCovariantReturnTypeNoErrorSinceTypesMatch() {
+ MyParent *obj = [[EvilChild alloc] init];
+
+ CFStringRef S = ((void*)0);
+ S = [obj testCovariantReturnType];
+ if (S)
+ CFRelease(S);
+ CFRelease(obj);
+}