DynamicTypePropagation.cpp revision 0ad36baedc516005cb6ea97d96327517ebfe5138
1c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks//== DynamicTypePropagation.cpp ----------------------------------- -*- C++ -*--=// 2c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks// 3c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks// The LLVM Compiler Infrastructure 4c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks// 5c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks// This file is distributed under the University of Illinois Open Source 6c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks// License. See LICENSE.TXT for details. 7c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks// 8c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks//===----------------------------------------------------------------------===// 9c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks// 10c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks// This checker defines the rules for dynamic type gathering and propagation. 11c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks// 12c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks//===----------------------------------------------------------------------===// 13c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 14c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks#include "ClangSACheckers.h" 15c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks#include "clang/StaticAnalyzer/Core/Checker.h" 16c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks#include "clang/StaticAnalyzer/Core/CheckerManager.h" 17c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 18c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 19c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 20c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 21c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks#include "clang/Basic/Builtins.h" 22c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 23c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaksusing namespace clang; 24c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaksusing namespace ento; 25c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 26c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaksnamespace { 27c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaksclass DynamicTypePropagation: 280ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose public Checker< check::PreCall, 290ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose check::PostCall, 30c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks check::PostStmt<ImplicitCastExpr> > { 31c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 32c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks CheckerContext &C) const; 33c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks 34c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks /// \brief Return a better dynamic type if one can be derived from the cast. 35c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, 36c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks CheckerContext &C) const; 37c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zakspublic: 380ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 39c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 40c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const; 41c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks}; 42c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks} 43c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 440ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rosevoid DynamicTypePropagation::checkPreCall(const CallEvent &Call, 450ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose CheckerContext &C) const { 460ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { 470ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // C++11 [class.cdtor]p4: When a virtual function is called directly or 480ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // indirectly from a constructor or from a destructor, including during 490ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // the construction or destruction of the class’s non-static data members, 500ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // and the object to which the call applies is the object under 510ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // construction or destruction, the function called is the final overrider 520ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // in the constructor's or destructor's class and not one overriding it in 530ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // a more-derived class. 540ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // FIXME: We don't support this behavior yet for constructors. 550ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose 560ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); 570ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose if (!Target) 580ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose return; 590ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose 600ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // FIXME: getRuntimeDefinition() can be expensive. It would be better to do 610ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose // this when we are entering the stack frame for the destructor. 620ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose const Decl *D = Dtor->getRuntimeDefinition().getDecl(); 630ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose if (!D) 640ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose return; 650ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose 660ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose const CXXRecordDecl *Class = cast<CXXDestructorDecl>(D)->getParent(); 670ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose 680ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose ASTContext &Ctx = C.getASTContext(); 690ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose QualType Ty = Ctx.getPointerType(Ctx.getRecordType(Class)); 700ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose 710ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose ProgramStateRef State = C.getState(); 720ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose State = State->setDynamicTypeInfo(Target, Ty, /*CanBeSubclass=*/false); 730ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose C.addTransition(State); 740ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose } 750ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose} 760ad36baedc516005cb6ea97d96327517ebfe5138Jordan Rose 77c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaksvoid DynamicTypePropagation::checkPostCall(const CallEvent &Call, 78c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks CheckerContext &C) const { 79c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // We can obtain perfect type info for return values from some calls. 80c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { 81c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 82c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // Get the returned value if it's a region. 83c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks SVal Result = C.getSVal(Call.getOriginExpr()); 84c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks const MemRegion *RetReg = Result.getAsRegion(); 85c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (!RetReg) 86c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks return; 87c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 88c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks ProgramStateRef State = C.getState(); 89c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 90c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks switch (Msg->getMethodFamily()) { 91c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks default: 92c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks break; 93c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 94c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // We assume that the type of the object returned by alloc and new are the 95c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // pointer to the object of the class specified in the receiver of the 96c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // message. 97c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks case OMF_alloc: 98c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks case OMF_new: { 99c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // Get the type of object that will get created. 100c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); 101c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); 102c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (!ObjTy) 103c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks return; 104c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks QualType DynResTy = 105c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); 10654918ba02ba900c0e0bb4fd3d749b6b1ac4e50a9Anna Zaks C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false)); 107c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks break; 108c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks } 109c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks case OMF_init: { 110c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // Assume, the result of the init method has the same dynamic type as 111c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // the receiver and propagate the dynamic type info. 112c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); 1138ed21ef726be89ef7151b5ff397631379bd8a537Anna Zaks if (!RecReg) 1148ed21ef726be89ef7151b5ff397631379bd8a537Anna Zaks return; 115c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); 116d4fe57f7f7a8793227effc1274d70ec44cee9a4fAnna Zaks C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); 117c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks break; 118c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks } 119c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks } 120c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks } 121c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks} 122c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 123c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaksvoid DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE, 124c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks CheckerContext &C) const { 125c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks // We only track dynamic type info for regions. 126c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 127c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks if (!ToR) 128c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks return; 129c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks 130c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks switch (CastE->getCastKind()) { 131c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks default: 132c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks break; 133c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks case CK_BitCast: 134c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks // Only handle ObjCObjects for now. 135c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks if (const Type *NewTy = getBetterObjCType(CastE, C)) 136d4fe57f7f7a8793227effc1274d70ec44cee9a4fAnna Zaks C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0))); 137c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks break; 138c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks } 139c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks return; 140c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks} 141c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks 142c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaksconst ObjCObjectType * 143c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna ZaksDynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 144c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks CheckerContext &C) const { 145c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) { 146c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (const ObjCObjectType *ObjTy 147c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks = MsgE->getClassReceiver()->getAs<ObjCObjectType>()) 148c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks return ObjTy; 149c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks } 150c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 151c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) { 152c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (const ObjCObjectType *ObjTy 153c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks = MsgE->getSuperType()->getAs<ObjCObjectType>()) 154c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks return ObjTy; 155c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks } 156c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 157c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks const Expr *RecE = MsgE->getInstanceReceiver(); 158c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (!RecE) 159c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks return 0; 160c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 161c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks RecE= RecE->IgnoreParenImpCasts(); 162c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { 163955cd444f445bcdbade1cdd3926254c8ee7890d8Anna Zaks const StackFrameContext *SFCtx = C.getStackFrame(); 164c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // Are we calling [self alloc]? If this is self, get the type of the 165c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks // enclosing ObjC class. 166c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (DRE->getDecl() == SFCtx->getSelfDecl()) { 167c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl())) 168c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks if (const ObjCObjectType *ObjTy = 169c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl())) 170c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks return ObjTy; 171c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks } 172c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks } 173c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks return 0; 174c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks} 175c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks 176c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks// Return a better dynamic type if one can be derived from the cast. 177c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks// Compare the current dynamic type of the region and the new type to which we 178c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks// are casting. If the new type is lower in the inheritance hierarchy, pick it. 179c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaksconst ObjCObjectPointerType * 180c4c647c88ced2e953f15f8987952ede9b96aa969Anna ZaksDynamicTypePropagation::getBetterObjCType(const Expr *CastE, 181c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks CheckerContext &C) const { 182c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 183c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks assert(ToR); 184c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks 185c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks // Get the old and new types. 186c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks const ObjCObjectPointerType *NewTy = 187c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks CastE->getType()->getAs<ObjCObjectPointerType>(); 188c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks if (!NewTy) 189c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks return 0; 190c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType(); 191c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks if (OldDTy.isNull()) { 192c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks return NewTy; 193c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks } 194c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks const ObjCObjectPointerType *OldTy = 195c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks OldDTy->getAs<ObjCObjectPointerType>(); 196c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks if (!OldTy) 197c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks return 0; 198c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks 199c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks // Id the old type is 'id', the new one is more precise. 200c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) 201c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks return NewTy; 202c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks 203c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks // Return new if it's a subclass of old. 204c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl(); 205c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl(); 206c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks if (ToI && FromI && FromI->isSuperClassOf(ToI)) 207c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks return NewTy; 208c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks 209c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks return 0; 210c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks} 211c4c647c88ced2e953f15f8987952ede9b96aa969Anna Zaks 212c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaksvoid ento::registerDynamicTypePropagation(CheckerManager &mgr) { 213c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks mgr.registerChecker<DynamicTypePropagation>(); 214c7ecc43c33a21b82c49664910b19fcc1f555aa51Anna Zaks} 215