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 Circle : public Shape {
23 public:
24   ~Circle();
25 };
26 class SuspiciouslySpecificCircle : public Circle {};
27 } // namespace clang
28 
29 using namespace llvm;
30 using namespace clang;
31 
32 void test_regions_dyn_cast(const Shape *A, const Shape *B) {
33   if (dyn_cast<Circle>(A) && !dyn_cast<Circle>(B))
34     clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
35 }
36 
37 void test_regions_isa(const Shape *A, const Shape *B) {
38   if (isa<Circle>(A) && !isa<Circle>(B))
39     clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
40 }
41 
42 namespace test_cast {
43 void evalLogic(const Shape *S) {
44   const Circle *C = cast<Circle>(S);
45   clang_analyzer_numTimesReached(); // expected-warning {{1}}
46 
47   if (S && C)
48     clang_analyzer_eval(C == S); // expected-warning {{TRUE}}
49 
50   if (S && !C)
51     clang_analyzer_warnIfReached(); // no-warning
52 
53   if (!S)
54     clang_analyzer_warnIfReached(); // no-warning
55 }
56 } // namespace test_cast
57 
58 namespace test_dyn_cast {
59 void evalLogic(const Shape *S) {
60   const Circle *C = dyn_cast<Circle>(S);
61   clang_analyzer_numTimesReached(); // expected-warning {{2}}
62 
63   if (S && C)
64     clang_analyzer_eval(C == S); // expected-warning {{TRUE}}
65 
66   if (S && !C)
67     clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
68 
69   if (!S)
70     clang_analyzer_warnIfReached(); // no-warning
71 }
72 } // namespace test_dyn_cast
73 
74 namespace test_cast_or_null {
75 void evalLogic(const Shape *S) {
76   const Circle *C = cast_or_null<Circle>(S);
77   clang_analyzer_numTimesReached(); // expected-warning {{2}}
78 
79   if (S && C)
80     clang_analyzer_eval(C == S); // expected-warning {{TRUE}}
81 
82   if (S && !C)
83     clang_analyzer_warnIfReached(); // no-warning
84 
85   if (!S)
86     clang_analyzer_eval(!C); // expected-warning {{TRUE}}
87 }
88 } // namespace test_cast_or_null
89 
90 namespace test_dyn_cast_or_null {
91 void evalLogic(const Shape *S) {
92   const Circle *C = dyn_cast_or_null<Circle>(S);
93   clang_analyzer_numTimesReached(); // expected-warning {{3}}
94 
95   if (S && C)
96     clang_analyzer_eval(C == S); // expected-warning {{TRUE}}
97 
98   if (S && !C)
99     clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
100 
101   if (!S)
102     clang_analyzer_eval(!C); // expected-warning {{TRUE}}
103 }
104 } // namespace test_dyn_cast_or_null
105 
106 namespace test_cast_as {
107 void evalLogic(const Shape *S) {
108   const Circle *C = S->castAs<Circle>();
109   clang_analyzer_numTimesReached(); // expected-warning {{1}}
110 
111   if (S && C)
112     clang_analyzer_eval(C == S);
113   // expected-warning@-1 {{TRUE}}
114 
115   if (S && !C)
116     clang_analyzer_warnIfReached(); // no-warning
117 
118   if (!S)
119     clang_analyzer_warnIfReached(); // no-warning
120 }
121 } // namespace test_cast_as
122 
123 namespace test_get_as {
124 void evalLogic(const Shape *S) {
125   const Circle *C = S->getAs<Circle>();
126   clang_analyzer_numTimesReached(); // expected-warning {{2}}
127 
128   if (S && C)
129     clang_analyzer_eval(C == S);
130   // expected-warning@-1 {{TRUE}}
131 
132   if (S && !C)
133     clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
134 
135   if (!S)
136     clang_analyzer_warnIfReached(); // no-warning
137 }
138 } // namespace test_get_as
139 
140 namespace crashes {
141 void test_non_reference_null_region_crash(Shape s) {
142   cast<Circle>(s); // no-crash
143 }
144 
145 void test_non_reference_temporary_crash() {
146   extern std::unique_ptr<Shape> foo();
147   auto P = foo();
148   auto Q = cast<Circle>(std::move(P)); // no-crash
149 }
150 
151 double test_virtual_method_after_call(Shape *S) {
152   if (isa<Circle>(S))
153     return S->area();
154   return S->area() / 2;
155 }
156 
157 void test_delete_crash() {
158   extern Circle *makeCircle();
159   Shape *S = makeCircle();
160   delete cast<SuspiciouslySpecificCircle>(S);
161 }
162 } // namespace crashes
163