1// RUN: %clang_analyze_cc1 -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+ (void)testAllocClass {
30  id a = [PublicSubClass2 alloc];
31  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
32}
33
34+ (void)testAllocSuperOverriden {
35  id a = [super alloc];
36  // Evaluates to 1 in the parent.
37  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{FALSE}}
38}
39
40+ (void)testAllocSuper {
41  id a = [super alloc];
42  clang_analyzer_eval([a getZero] == 0); // expected-warning{{TRUE}}
43}
44
45+ (void)testAllocInit {
46  id a = [[self alloc] init];
47  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
48}
49
50+ (void)testNewSelf {
51  id a = [self new];
52  clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
53}
54
55// Casting to parent should not pessimize the dynamic type.
56+ (void)testCastToParent {
57  id a = [[self alloc] init];
58  PublicParent *p = a;
59  clang_analyzer_eval([p getZeroOverridden] == 0); // expected-warning{{TRUE}}
60}
61
62// The type of parameter gets used.
63+ (void)testTypeFromParam:(PublicParent *)p {
64  clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
65}
66
67// Test implicit cast.
68// Note, in this case, p could also be a subclass of MyParent.
69+ (void)testCastFromId:(id)a {
70  PublicParent *p = a;
71  clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
72}
73@end
74
75// TODO: Would be nice to handle the case of dynamically obtained class info
76// as well. We need a MemRegion for class types for this.
77int testDynamicClass(BOOL coin) {
78  Class AllocClass = (coin ? [NSObject class] : [PublicSubClass2 class]);
79  id x = [[AllocClass alloc] init];
80  if (coin)
81    return [x getZero];
82  return 1;
83}
84
85@interface UserClass : NSObject
86- (PublicSubClass2 *)_newPublicSubClass2;
87- (int)getZero;
88- (void)callNew;
89@end
90
91@implementation UserClass
92- (PublicSubClass2 *)_newPublicSubClass2 {
93  return [[PublicSubClass2 alloc] init];
94}
95- (int)getZero {
96  return 5;
97}
98- (void)callNew {
99  PublicSubClass2 *x = [self _newPublicSubClass2];
100  clang_analyzer_eval([x getZero] == 0); //expected-warning{{TRUE}}
101}
102@end