[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.

llvm-svn: 176054
This commit is contained in:
Anna Zaks 2013-02-25 22:10:34 +00:00
parent 0adc042392
commit ba34272321
2 changed files with 48 additions and 29 deletions

View File

@ -110,38 +110,40 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
return;
ProgramStateRef State = C.getState();
const ObjCMethodDecl *D = Msg->getDecl();
if (D && D->hasRelatedResultType()) {
switch (Msg->getMethodFamily()) {
default:
break;
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 =
// 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;
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;
}
}
}
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;
}

View File

@ -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