[analyzer] Track if a region can be a subclass in the dynamic type info.
When object is allocated with alloc or init, we assume it cannot be a
subclass (currently used only for bifurcation purposes).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161682 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 3785e90..d36aa1b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -61,16 +61,20 @@
/// dispatch implementation.
class DynamicTypeInfo {
QualType T;
+ bool CanBeASubClass;
public:
DynamicTypeInfo() : T(QualType()) {}
- DynamicTypeInfo(QualType WithType) : T(WithType) {}
- QualType getType() {return T;}
+ DynamicTypeInfo(QualType WithType, bool CanBeSub = true):
+ T(WithType), CanBeASubClass(CanBeSub) {}
+ QualType getType() { return T; }
+ bool canBeASubClass() { return CanBeASubClass; }
void Profile(llvm::FoldingSetNodeID &ID) const {
T.Profile(ID);
+ ID.AddInteger((unsigned)CanBeASubClass);
}
bool operator==(const DynamicTypeInfo &X) const {
- return T == X.T;
+ return T == X.T && CanBeASubClass == X.CanBeASubClass;
}
};
@@ -340,8 +344,9 @@
/// \brief Set dynamic type information of the region; return the new state.
ProgramStateRef setDynamicTypeInfo(const MemRegion *Reg,
- QualType NewTy) const {
- return setDynamicTypeInfo(Reg, DynamicTypeInfo(NewTy));
+ QualType NewTy,
+ bool CanBeSubClassed = true) const {
+ return setDynamicTypeInfo(Reg, DynamicTypeInfo(NewTy, CanBeSubClassed));
}
//==---------------------------------------------------------------------==//
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index d8bb5ea..f22d740 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -68,7 +68,7 @@
return;
QualType DynResTy =
C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
- C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy));
+ C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
break;
}
case OMF_init: {
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 773600b..6635067 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -721,6 +721,7 @@
// Find the the receiver type.
const ObjCObjectPointerType *ReceiverT = 0;
+ bool CanBeSubClassed = false;
QualType SupersType = E->getSuperType();
const MemRegion *Receiver = 0;
@@ -733,17 +734,25 @@
if (!Receiver)
return RuntimeDefinition();
- QualType DynType = getState()->getDynamicTypeInfo(Receiver).getType();
+ DynamicTypeInfo DTI = getState()->getDynamicTypeInfo(Receiver);
+ QualType DynType = DTI.getType();
+ CanBeSubClassed = DTI.canBeASubClass();
ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType);
+
+ if (ReceiverT && CanBeSubClassed)
+ if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl())
+ if (!canBeOverridenInSubclass(IDecl, Sel))
+ CanBeSubClassed = false;
}
// Lookup the method implementation.
if (ReceiverT)
if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) {
- if (canBeOverridenInSubclass(IDecl, Sel))
- return RuntimeDefinition(IDecl->lookupPrivateMethod(Sel), Receiver);
+ const ObjCMethodDecl *MD = IDecl->lookupPrivateMethod(Sel);
+ if (CanBeSubClassed)
+ return RuntimeDefinition(MD, Receiver);
else
- return RuntimeDefinition(IDecl->lookupPrivateMethod(Sel), 0);
+ return RuntimeDefinition(MD, 0);
}
} else {
diff --git a/test/Analysis/inlining/InlineObjCClassMethod.m b/test/Analysis/inlining/InlineObjCClassMethod.m
index a5a1369..7e8b51f 100644
--- a/test/Analysis/inlining/InlineObjCClassMethod.m
+++ b/test/Analysis/inlining/InlineObjCClassMethod.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -verify %s
// Test inlining of ObjC class methods.
diff --git a/test/Analysis/inlining/InlineObjCInstanceMethod.h b/test/Analysis/inlining/InlineObjCInstanceMethod.h
index bae80c6..715b89e 100644
--- a/test/Analysis/inlining/InlineObjCInstanceMethod.h
+++ b/test/Analysis/inlining/InlineObjCInstanceMethod.h
@@ -11,6 +11,7 @@
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@interface NSObject <NSObject> {}
+(id)alloc;
++(id)new;
-(id)init;
-(id)autorelease;
-(id)copy;
@@ -24,3 +25,12 @@
@interface PublicSubClass : PublicClass
@end
+
+@interface PublicParent : NSObject
+- (int)getZeroOverridden;
+@end
+
+@interface PublicSubClass2 : PublicParent
+- (int) getZeroOverridden;
+@end
+
diff --git a/test/Analysis/inlining/InlineObjCInstanceMethod.m b/test/Analysis/inlining/InlineObjCInstanceMethod.m
index d7b184e..31b6d5b 100644
--- a/test/Analysis/inlining/InlineObjCInstanceMethod.m
+++ b/test/Analysis/inlining/InlineObjCInstanceMethod.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -verify %s
#include "InlineObjCInstanceMethod.h"
diff --git a/test/Analysis/inlining/ObjCDynTypePopagation.m b/test/Analysis/inlining/ObjCDynTypePopagation.m
index 9604497..4faaa2c 100644
--- a/test/Analysis/inlining/ObjCDynTypePopagation.m
+++ b/test/Analysis/inlining/ObjCDynTypePopagation.m
@@ -1,28 +1,12 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic-bifurcate -verify %s
-typedef signed char BOOL;
-typedef struct objc_class *Class;
-typedef struct objc_object {
- Class isa;
-} *id;
+#include "InlineObjCInstanceMethod.h"
-void clang_analyzer_eval(BOOL);
+void clang_analyzer_eval(int);
-@protocol NSObject - (BOOL)isEqual:(id)object; @end
-@interface NSObject <NSObject> {}
-+(id)alloc;
--(id)init;
-+(id)new;
--(id)autorelease;
--(id)copy;
-- (Class)class;
--(id)retain;
-@end
+PublicSubClass2 *getObj();
-@interface MyParent : NSObject
-- (int)getZeroOverridden;
-@end
-@implementation MyParent
+@implementation PublicParent
- (int) getZeroOverridden {
return 1;
}
@@ -31,19 +15,12 @@
}
@end
-@interface MyClass : MyParent
-- (int) getZeroOverridden;
-@end
-
-MyClass *getObj();
-
-@implementation MyClass
+@implementation PublicSubClass2
- (int) getZeroOverridden {
return 0;
}
/* 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}}
@@ -51,7 +28,7 @@
+ (void) testAllocClass {
- id a = [MyClass alloc];
+ id a = [PublicSubClass2 alloc];
clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
}
@@ -79,19 +56,19 @@
// Casting to parent should not pessimize the dynamic type.
+ (void) testCastToParent {
id a = [[self alloc] init];
- MyParent *p = a;
+ PublicParent *p = a;
clang_analyzer_eval([p getZeroOverridden] == 0); // expected-warning{{TRUE}}
}
// The type of parameter gets used.
-+ (void)testTypeFromParam:(MyParent*) p {
++ (void)testTypeFromParam:(PublicParent*) p {
clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
}
// Test implicit cast.
// Note, in this case, p could also be a subclass of MyParent.
+ (void) testCastFromId:(id) a {
- MyParent *p = a;
+ PublicParent *p = a;
clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
}
@end
@@ -99,7 +76,7 @@
// TODO: Would be nice to handle the case of dynamically obtained class info
// as well. We need a MemRegion for class types for this.
int testDynamicClass(BOOL coin) {
- Class AllocClass = (coin ? [NSObject class] : [MyClass class]);
+ Class AllocClass = (coin ? [NSObject class] : [PublicSubClass2 class]);
id x = [[AllocClass alloc] init];
if (coin)
return [x getZero];
diff --git a/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m b/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m
index d337ee4..739e10f 100644
--- a/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m
+++ b/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic-bifurcate -verify %s
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end