[analyzer] CastValueChecker: Store the dynamic types and casts
Summary:
This patch introduces `DynamicCastInfo` similar to `DynamicTypeInfo` which
is stored in `CastSets` which are storing the dynamic cast informations of
objects based on memory regions. It could be used to store and check the
casts and prevent infeasible paths.
Reviewed By: NoQ
Differential Revision: https://reviews.llvm.org/D66325
llvm-svn: 369605
diff --git a/clang/test/Analysis/cast-value-logic.cpp b/clang/test/Analysis/cast-value-logic.cpp
new file mode 100644
index 0000000..32001d8
--- /dev/null
+++ b/clang/test/Analysis/cast-value-logic.cpp
@@ -0,0 +1,128 @@
+// RUN: %clang_analyze_cc1 \
+// 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;
+};
+class Triangle : public Shape {};
+class Circle : public Shape {};
+} // namespace clang
+
+using namespace llvm;
+using namespace clang;
+
+void test_regions(const Shape *A, const Shape *B) {
+ if (dyn_cast<Circle>(A) && !dyn_cast<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
+