forked from OSchip/llvm-project
[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:
parent
0adc042392
commit
ba34272321
|
@ -110,38 +110,40 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ProgramStateRef State = C.getState();
|
ProgramStateRef State = C.getState();
|
||||||
|
const ObjCMethodDecl *D = Msg->getDecl();
|
||||||
|
|
||||||
|
if (D && D->hasRelatedResultType()) {
|
||||||
|
switch (Msg->getMethodFamily()) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
switch (Msg->getMethodFamily()) {
|
// We assume that the type of the object returned by alloc and new are the
|
||||||
default:
|
// pointer to the object of the class specified in the receiver of the
|
||||||
break;
|
// message.
|
||||||
|
case OMF_alloc:
|
||||||
// We assume that the type of the object returned by alloc and new are the
|
case OMF_new: {
|
||||||
// pointer to the object of the class specified in the receiver of the
|
// Get the type of object that will get created.
|
||||||
// message.
|
const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
|
||||||
case OMF_alloc:
|
const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
|
||||||
case OMF_new: {
|
if (!ObjTy)
|
||||||
// Get the type of object that will get created.
|
return;
|
||||||
const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
|
QualType DynResTy =
|
||||||
const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
|
|
||||||
if (!ObjTy)
|
|
||||||
return;
|
|
||||||
QualType DynResTy =
|
|
||||||
C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
|
C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
|
||||||
C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
|
C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
|
||||||
break;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,3 +82,20 @@ int testDynamicClass(BOOL coin) {
|
||||||
return [x getZero];
|
return [x getZero];
|
||||||
return 1;
|
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
|
Loading…
Reference in New Issue