1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s |
2 | |
3 | #include "InlineObjCInstanceMethod.h" |
4 | |
5 | void clang_analyzer_eval(int); |
6 | |
7 | PublicSubClass2 *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. |
78 | int 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 |