1 // RUN: %clang_analyze_cc1 -std=c++14 \
2 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
3 // RUN: -verify %s
4
5 #include "Inputs/llvm.h"
6
7 void clang_analyzer_numTimesReached();
8 void clang_analyzer_warnIfReached();
9 void clang_analyzer_eval(bool);
10
11 namespace clang {
12 struct Shape {
13 template <typename T>
14 const T *castAs() const;
15
16 template <typename T>
17 const T *getAs() const;
18
19 virtual double area();
20 };
21 class Triangle : public Shape {};
22 class Rectangle : public Shape {};
23 class Hexagon : public Shape {};
24 class Circle : public Shape {
25 public:
26 ~Circle();
27 };
28 class SuspiciouslySpecificCircle : public Circle {};
29 } // namespace clang
30
31 using namespace llvm;
32 using namespace clang;
33
test_regions_dyn_cast(const Shape * A,const Shape * B)34 void test_regions_dyn_cast(const Shape *A, const Shape *B) {
35 if (dyn_cast<Circle>(A) && !dyn_cast<Circle>(B))
36 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
37 }
38
test_regions_isa(const Shape * A,const Shape * B)39 void test_regions_isa(const Shape *A, const Shape *B) {
40 if (isa<Circle>(A) && !isa<Circle>(B))
41 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
42 }
43
test_regions_isa_variadic(const Shape * A,const Shape * B)44 void test_regions_isa_variadic(const Shape *A, const Shape *B) {
45 if (isa<Triangle, Rectangle, Hexagon>(A) &&
46 !isa<Rectangle, Hexagon, Circle>(B))
47 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
48 }
49
test_regions_isa_and_nonnull(const Shape * A,const Shape * B)50 void test_regions_isa_and_nonnull(const Shape *A, const Shape *B) {
51 if (isa_and_nonnull<Circle>(A) && !isa_and_nonnull<Circle>(B))
52 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
53 }
54
test_regions_isa_and_nonnull_variadic(const Shape * A,const Shape * B)55 void test_regions_isa_and_nonnull_variadic(const Shape *A, const Shape *B) {
56 if (isa_and_nonnull<Triangle, Rectangle, Hexagon>(A) &&
57 !isa_and_nonnull<Rectangle, Hexagon, Circle>(B))
58 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
59 }
60
61 namespace test_cast {
evalLogic(const Shape * S)62 void evalLogic(const Shape *S) {
63 const Circle *C = cast<Circle>(S);
64 clang_analyzer_numTimesReached(); // expected-warning {{1}}
65
66 if (S && C)
67 clang_analyzer_eval(C == S); // expected-warning {{TRUE}}
68
69 if (S && !C)
70 clang_analyzer_warnIfReached(); // no-warning
71
72 if (!S)
73 clang_analyzer_warnIfReached(); // no-warning
74 }
75 } // namespace test_cast
76
77 namespace test_dyn_cast {
evalLogic(const Shape * S)78 void evalLogic(const Shape *S) {
79 const Circle *C = dyn_cast<Circle>(S);
80 clang_analyzer_numTimesReached(); // expected-warning {{2}}
81
82 if (S && C)
83 clang_analyzer_eval(C == S); // expected-warning {{TRUE}}
84
85 if (S && !C)
86 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
87
88 if (!S)
89 clang_analyzer_warnIfReached(); // no-warning
90 }
91 } // namespace test_dyn_cast
92
93 namespace test_cast_or_null {
evalLogic(const Shape * S)94 void evalLogic(const Shape *S) {
95 const Circle *C = cast_or_null<Circle>(S);
96 clang_analyzer_numTimesReached(); // expected-warning {{2}}
97
98 if (S && C)
99 clang_analyzer_eval(C == S); // expected-warning {{TRUE}}
100
101 if (S && !C)
102 clang_analyzer_warnIfReached(); // no-warning
103
104 if (!S)
105 clang_analyzer_eval(!C); // expected-warning {{TRUE}}
106 }
107 } // namespace test_cast_or_null
108
109 namespace test_dyn_cast_or_null {
evalLogic(const Shape * S)110 void evalLogic(const Shape *S) {
111 const Circle *C = dyn_cast_or_null<Circle>(S);
112 clang_analyzer_numTimesReached(); // expected-warning {{3}}
113
114 if (S && C)
115 clang_analyzer_eval(C == S); // expected-warning {{TRUE}}
116
117 if (S && !C)
118 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
119
120 if (!S)
121 clang_analyzer_eval(!C); // expected-warning {{TRUE}}
122 }
123 } // namespace test_dyn_cast_or_null
124
125 namespace test_cast_as {
evalLogic(const Shape * S)126 void evalLogic(const Shape *S) {
127 const Circle *C = S->castAs<Circle>();
128 clang_analyzer_numTimesReached(); // expected-warning {{1}}
129
130 if (S && C)
131 clang_analyzer_eval(C == S);
132 // expected-warning@-1 {{TRUE}}
133
134 if (S && !C)
135 clang_analyzer_warnIfReached(); // no-warning
136
137 if (!S)
138 clang_analyzer_warnIfReached(); // no-warning
139 }
140 } // namespace test_cast_as
141
142 namespace test_get_as {
evalLogic(const Shape * S)143 void evalLogic(const Shape *S) {
144 const Circle *C = S->getAs<Circle>();
145 clang_analyzer_numTimesReached(); // expected-warning {{2}}
146
147 if (S && C)
148 clang_analyzer_eval(C == S);
149 // expected-warning@-1 {{TRUE}}
150
151 if (S && !C)
152 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
153
154 if (!S)
155 clang_analyzer_warnIfReached(); // no-warning
156 }
157 } // namespace test_get_as
158
159 namespace crashes {
test_non_reference_null_region_crash(Shape s)160 void test_non_reference_null_region_crash(Shape s) {
161 cast<Circle>(s); // no-crash
162 }
163
test_non_reference_temporary_crash()164 void test_non_reference_temporary_crash() {
165 extern std::unique_ptr<Shape> foo();
166 auto P = foo();
167 auto Q = cast<Circle>(std::move(P)); // no-crash
168 }
169
test_virtual_method_after_call(Shape * S)170 double test_virtual_method_after_call(Shape *S) {
171 if (isa<Circle>(S))
172 return S->area();
173 return S->area() / 2;
174 }
175
test_delete_crash()176 void test_delete_crash() {
177 extern Circle *makeCircle();
178 Shape *S = makeCircle();
179 delete cast<SuspiciouslySpecificCircle>(S);
180 }
181 } // namespace crashes
182