diff options
author | Anna Zaks <ganna@apple.com> | 2012-11-13 00:48:20 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-11-13 00:48:20 +0000 |
commit | d490d5d5b7f761892905bae2c779a6331aafb9e4 (patch) | |
tree | 1839494bdb8729b7f4c0bb38865ab826f4676b32 | |
parent | 00454e0c6baabd759a0ecea6332bf8b9ca3a7396 (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.cpp | 17 | ||||
-rw-r--r-- | test/Analysis/inlining/InlineObjCInstanceMethod.m | 39 |
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); +} |