182 lines
4.7 KiB
C++
182 lines
4.7 KiB
C++
// 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
|