[cfe-commits] r161358 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp test/Analysis/inlining/ObjCDynTypePopagation.m

Anna Zaks ganna at apple.com
Mon Aug 6 16:25:46 PDT 2012


Author: zaks
Date: Mon Aug  6 18:25:45 2012
New Revision: 161358

URL: http://llvm.org/viewvc/llvm-project?rev=161358&view=rev
Log:
[analyzer] Dynamic type info - propagate through implicit casts.

I currently have a bit of redundancy with the cast kind switch statement
inside the ImplicitCast callback, but I might be adding more casts going
forward.

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
    cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp?rev=161358&r1=161357&r2=161358&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp Mon Aug  6 18:25:45 2012
@@ -24,11 +24,18 @@
 using namespace ento;
 
 namespace {
-class DynamicTypePropagation : public Checker< check::PostCall > {
+class DynamicTypePropagation:
+    public Checker< check::PostCall,
+                    check::PostStmt<ImplicitCastExpr> > {
   const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
                                                     CheckerContext &C) const;
+
+  /// \brief Return a better dynamic type if one can be derived from the cast.
+  const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE,
+                                                 CheckerContext &C) const;
 public:
-  void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+  void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const;
 };
 }
 
@@ -77,6 +84,25 @@
   }
 }
 
+void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE,
+                                           CheckerContext &C) const {
+  // We only track dynamic type info for regions.
+  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
+  if (!ToR)
+    return;
+
+  switch (CastE->getCastKind()) {
+  default:
+    break;
+  case CK_BitCast:
+    // Only handle ObjCObjects for now.
+    if (const Type *NewTy = getBetterObjCType(CastE, C))
+      C.addTransition(C.getState()->addDynamicTypeInfo(ToR, QualType(NewTy,0)));
+    break;
+  }
+  return;
+}
+
 const ObjCObjectType *
 DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
                                                     CheckerContext &C) const {
@@ -111,6 +137,42 @@
   return 0;
 }
 
+// Return a better dynamic type if one can be derived from the cast.
+// Compare the current dynamic type of the region and the new type to which we
+// are casting. If the new type is lower in the inheritance hierarchy, pick it.
+const ObjCObjectPointerType *
+DynamicTypePropagation::getBetterObjCType(const Expr *CastE,
+                                          CheckerContext &C) const {
+  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
+  assert(ToR);
+
+  // Get the old and new types.
+  const ObjCObjectPointerType *NewTy =
+      CastE->getType()->getAs<ObjCObjectPointerType>();
+  if (!NewTy)
+    return 0;
+  QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
+  if (OldDTy.isNull()) {
+    return NewTy;
+  }
+  const ObjCObjectPointerType *OldTy =
+    OldDTy->getAs<ObjCObjectPointerType>();
+  if (!OldTy)
+    return 0;
+
+  // Id the old type is 'id', the new one is more precise.
+  if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
+    return NewTy;
+
+  // Return new if it's a subclass of old.
+  const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl();
+  const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl();
+  if (ToI && FromI && FromI->isSuperClassOf(ToI))
+    return NewTy;
+
+  return 0;
+}
+
 void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
   mgr.registerChecker<DynamicTypePropagation>();
 }

Modified: cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m?rev=161358&r1=161357&r2=161358&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m (original)
+++ cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m Mon Aug  6 18:25:45 2012
@@ -41,8 +41,8 @@
 /* Test that we get the right type from call to alloc. */
 
 + (void) testAllocSelf {
- id a = [self alloc];
- clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
+  id a = [self alloc];
+  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
 }
 
 
@@ -68,8 +68,26 @@
 }
 
 + (void) testNewSelf {
- id a = [self new];
- clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
+  id a = [self new];
+  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
+}
+
+// Casting to parent should not pessimize the dynamic type. 
++ (void) testCastToParent {
+ id a = [[self alloc] init];
+  MyParent *p = a;  
+  clang_analyzer_eval([p getZeroOverridden] == 0); // expected-warning{{TRUE}}
+}
+
+// The type of parameter gets used.
++ (void)testTypeFromParam:(MyParent*) p {
+  clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
+}
+
+// Test implisit cast.
++ (void) testCastFromId:(id) a {
+  MyParent *p = a;  
+  clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
 }
 
 @end
\ No newline at end of file





More information about the cfe-commits mailing list