1// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
2
3#include "InlineObjCInstanceMethod.h"
4
5void clang_analyzer_eval(int);
6
7PublicSubClass2 *getObj();
8
9@implementation PublicParent
10- (int) getZeroOverridden {
11   return 1;
12}
13- (int) getZero {
14   return 0;
15}
16@end
17
18@implementation PublicSubClass2
19- (int) getZeroOverridden {
20   return 0;
21}
22
23/* Test that we get the right type from call to alloc. */
24+ (void) testAllocSelf {
25  id a = [self alloc];
26  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
27}
28
29
30+ (void) testAllocClass {
31  id a = [PublicSubClass2 alloc];
32  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
33}
34
35+ (void) testAllocSuperOverriden {
36  id a = [super alloc];
37  // Evaluates to 1 in the parent.
38  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{FALSE}}
39}
40
41+ (void) testAllocSuper {
42  id a = [super alloc];
43  clang_analyzer_eval([a getZero] == 0); // expected-warning{{TRUE}}
44}
45
46+ (void) testAllocInit {
47  id a = [[self alloc] init];
48  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
49}
50
51+ (void) testNewSelf {
52  id a = [self new];
53  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
54}
55
56// Casting to parent should not pessimize the dynamic type.
57+ (void) testCastToParent {
58 id a = [[self alloc] init];
59 PublicParent *p = a;
60  clang_analyzer_eval([p getZeroOverridden] == 0); // expected-warning{{TRUE}}
61}
62
63// The type of parameter gets used.
64+ (void)testTypeFromParam:(PublicParent*) p {
65  clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
66}
67
68// Test implicit cast.
69// Note, in this case, p could also be a subclass of MyParent.
70+ (void) testCastFromId:(id) a {
71  PublicParent *p = a;
72  clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
73}
74@end
75
76// TODO: Would be nice to handle the case of dynamically obtained class info
77// as well. We need a MemRegion for class types for this.
78int testDynamicClass(BOOL coin) {
79 Class AllocClass = (coin ? [NSObject class] : [PublicSubClass2 class]);
80 id x = [[AllocClass alloc] init];
81 if (coin)
82   return [x getZero];
83 return 1;
84}
85
86@interface UserClass : NSObject
87- (PublicSubClass2 *) _newPublicSubClass2;
88- (int) getZero;
89- (void) callNew;
90@end
91
92@implementation UserClass
93- (PublicSubClass2 *) _newPublicSubClass2 {
94  return [[PublicSubClass2 alloc] init];
95}
96- (int) getZero { return 5; }
97- (void) callNew {
98  PublicSubClass2 *x = [self _newPublicSubClass2];
99  clang_analyzer_eval([x getZero] == 0); //expected-warning{{TRUE}}
100}
101@end