diff options
8 files changed, 51 insertions, 50 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 3785e900c8..d36aa1bd1b 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -61,16 +61,20 @@ template <typename T> struct ProgramStateTrait { /// 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 @@ public: /// \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 d8bb5ea7a5..f22d7404c0 100644 --- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -68,7 +68,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, 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 773600b096..6635067d0f 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -721,6 +721,7 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { // Find the the receiver type. const ObjCObjectPointerType *ReceiverT = 0; + bool CanBeSubClassed = false; QualType SupersType = E->getSuperType(); const MemRegion *Receiver = 0; @@ -733,17 +734,25 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { 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 a5a1369bfe..7e8b51fe0b 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 bae80c60ec..715b89eff8 100644 --- a/test/Analysis/inlining/InlineObjCInstanceMethod.h +++ b/test/Analysis/inlining/InlineObjCInstanceMethod.h @@ -11,6 +11,7 @@ typedef struct objc_object { @protocol NSObject - (BOOL)isEqual:(id)object; @end @interface NSObject <NSObject> {} +(id)alloc; ++(id)new; -(id)init; -(id)autorelease; -(id)copy; @@ -24,3 +25,12 @@ typedef struct objc_object { @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 d7b184e002..31b6d5baa6 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 960449758b..4faaa2cb30 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 - -typedef signed char BOOL; -typedef struct objc_class *Class; -typedef struct objc_object { - Class isa; -} *id; - -void clang_analyzer_eval(BOOL); - -@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 +// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic-bifurcate -verify %s -@interface MyParent : NSObject -- (int)getZeroOverridden; -@end -@implementation MyParent +#include "InlineObjCInstanceMethod.h" + +void clang_analyzer_eval(int); + +PublicSubClass2 *getObj(); + +@implementation PublicParent - (int) getZeroOverridden { return 1; } @@ -31,19 +15,12 @@ void clang_analyzer_eval(BOOL); } @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 @@ MyClass *getObj(); + (void) testAllocClass { - id a = [MyClass alloc]; + id a = [PublicSubClass2 alloc]; clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}} } @@ -79,19 +56,19 @@ MyClass *getObj(); // 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 @@ MyClass *getObj(); // 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 d337ee4b16..739e10f2a5 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 |