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