// 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 const T *castAs() const; template 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(A) && !dyn_cast(B)) clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} } void test_regions_isa(const Shape *A, const Shape *B) { if (isa(A) && !isa(B)) clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} } void test_regions_isa_variadic(const Shape *A, const Shape *B) { if (isa(A) && !isa(B)) clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} } void test_regions_isa_and_nonnull(const Shape *A, const Shape *B) { if (isa_and_nonnull(A) && !isa_and_nonnull(B)) clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} } void test_regions_isa_and_nonnull_variadic(const Shape *A, const Shape *B) { if (isa_and_nonnull(A) && !isa_and_nonnull(B)) clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} } namespace test_cast { void evalLogic(const Shape *S) { const Circle *C = cast(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(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(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(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(); 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(); 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(s); // no-crash } void test_non_reference_temporary_crash() { extern std::unique_ptr foo(); auto P = foo(); auto Q = cast(std::move(P)); // no-crash } double test_virtual_method_after_call(Shape *S) { if (isa(S)) return S->area(); return S->area() / 2; } void test_delete_crash() { extern Circle *makeCircle(); Shape *S = makeCircle(); delete cast(S); } } // namespace crashes