blob: ab1dfc5ec14b6aa3bde2111b00ced92c07e35ea0 [file] [log] [blame]
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-config ipa=dynamic-bifurcate -verify %s
#include "InlineObjCInstanceMethod.h"
@interface MyParent : NSObject
- (int)getZero;
@end
@implementation MyParent
- (int)getZero {
return 0;
}
@end
@interface PublicClass () {
int value2;
}
@property (readwrite) int value1;
- (void)setValue2:(int)newValue2;
@end
@implementation PublicClass
- (int)getZeroPublic {
return 0;
}
@synthesize value1;
- (int)value2 {
return value2;
}
- (void)setValue2:(int)newValue {
value2 = newValue;
}
- (int)value3 {
return value3;
}
- (void)setValue3:(int)newValue {
value3 = newValue;
}
@end
@interface MyClassWithPublicParent : PublicClass
- (int)getZeroPublic;
@end
@implementation MyClassWithPublicParent
- (int)getZeroPublic {
return 0;
}
@end
// Category overrides a public method.
@interface PublicSubClass (PrvateCat)
- (int) getZeroPublic;
@end
@implementation PublicSubClass (PrvateCat)
- (int)getZeroPublic {
return 0;
}
@end
@interface MyClass : MyParent {
int value;
}
- (int)getZero;
@property int value;
@end
// Since class is private, we assume that it cannot be subclassed.
// False negative: this class is "privately subclassed". this is very rare
// in practice.
@implementation MyClass
+ (int) testTypeFromParam:(MyParent*) p {
int m = 0;
int z = [p getZero];
if (z)
return 5/m; // false negative
return 5/[p getZero];// expected-warning {{Division by zero}}
}
// Here only one definition is possible, since the declaration is not visible
// from outside.
+ (int) testTypeFromParamPrivateChild:(MyClass*) c {
int m = 0;
int z = [c getZero]; // MyClass overrides getZero to return '1'.
if (z)
return 5/m; // expected-warning {{Division by zero}}
return 5/[c getZero];//no warning
}
- (int)getZero {
return 1;
}
- (int)value {
return value;
}
- (void)setValue:(int)newValue {
value = newValue;
}
// Test ivar access.
- (int) testIvarInSelf {
value = 0;
return 5/value; // expected-warning {{Division by zero}}
}
+ (int) testIvar: (MyClass*) p {
p.value = 0;
return 5/p.value; // expected-warning {{Division by zero}}
}
// Test simple property access.
+ (int) testProperty: (MyClass*) p {
int x= 0;
[p setValue:0];
return 5/[p value]; // expected-warning {{Division by zero}}
}
@end
// The class is prvate and is not subclassed.
int testCallToPublicAPIInParent(MyClassWithPublicParent *p) {
int m = 0;
int z = [p getZeroPublic];
if (z)
return 5/m; // no warning
return 5/[p getZeroPublic];// expected-warning {{Division by zero}}
}
// When the called method is public (due to it being defined outside of main file),
// split the path and analyze both branches.
// In this case, p can be either the object of type MyParent* or MyClass*:
// - If it's MyParent*, getZero returns 0.
// - If it's MyClass*, getZero returns 1 and 'return 5/m' is reachable.
// Declaration is provate, but p can be a subclass (MyClass*).
int testCallToPublicAPI(PublicClass *p) {
int m = 0;
int z = [p getZeroPublic];
if (z)
return 5/m; // expected-warning {{Division by zero}}
return 5/[p getZeroPublic];// expected-warning {{Division by zero}}
}
// Even though the method is privately declared in the category, the parent
// declares the method as public. Assume the instance can be subclassed.
int testCallToPublicAPICat(PublicSubClass *p) {
int m = 0;
int z = [p getZeroPublic];
if (z)
return 5/m; // expected-warning {{Division by zero}}
return 5/[p getZeroPublic];// expected-warning {{Division by zero}}
}
// Test public property - properties should always be inlined, regardless
// weither they are "public" or private.
int testPublicProperty(PublicClass *p) {
int x = 0;
p.value3 = 0;
if (p.value3 != 0)
return 5/x;
return 5/p.value3;// expected-warning {{Division by zero}}
}
int testExtension(PublicClass *p) {
int x = 0;
[p setValue2:0];
if ([p value2] != 0)
return 5/x; // expected-warning {{Division by zero}}
return 5/[p value2]; // expected-warning {{Division by zero}}
}
// TODO: we do not handle synthesized properties yet.
int testPropertySynthesized(PublicClass *p) {
[p setValue1:0];
return 5/[p value1];
}
// Test definition not available edge case.
@interface DefNotAvailClass : NSObject
@end
id testDefNotAvailableInlined(DefNotAvailClass *C) {
return [C mem]; // expected-warning {{instance method '-mem' not found}}
}
id testDefNotAvailable(DefNotAvailClass *C) {
return testDefNotAvailableInlined(C);
}