// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=osx.cocoa.MissingSuperCall -verify -Wno-objc-root-class %s

// Define used Classes
@protocol NSObject
- (id)retain;
- (oneway void)release;
@end
@interface NSObject <NSObject> {}
- (id)init;
+ (id)alloc;
@end
typedef char BOOL;
typedef double NSTimeInterval;
typedef enum UIViewAnimationOptions {
    UIViewAnimationOptionLayoutSubviews = 1 <<  0
} UIViewAnimationOptions;
@interface NSCoder : NSObject {}
@end

// Define the Superclasses for our Checks
@interface UIViewController : NSObject {}
- (void)addChildViewController:(UIViewController *)childController;
- (void)viewDidAppear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
- (void)viewDidUnload;
- (void)viewDidLoad;
- (void)viewWillUnload;
- (void)viewWillAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated;
- (void)didReceiveMemoryWarning;
- (void)removeFromParentViewController;
- (void)transitionFromViewController:(UIViewController *)fromViewController
  toViewController:(UIViewController *)toViewController 
  duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options
  animations:(void (^)(void))animations
  completion:(void (^)(BOOL finished))completion;
@end
@interface UIResponder : NSObject {}
- (BOOL)resignFirstResponder;
@end
@interface NSResponder : NSObject {}
- (void)restoreStateWithCoder:(NSCoder *)coder;
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder;
@end
@interface NSDocument : NSObject {}
- (void)restoreStateWithCoder:(NSCoder *)coder;
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder;
@end

// Checks

// Do not warn if UIViewController/*Responder/NSDocument is not our superclass
@interface TestA 
@end
@implementation TestA

- (void)addChildViewController:(UIViewController *)childController {}
- (void)viewDidAppear:(BOOL)animated {}
- (void)viewDidDisappear:(BOOL)animated {}
- (void)viewDidUnload {}
- (void)viewDidLoad {}
- (void)viewWillUnload {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)viewWillDisappear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}
- (void)removeFromParentViewController {}
- (BOOL)resignFirstResponder { return 0; }
- (void)restoreStateWithCoder:(NSCoder *)coder {}
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {}
@end

// Warn if UIViewController is our superclass and we do not call super
@interface TestB : UIViewController {}
@end
@implementation TestB

- (void)addChildViewController:(UIViewController *)childController {  
  int addChildViewController = 5;
  for (int i = 0; i < addChildViewController; i++)
  	[self viewDidAppear:i];
} // expected-warning {{The 'addChildViewController:' instance method in UIViewController subclass 'TestB' is missing a [super addChildViewController:] call}}
- (void)viewDidAppear:(BOOL)animated {} // expected-warning {{The 'viewDidAppear:' instance method in UIViewController subclass 'TestB' is missing a [super viewDidAppear:] call}}
- (void)viewDidDisappear:(BOOL)animated {} // expected-warning {{The 'viewDidDisappear:' instance method in UIViewController subclass 'TestB' is missing a [super viewDidDisappear:] call}}
- (void)viewDidUnload {} // expected-warning {{The 'viewDidUnload' instance method in UIViewController subclass 'TestB' is missing a [super viewDidUnload] call}}
- (void)viewDidLoad {} // expected-warning {{The 'viewDidLoad' instance method in UIViewController subclass 'TestB' is missing a [super viewDidLoad] call}}
- (void)viewWillUnload {} // expected-warning {{The 'viewWillUnload' instance method in UIViewController subclass 'TestB' is missing a [super viewWillUnload] call}}
- (void)viewWillAppear:(BOOL)animated {} // expected-warning {{The 'viewWillAppear:' instance method in UIViewController subclass 'TestB' is missing a [super viewWillAppear:] call}}
- (void)viewWillDisappear:(BOOL)animated {} // expected-warning {{The 'viewWillDisappear:' instance method in UIViewController subclass 'TestB' is missing a [super viewWillDisappear:] call}}
- (void)didReceiveMemoryWarning {} // expected-warning {{The 'didReceiveMemoryWarning' instance method in UIViewController subclass 'TestB' is missing a [super didReceiveMemoryWarning] call}}
- (void)removeFromParentViewController {} // expected-warning {{The 'removeFromParentViewController' instance method in UIViewController subclass 'TestB' is missing a [super removeFromParentViewController] call}}

// Do not warn for methods were it shouldn't
- (void)shouldAutorotate {}
@end

// Do not warn if UIViewController is our superclass but we did call super
@interface TestC : UIViewController {}
@end
@implementation TestC

- (BOOL)methodReturningStuff {
  return 1;
}

- (void)methodDoingStuff {
  [super removeFromParentViewController];
}

- (void)addChildViewController:(UIViewController *)childController {
  [super addChildViewController:childController];
}

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
} 

- (void)viewDidDisappear:(BOOL)animated {
  [super viewDidDisappear:animated]; 
}

- (void)viewDidUnload {
  [super viewDidUnload];
}

- (void)viewDidLoad {
  [super viewDidLoad];
}

- (void)viewWillUnload {
  [super viewWillUnload];
} 

- (void)viewWillAppear:(BOOL)animated {
  int i = 0; // Also don't start warning just because we do additional stuff
  i++;
  [self viewDidDisappear:i];
  [super viewWillAppear:animated];
} 

- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:[self methodReturningStuff]];
}

- (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
}

// We expect a warning here because at the moment the super-call can't be 
// done from another method.
- (void)removeFromParentViewController { 
  [self methodDoingStuff]; 
} // expected-warning {{The 'removeFromParentViewController' instance method in UIViewController subclass 'TestC' is missing a [super removeFromParentViewController] call}}
@end


// Do warn for UIResponder subclasses that don't call super
@interface TestD : UIResponder {}
@end
@implementation TestD

- (BOOL)resignFirstResponder {
  return 0;
} // expected-warning {{The 'resignFirstResponder' instance method in UIResponder subclass 'TestD' is missing a [super resignFirstResponder] call}}
@end

// Do not warn for UIResponder subclasses that do the right thing
@interface TestE : UIResponder {}
@end
@implementation TestE

- (BOOL)resignFirstResponder {
  return [super resignFirstResponder];
}
@end

// Do warn for NSResponder subclasses that don't call super
@interface TestF : NSResponder {}
@end
@implementation TestF

- (void)restoreStateWithCoder:(NSCoder *)coder {
} // expected-warning {{The 'restoreStateWithCoder:' instance method in NSResponder subclass 'TestF' is missing a [super restoreStateWithCoder:] call}}
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
} // expected-warning {{The 'encodeRestorableStateWithCoder:' instance method in NSResponder subclass 'TestF' is missing a [super encodeRestorableStateWithCoder:] call}}
@end

// Do not warn for NSResponder subclasses that do the right thing
@interface TestG : NSResponder {}
@end
@implementation TestG

- (void)restoreStateWithCoder:(NSCoder *)coder {
	[super restoreStateWithCoder:coder];
}
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
	[super encodeRestorableStateWithCoder:coder];
}
@end

// Do warn for NSDocument subclasses that don't call super
@interface TestH : NSDocument {}
@end
@implementation TestH

- (void)restoreStateWithCoder:(NSCoder *)coder {
} // expected-warning {{The 'restoreStateWithCoder:' instance method in NSDocument subclass 'TestH' is missing a [super restoreStateWithCoder:] call}}
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
} // expected-warning {{The 'encodeRestorableStateWithCoder:' instance method in NSDocument subclass 'TestH' is missing a [super encodeRestorableStateWithCoder:] call}}
@end

// Do not warn for NSDocument subclasses that do the right thing
@interface TestI : NSDocument {}
@end
@implementation TestI

- (void)restoreStateWithCoder:(NSCoder *)coder {
	[super restoreStateWithCoder:coder];
}
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
	[super encodeRestorableStateWithCoder:coder];
}
@end