xref: /llvm-project/clang/test/Analysis/cast-value-logic.cpp (revision 4448affede5100658530aea8793ae7a7bc05a110)
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