summaryrefslogtreecommitdiffstats
path: root/clang/test/Analysis/cast-value-logic.cpp
blob: 1411ede92e36641d4c2c72b72e4717527e3f792c (plain)
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
// 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 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}}
}

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
OpenPOWER on IntegriCloud