1 // RUN: %clang_analyze_cc1 -std=c++14 \
2 // RUN:  -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
3 // RUN:  -analyzer-output=text -verify %s
4 
5 #include "Inputs/llvm.h"
6 
7 namespace clang {
8 struct Shape {
9   template <typename T>
10   const T *castAs() const;
11 
12   template <typename T>
13   const T *getAs() const;
14 };
15 class Triangle : public Shape {};
16 class Circle : public Shape {};
17 } // namespace clang
18 
19 using namespace llvm;
20 using namespace clang;
21 
evalReferences(const Shape & S)22 void evalReferences(const Shape &S) {
23   const auto &C = dyn_cast<Circle>(S);
24   // expected-note@-1 {{Assuming 'S' is not a 'Circle'}}
25   // expected-note@-2 {{Dereference of null pointer}}
26   // expected-warning@-3 {{Dereference of null pointer}}
27 }
28 
evalNonNullParamNonNullReturnReference(const Shape & S)29 void evalNonNullParamNonNullReturnReference(const Shape &S) {
30   // Unmodeled cast from reference to pointer.
31   const auto *C = dyn_cast_or_null<Circle>(S);
32   // expected-note@-1 {{'C' initialized here}}
33 
34   if (!dyn_cast_or_null<Circle>(C)) {
35     // expected-note@-1 {{'C' is a 'Circle'}}
36     // expected-note@-2 {{Taking false branch}}
37     return;
38   }
39 
40   if (dyn_cast_or_null<Triangle>(C)) {
41     // expected-note@-1 {{Assuming 'C' is not a 'Triangle'}}
42     // expected-note@-2 {{Taking false branch}}
43     return;
44   }
45 
46   if (isa<Triangle>(C)) {
47     // expected-note@-1 {{'C' is not a 'Triangle'}}
48     // expected-note@-2 {{Taking false branch}}
49     return;
50   }
51 
52   if (isa<Circle>(C)) {
53     // expected-note@-1 {{'C' is a 'Circle'}}
54     // expected-note@-2 {{Taking true branch}}
55 
56     (void)(1 / !C);
57     // expected-note@-1 {{'C' is non-null}}
58     // expected-note@-2 {{Division by zero}}
59     // expected-warning@-3 {{Division by zero}}
60   }
61 }
62 
evalNonNullParamNonNullReturn(const Shape * S)63 void evalNonNullParamNonNullReturn(const Shape *S) {
64   const auto *C = cast<Circle>(S);
65   // expected-note@-1 {{'S' is a 'Circle'}}
66   // expected-note@-2 {{'C' initialized here}}
67 
68   if (!isa<Triangle>(C)) {
69     // expected-note@-1 {{Assuming 'C' is a 'Triangle'}}
70     // expected-note@-2 {{Taking false branch}}
71     return;
72   }
73 
74   if (!isa<Triangle>(C)) {
75     // expected-note@-1 {{'C' is a 'Triangle'}}
76     // expected-note@-2 {{Taking false branch}}
77     return;
78   }
79 
80   (void)(1 / !C);
81   // expected-note@-1 {{'C' is non-null}}
82   // expected-note@-2 {{Division by zero}}
83   // expected-warning@-3 {{Division by zero}}
84 }
85 
evalNonNullParamNullReturn(const Shape * S)86 void evalNonNullParamNullReturn(const Shape *S) {
87   const auto *C = dyn_cast_or_null<Circle>(S);
88   // expected-note@-1 {{Assuming 'S' is not a 'Circle'}}
89 
90   if (const auto *T = dyn_cast_or_null<Triangle>(S)) {
91     // expected-note@-1 {{Assuming 'S' is a 'Triangle'}}
92     // expected-note@-2 {{'T' initialized here}}
93     // expected-note@-3 {{'T' is non-null}}
94     // expected-note@-4 {{Taking true branch}}
95 
96     (void)(1 / !T);
97     // expected-note@-1 {{'T' is non-null}}
98     // expected-note@-2 {{Division by zero}}
99     // expected-warning@-3 {{Division by zero}}
100   }
101 }
102 
evalNullParamNullReturn(const Shape * S)103 void evalNullParamNullReturn(const Shape *S) {
104   const auto *C = dyn_cast_or_null<Circle>(S);
105   // expected-note@-1 {{Assuming null pointer is passed into cast}}
106   // expected-note@-2 {{'C' initialized to a null pointer value}}
107 
108   (void)(1 / (bool)C);
109   // expected-note@-1 {{Division by zero}}
110   // expected-warning@-2 {{Division by zero}}
111 }
112 
evalZeroParamNonNullReturnPointer(const Shape * S)113 void evalZeroParamNonNullReturnPointer(const Shape *S) {
114   const auto *C = S->castAs<Circle>();
115   // expected-note@-1 {{'S' is a 'Circle'}}
116   // expected-note@-2 {{'C' initialized here}}
117 
118   (void)(1 / !C);
119   // expected-note@-1 {{'C' is non-null}}
120   // expected-note@-2 {{Division by zero}}
121   // expected-warning@-3 {{Division by zero}}
122 }
123 
evalZeroParamNonNullReturn(const Shape & S)124 void evalZeroParamNonNullReturn(const Shape &S) {
125   const auto *C = S.castAs<Circle>();
126   // expected-note@-1 {{'C' initialized here}}
127 
128   (void)(1 / !C);
129   // expected-note@-1 {{'C' is non-null}}
130   // expected-note@-2 {{Division by zero}}
131   // expected-warning@-3 {{Division by zero}}
132 }
133 
evalZeroParamNullReturn(const Shape * S)134 void evalZeroParamNullReturn(const Shape *S) {
135   const auto &C = S->getAs<Circle>();
136   // expected-note@-1 {{Assuming 'S' is not a 'Circle'}}
137   // expected-note@-2 {{Storing null pointer value}}
138   // expected-note@-3 {{'C' initialized here}}
139 
140   if (!dyn_cast_or_null<Triangle>(S)) {
141     // expected-note@-1 {{Assuming 'S' is a 'Triangle'}}
142     // expected-note@-2 {{Taking false branch}}
143     return;
144   }
145 
146   if (!dyn_cast_or_null<Triangle>(S)) {
147     // expected-note@-1 {{'S' is a 'Triangle'}}
148     // expected-note@-2 {{Taking false branch}}
149     return;
150   }
151 
152   (void)(1 / (bool)C);
153   // expected-note@-1 {{Division by zero}}
154   // expected-warning@-2 {{Division by zero}}
155 }
156