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 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 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 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 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 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 { 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 { 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 { 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 { 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 { 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 { 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 { 160 void test_non_reference_null_region_crash(Shape s) { 161 cast<Circle>(s); // no-crash 162 } 163 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 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 176 void test_delete_crash() { 177 extern Circle *makeCircle(); 178 Shape *S = makeCircle(); 179 delete cast<SuspiciouslySpecificCircle>(S); 180 } 181 } // namespace crashes 182