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