summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-08-06 23:25:45 +0000
committerAnna Zaks <ganna@apple.com>2012-08-06 23:25:45 +0000
commit05253782a48d82cbcefba4ff1744fbf5eb6923bf (patch)
tree30e8da2c016cfe8bb0bac8745dd31554f6c67d8c
parent472dbcf15673dc67d03b463845635784f41847a2 (diff)
downloadbcm5719-llvm-05253782a48d82cbcefba4ff1744fbf5eb6923bf.tar.gz
bcm5719-llvm-05253782a48d82cbcefba4ff1744fbf5eb6923bf.zip
[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. llvm-svn: 161358
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp66
-rw-r--r--clang/test/Analysis/inlining/ObjCDynTypePopagation.m26
2 files changed, 86 insertions, 6 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index 56610b58183..fec6c43dbd1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -24,11 +24,18 @@ using namespace clang;
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::checkPostCall(const CallEvent &Call,
}
}
+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 @@ DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
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>();
}
diff --git a/clang/test/Analysis/inlining/ObjCDynTypePopagation.m b/clang/test/Analysis/inlining/ObjCDynTypePopagation.m
index 89c05c9c567..425903242dc 100644
--- a/clang/test/Analysis/inlining/ObjCDynTypePopagation.m
+++ b/clang/test/Analysis/inlining/ObjCDynTypePopagation.m
@@ -41,8 +41,8 @@ MyClass *getObj();
/* 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 @@ MyClass *getObj();
}
+ (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
OpenPOWER on IntegriCloud