brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.7 KiB · 7ce8ea8 Raw
403 lines · plain
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify -analyzer-config eagerly-assume=false %s2 3void clang_analyzer_checkInlined(int);4void clang_analyzer_eval(int);5 6// Test inlining of ObjC class methods.7 8typedef signed char BOOL;9#define YES ((BOOL)1)10#define NO ((BOOL)0)11typedef struct objc_class *Class;12typedef struct objc_object {13  Class isa;14} * id;15@protocol NSObject16- (BOOL)isEqual:(id)object;17@end18@interface NSObject <NSObject> {}19+ (id)alloc;20+ (Class)class;21+ (Class)superclass;22- (id)init;23- (id)autorelease;24- (id)copy;25- (Class)class;26- (instancetype)self;27- (id)retain;28@end29 30// Vanila: ObjC class method is called by name.31@interface MyParent : NSObject32+ (int)getInt;33@end34@interface MyClass : MyParent35+ (int)getInt;36@end37@implementation MyClass38+ (int)testClassMethodByName {39    int y = [MyClass getInt];40    return 5/y; // expected-warning {{Division by zero}}41}42+ (int)getInt {43  return 0;44}45@end46 47// The definition is defined by the parent. Make sure we find it and inline.48@interface MyParentDIP : NSObject49+ (int)getInt;50@end51@interface MyClassDIP : MyParentDIP52@end53@implementation MyClassDIP54+ (int)testClassMethodByName {55    int y = [MyClassDIP getInt];56    return 5/y; // expected-warning {{Division by zero}}57}58@end59@implementation MyParentDIP60+ (int)getInt {61    return 0;62}63@end64 65// ObjC class method is called by name. Definition is in the category.66@interface AAA : NSObject67@end68@interface AAA (MyCat)69+ (int)getInt;70@end71int foo(void) {72    int y = [AAA getInt];73    return 5/y; // expected-warning {{Division by zero}}74}75@implementation AAA76@end77@implementation AAA (MyCat)78+ (int)getInt {79    return 0;80}81@end82 83// ObjC class method is called by name. Definition is in the parent category.84@interface PPP : NSObject85@end86@interface PPP (MyCat)87+ (int)getInt;88@end89@interface CCC : PPP90@end91int foo4(void) {92    int y = [CCC getInt];93    return 5/y; // expected-warning {{Division by zero}}94}95@implementation PPP96@end97@implementation PPP (MyCat)98+ (int)getInt {99    return 0;100}101@end102 103// There is no declaration in the class but there is one in the parent. Make 104// sure we pick the definition from the class and not the parent.105@interface MyParentTricky : NSObject106+ (int)getInt;107@end108@interface MyClassTricky : MyParentTricky109@end110@implementation MyParentTricky111+ (int)getInt {112    return 0;113}114@end115@implementation MyClassTricky116+ (int)getInt {117  return 1;118}119+ (int)testClassMethodByName {120    int y = [MyClassTricky getInt];121    return 5/y; // no-warning122}123@end124 125// ObjC class method is called by unknown class declaration (passed in as a 126// parameter). We should not inline in such case.127@interface MyParentUnknown : NSObject128+ (int)getInt;129@end130@interface MyClassUnknown : MyParentUnknown131+ (int)getInt;132@end133@implementation MyClassUnknown134+ (int)testClassVariableByUnknownVarDecl: (Class)cl  {135  int y = [cl getInt];136  return 3/y; // no-warning137}138+ (int)getInt {139  return 0;140}141@end142 143// ObjC class method call through a decl with a known type.144// Note, [self class] could be a subclass. Do we still want to inline here?145@interface MyClassKT : NSObject146@end147@interface MyClassKT (MyCatKT)148+ (int)getInt;149@end150@implementation MyClassKT (MyCatKT)151+ (int)getInt {152    return 0;153}154@end155@implementation MyClassKT156- (int)testClassMethodByKnownVarDecl {157  Class currentClass = [self class];158  int y = [currentClass getInt];159  return 5 / y; // expected-warning{{Division by zero}}160}161@end162 163// Another false negative due to us not reasoning about self, which in this 164// case points to the object of the class in the call site and should be equal 165// to [MyParent class].166@interface MyParentSelf : NSObject167+ (int)testSelf;168@end169@implementation MyParentSelf170+ (int)testSelf {171  if (self == [MyParentSelf class])172      return 0;173    else174      return 1;175}176@end177@interface MyClassSelf : MyParentSelf178@end179@implementation MyClassSelf180+ (int)testClassMethodByKnownVarDecl {181  int y = [MyParentSelf testSelf];182  return 5/y; // expected-warning{{Division by zero}}183}184@end185int foo2(void) {186  int y = [MyParentSelf testSelf];187  return 5/y; // expected-warning{{Division by zero}}188}189 190// TODO: We do not inline 'getNum' in the following case, where the value of 191// 'self' in call '[self getNum]' is available and evaualtes to 192// 'SelfUsedInParentChild' if it's called from fooA.193// Self region should get created before we call foo and yje call to super 194// should keep it live. 195@interface SelfUsedInParent : NSObject196+ (int)getNum;197+ (int)foo;198@end199@implementation SelfUsedInParent200+ (int)getNum {return 5;}201+ (int)foo {202  int r = [self getNum];203  clang_analyzer_eval(r == 5); // expected-warning{{TRUE}}204  return r;205}206@end207@interface SelfUsedInParentChild : SelfUsedInParent208+ (int)getNum;209+ (int)fooA;210@end211@implementation SelfUsedInParentChild212+ (int)getNum {return 0;}213+ (int)fooA {214  return [super foo];215}216@end217int checkSelfUsedInparentClassMethod(void) {218    return 5/[SelfUsedInParentChild fooA];219}220 221 222@interface Rdar15037033 : NSObject223@end224 225void rdar15037033(void) {226  [Rdar15037033 forwardDeclaredMethod]; // expected-warning {{class method '+forwardDeclaredMethod' not found}}227  [Rdar15037033 forwardDeclaredVariadicMethod:1, 2, 3, 0]; // expected-warning {{class method '+forwardDeclaredVariadicMethod:' not found}}228}229 230@implementation Rdar15037033231 232+ (void)forwardDeclaredMethod {233  clang_analyzer_checkInlined(1); // expected-warning{{TRUE}}234}235 236+ (void)forwardDeclaredVariadicMethod:(int)x, ... {237  clang_analyzer_checkInlined(0); // no-warning238}239@end240 241@interface SelfClassTestParent : NSObject242-(unsigned)returns10;243+(unsigned)returns20;244+(unsigned)returns30;245@end246 247@interface SelfClassTest : SelfClassTestParent248- (unsigned)returns10;249+ (unsigned)returns20;250+ (unsigned)returns30;251@end252 253@implementation SelfClassTestParent254- (unsigned)returns10 {255  return 100;256}257+ (unsigned)returns20 {258  return 100;259}260+ (unsigned)returns30 {261  return 100;262}263 264- (void)testSelfReassignment {265  // Check that we didn't hardcode type for self.266  self = [[[SelfClassTest class] alloc] init];267  Class actuallyChildClass = [self class];268  unsigned result = [actuallyChildClass returns30];269  clang_analyzer_eval(result == 30); // expected-warning{{TRUE}}270}271@end272 273@implementation SelfClassTest274- (unsigned)returns10 {275  return 10;276}277+ (unsigned)returns20 {278  return 20;279}280+ (unsigned)returns30 {281  return 30;282}283+ (BOOL)isClass {284  return YES;285}286- (BOOL)isClass {287  return NO;288}289+ (SelfClassTest *)create {290  return [[self alloc] init];291}292+ (void)classMethod {293  unsigned result1 = [self returns20];294  clang_analyzer_eval(result1 == 20); // expected-warning{{TRUE}}295 296  unsigned result2 = [[self class] returns30];297  clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}}298 299  unsigned result3 = [[super class] returns30];300  clang_analyzer_eval(result3 == 100); // expected-warning{{TRUE}}301 302  // Check that class info is propagated with data303  Class class41 = [self class];304  Class class42 = class41;305  unsigned result4 = [class42 returns30];306  clang_analyzer_eval(result4 == 30); // expected-warning{{TRUE}}307 308  Class class51 = [super class];309  Class class52 = class51;310  unsigned result5 = [class52 returns30];311  clang_analyzer_eval(result5 == 100); // expected-warning{{TRUE}}312}313- (void)instanceMethod {314  unsigned result0 = [self returns10];315  clang_analyzer_eval(result0 == 10); // expected-warning{{TRUE}}316 317  unsigned result2 = [[self class] returns30];318  clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}}319 320  unsigned result3 = [[super class] returns30];321  clang_analyzer_eval(result3 == 100); // expected-warning{{TRUE}}322 323  // Check that class info is propagated with data324  Class class41 = [self class];325  Class class42 = class41;326  unsigned result4 = [class42 returns30];327  clang_analyzer_eval(result4 == 30); // expected-warning{{TRUE}}328 329  Class class51 = [super class];330  Class class52 = class51;331  unsigned result5 = [class52 returns30];332  clang_analyzer_eval(result5 == 100); // expected-warning{{TRUE}}333 334  // Check that we inline class methods when class object is a receiver335  Class class6 = [self class];336  BOOL calledClassMethod = [class6 isClass];337  clang_analyzer_eval(calledClassMethod == YES); // expected-warning{{TRUE}}338 339  // Check that class info is propagated through the 'self' method340  Class class71 = [self class];341  Class class72 = [class71 self];342  unsigned result7 = [class72 returns30];343  clang_analyzer_eval(result7 == 30); // expected-warning{{TRUE}}344 345  // Check that 'class' and 'super' info from direct invocation of the346  // corresponding class methods is propagated with data347  Class class8 = [SelfClassTest class];348  unsigned result8 = [class8 returns30];349  clang_analyzer_eval(result8 == 30); // expected-warning{{TRUE}}350 351  Class class9 = [SelfClassTest superclass];352  unsigned result9 = [class9 returns30];353  clang_analyzer_eval(result9 == 100); // expected-warning{{TRUE}}354 355  // Check that we get class from a propagated type356  SelfClassTestParent *selfAsParent10 = [[SelfClassTest alloc] init];357  Class class10 = [selfAsParent10 class];358  unsigned result10 = [class10 returns30];359  clang_analyzer_eval(result10 == 30); // expected-warning{{TRUE}}360 361  SelfClassTestParent *selfAsParent11 = [[[self class] alloc] init];362  Class class11 = [selfAsParent11 class];363  unsigned result11 = [class11 returns30];364  clang_analyzer_eval(result11 == 30); // expected-warning{{TRUE}}365}366@end367 368@interface Parent : NSObject369+ (int)a;370+ (int)b;371@end372@interface Child : Parent373@end374@interface Other : NSObject375+(void)run;376@end377int main(int argc, const char * argv[]) {378  @autoreleasepool {379    [Other run];380  }381  return 0;382}383@implementation Other384+(void)run {385  int result = [Child a];386  // TODO: This should return 100.387  clang_analyzer_eval(result == 12); // expected-warning{{TRUE}}388}389@end390@implementation Parent391+ (int)a; {392  return [self b];393}394+ (int)b; {395  return 12;396}397@end398@implementation Child399+ (int)b; {400  return 100;401}402@end403