diff options
author | Anna Zaks <ganna@apple.com> | 2013-02-25 22:10:34 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2013-02-25 22:10:34 +0000 |
commit | db061e40d639da0d938f915f0eef9e9772019c22 (patch) | |
tree | 3ed41eda7b9adcdcbf7274ee330de4f85fe0a61f | |
parent | 6f8e9b6caed0bf6108cf90f0d54fa637b60b3b9e (diff) |
[analyzer] Restrict ObjC type inference to methods that have related result type.
This addresses a case when we inline a wrong method due to incorrect
dynamic type inference. Specifically, when user code contains a method from init
family, which creates an instance of another class.
Use hasRelatedResultType() to find out if our inference rules should be triggered.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176054 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp | 62 | ||||
-rw-r--r-- | test/Analysis/inlining/ObjCDynTypePopagation.m | 17 |
2 files changed, 49 insertions, 30 deletions
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 08af45df37..9f176a4b5b 100644 --- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -110,38 +110,40 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, return; ProgramStateRef State = C.getState(); - - switch (Msg->getMethodFamily()) { - default: - break; - - // We assume that the type of the object returned by alloc and new are the - // pointer to the object of the class specified in the receiver of the - // message. - case OMF_alloc: - case OMF_new: { - // Get the type of object that will get created. - const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); - const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); - if (!ObjTy) - return; - QualType DynResTy = + const ObjCMethodDecl *D = Msg->getDecl(); + + if (D && D->hasRelatedResultType()) { + switch (Msg->getMethodFamily()) { + default: + break; + + // We assume that the type of the object returned by alloc and new are the + // pointer to the object of the class specified in the receiver of the + // message. + case OMF_alloc: + case OMF_new: { + // Get the type of object that will get created. + const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); + const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); + if (!ObjTy) + return; + QualType DynResTy = C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); - C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false)); - break; - } - case OMF_init: { - // Assume, the result of the init method has the same dynamic type as - // the receiver and propagate the dynamic type info. - const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); - if (!RecReg) - return; - DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); - C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); - break; - } + C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false)); + break; + } + case OMF_init: { + // Assume, the result of the init method has the same dynamic type as + // the receiver and propagate the dynamic type info. + const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); + if (!RecReg) + return; + DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); + C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); + break; + } + } } - return; } diff --git a/test/Analysis/inlining/ObjCDynTypePopagation.m b/test/Analysis/inlining/ObjCDynTypePopagation.m index fc38a85d85..ccc2471378 100644 --- a/test/Analysis/inlining/ObjCDynTypePopagation.m +++ b/test/Analysis/inlining/ObjCDynTypePopagation.m @@ -82,3 +82,20 @@ int testDynamicClass(BOOL coin) { return [x getZero]; return 1; } + +@interface UserClass : NSObject +- (PublicSubClass2 *) _newPublicSubClass2; +- (int) getZero; +- (void) callNew; +@end + +@implementation UserClass +- (PublicSubClass2 *) _newPublicSubClass2 { + return [[PublicSubClass2 alloc] init]; +} +- (int) getZero { return 5; } +- (void) callNew { + PublicSubClass2 *x = [self _newPublicSubClass2]; + clang_analyzer_eval([x getZero] == 0); //expected-warning{{TRUE}} +} +@end
\ No newline at end of file |