|  | // 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 |