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