aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2013-02-25 22:10:34 +0000
committerAnna Zaks <ganna@apple.com>2013-02-25 22:10:34 +0000
commitdb061e40d639da0d938f915f0eef9e9772019c22 (patch)
tree3ed41eda7b9adcdcbf7274ee330de4f85fe0a61f
parent6f8e9b6caed0bf6108cf90f0d54fa637b60b3b9e (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.cpp62
-rw-r--r--test/Analysis/inlining/ObjCDynTypePopagation.m17
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