1 | // RUN: %check_clang_tidy %s modernize-use-nullptr %t -- \ |
2 | // RUN: -config="{CheckOptions: {modernize-use-nullptr.NullMacros: 'MY_NULL,NULL'}}" |
3 | |
4 | #define NULL 0 |
5 | |
6 | namespace std { |
7 | |
8 | typedef decltype(nullptr) nullptr_t; |
9 | |
10 | } // namespace std |
11 | |
12 | // Just to make sure make_null() could have side effects. |
13 | void external(); |
14 | |
15 | std::nullptr_t make_null() { |
16 | external(); |
17 | return nullptr; |
18 | } |
19 | |
20 | void func() { |
21 | void *CallTest = make_null(); |
22 | |
23 | int var = 1; |
24 | void *CommaTest = (var+=2, make_null()); |
25 | |
26 | int *CastTest = static_cast<int*>(make_null()); |
27 | } |
28 | |
29 | void dummy(int*) {} |
30 | void side_effect() {} |
31 | |
32 | #define MACRO_EXPANSION_HAS_NULL \ |
33 | void foo() { \ |
34 | dummy(0); \ |
35 | dummy(NULL); \ |
36 | side_effect(); \ |
37 | } |
38 | |
39 | MACRO_EXPANSION_HAS_NULL; |
40 | #undef MACRO_EXPANSION_HAS_NULL |
41 | |
42 | |
43 | void test_macro_expansion1() { |
44 | #define MACRO_EXPANSION_HAS_NULL \ |
45 | dummy(NULL); \ |
46 | side_effect(); |
47 | |
48 | MACRO_EXPANSION_HAS_NULL; |
49 | |
50 | #undef MACRO_EXPANSION_HAS_NULL |
51 | } |
52 | |
53 | // Test macro expansion with cast sequence, PR15572. |
54 | void test_macro_expansion2() { |
55 | #define MACRO_EXPANSION_HAS_NULL \ |
56 | dummy((int*)0); \ |
57 | side_effect(); |
58 | |
59 | MACRO_EXPANSION_HAS_NULL; |
60 | |
61 | #undef MACRO_EXPANSION_HAS_NULL |
62 | } |
63 | |
64 | void test_macro_expansion3() { |
65 | #define MACRO_EXPANSION_HAS_NULL \ |
66 | dummy(NULL); \ |
67 | side_effect(); |
68 | |
69 | #define OUTER_MACRO \ |
70 | MACRO_EXPANSION_HAS_NULL; \ |
71 | side_effect(); |
72 | |
73 | OUTER_MACRO; |
74 | |
75 | #undef OUTER_MACRO |
76 | #undef MACRO_EXPANSION_HAS_NULL |
77 | } |
78 | |
79 | void test_macro_expansion4() { |
80 | #define MY_NULL NULL |
81 | int *p = MY_NULL; |
82 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr [modernize-use-nullptr] |
83 | // CHECK-FIXES: int *p = nullptr; |
84 | #undef MY_NULL |
85 | } |
86 | |
87 | #define IS_EQ(x, y) if (x != y) return; |
88 | void test_macro_args() { |
89 | int i = 0; |
90 | int *Ptr; |
91 | |
92 | IS_EQ(static_cast<int*>(0), Ptr); |
93 | // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr |
94 | // CHECK-FIXES: IS_EQ(static_cast<int*>(nullptr), Ptr); |
95 | |
96 | IS_EQ(0, Ptr); // literal |
97 | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr |
98 | // CHECK-FIXES: IS_EQ(nullptr, Ptr); |
99 | |
100 | IS_EQ(NULL, Ptr); // macro |
101 | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr |
102 | // CHECK-FIXES: IS_EQ(nullptr, Ptr); |
103 | |
104 | // These are ok since the null literal is not spelled within a macro. |
105 | #define myassert(x) if (!(x)) return; |
106 | myassert(0 == Ptr); |
107 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr |
108 | // CHECK-FIXES: myassert(nullptr == Ptr); |
109 | |
110 | myassert(NULL == Ptr); |
111 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr |
112 | // CHECK-FIXES: myassert(nullptr == Ptr); |
113 | |
114 | // These are bad as the null literal is buried in a macro. |
115 | #define BLAH(X) myassert(0 == (X)); |
116 | #define BLAH2(X) myassert(NULL == (X)); |
117 | BLAH(Ptr); |
118 | BLAH2(Ptr); |
119 | |
120 | // Same as above but testing extra macro expansion. |
121 | #define EXPECT_NULL(X) IS_EQ(0, X); |
122 | #define EXPECT_NULL2(X) IS_EQ(NULL, X); |
123 | EXPECT_NULL(Ptr); |
124 | EXPECT_NULL2(Ptr); |
125 | |
126 | // Almost the same as above but now null literal is not in a macro so ok |
127 | // to transform. |
128 | #define EQUALS_PTR(X) IS_EQ(X, Ptr); |
129 | EQUALS_PTR(0); |
130 | // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr |
131 | // CHECK-FIXES: EQUALS_PTR(nullptr); |
132 | EQUALS_PTR(NULL); |
133 | // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr |
134 | // CHECK-FIXES: EQUALS_PTR(nullptr); |
135 | |
136 | // Same as above but testing extra macro expansion. |
137 | #define EQUALS_PTR_I(X) EQUALS_PTR(X) |
138 | EQUALS_PTR_I(0); |
139 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
140 | // CHECK-FIXES: EQUALS_PTR_I(nullptr); |
141 | EQUALS_PTR_I(NULL); |
142 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
143 | // CHECK-FIXES: EQUALS_PTR_I(nullptr); |
144 | |
145 | // Ok since null literal not within macro. However, now testing macro |
146 | // used as arg to another macro. |
147 | #define decorate(EXPR) side_effect(); EXPR; |
148 | decorate(IS_EQ(NULL, Ptr)); |
149 | // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr |
150 | // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr)); |
151 | decorate(IS_EQ(0, Ptr)); |
152 | // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr |
153 | // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr)); |
154 | |
155 | // This macro causes a NullToPointer cast to happen where 0 is assigned to z |
156 | // but the 0 literal cannot be replaced because it is also used as an |
157 | // integer in the comparison. |
158 | #define INT_AND_PTR_USE(X) do { int *z = X; if (X == 4) break; } while(false) |
159 | INT_AND_PTR_USE(0); |
160 | |
161 | // Both uses of X in this case result in NullToPointer casts so replacement |
162 | // is possible. |
163 | #define PTR_AND_PTR_USE(X) do { int *z = X; if (X != z) break; } while(false) |
164 | PTR_AND_PTR_USE(0); |
165 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr |
166 | // CHECK-FIXES: PTR_AND_PTR_USE(nullptr); |
167 | PTR_AND_PTR_USE(NULL); |
168 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr |
169 | // CHECK-FIXES: PTR_AND_PTR_USE(nullptr); |
170 | |
171 | #define OPTIONAL_CODE(...) __VA_ARGS__ |
172 | #define NOT_NULL dummy(0) |
173 | #define CALL(X) X |
174 | OPTIONAL_CODE(NOT_NULL); |
175 | CALL(NOT_NULL); |
176 | |
177 | #define ENTRY(X) {X} |
178 | struct A { |
179 | int *Ptr; |
180 | } a[2] = {ENTRY(0), {.Ptr: 0}}; |
181 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr |
182 | // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: use nullptr |
183 | // CHECK-FIXES: a[2] = {ENTRY(nullptr), {nullptr}}; |
184 | #undef ENTRY |
185 | |
186 | #define assert1(expr) (expr) ? 0 : 1 |
187 | #define assert2 assert1 |
188 | int *p; |
189 | assert2(p == 0); |
190 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
191 | // CHECK-FIXES: assert2(p == nullptr); |
192 | assert2(p == NULL); |
193 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
194 | // CHECK-FIXES: assert2(p == nullptr); |
195 | #undef assert2 |
196 | #undef assert1 |
197 | |
198 | #define ASSERT_EQ(a, b) a == b |
199 | #define ASSERT_NULL(x) ASSERT_EQ(static_cast<void *>(NULL), x) |
200 | int *pp; |
201 | ASSERT_NULL(pp); |
202 | ASSERT_NULL(NULL); |
203 | // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use nullptr |
204 | // CHECK-FIXES: ASSERT_NULL(nullptr); |
205 | #undef ASSERT_NULL |
206 | #undef ASSERT_EQ |
207 | } |
208 | |
209 | // One of the ancestor of the cast is a NestedNameSpecifierLoc. |
210 | class NoDef; |
211 | char function(NoDef *p); |
212 | #define F(x) (sizeof(function(x)) == 1) |
213 | template<class T, T t> |
214 | class C {}; |
215 | C<bool, F(0)> c; |
216 | // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr |
217 | // CHECK-FIXES: C<bool, F(nullptr)> c; |
218 | #undef F |
219 | |
220 | // Test default argument expression. |
221 | struct D { |
222 | explicit D(void *t, int *c = NULL) {} |
223 | // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use nullptr |
224 | // CHECK-FIXES: explicit D(void *t, int *c = nullptr) {} |
225 | }; |
226 | |
227 | void test_default_argument() { |
228 | D(nullptr); |
229 | } |
230 | |
231 | // Test on two neighbour CXXDefaultArgExprs nodes. |
232 | typedef unsigned long long uint64; |
233 | struct ZZ { |
234 | explicit ZZ(uint64, const uint64* = NULL) {} |
235 | // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: use nullptr |
236 | // CHECK-FIXES: explicit ZZ(uint64, const uint64* = nullptr) {} |
237 | operator bool() { return true; } |
238 | }; |
239 | |
240 | uint64 Hash(uint64 seed = 0) { return 0; } |
241 | |
242 | void f() { |
243 | bool a; |
244 | a = ZZ(Hash()); |
245 | } |
246 | |
247 | // Test on ignoring substituted template types. |
248 | template<typename T> |
249 | class TemplateClass { |
250 | public: |
251 | explicit TemplateClass(int a, T default_value = 0) {} |
252 | |
253 | void h(T *default_value = 0) {} |
254 | |
255 | void f(int* p = 0) {} |
256 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr |
257 | // CHECK-FIXES: void f(int* p = nullptr) {} |
258 | }; |
259 | |
260 | void IgnoreSubstTemplateType() { |
261 | TemplateClass<int*> a(1); |
262 | } |
263 | |
264 | // Test on casting nullptr. |
265 | struct G { |
266 | explicit G(bool, const char * = NULL) {} |
267 | // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use nullptr |
268 | // CHECK-FIXES: explicit G(bool, const char * = nullptr) {} |
269 | }; |
270 | bool g(const char*); |
271 | void test_cast_nullptr() { |
272 | G(g(nullptr)); |
273 | G(g((nullptr))); |
274 | G(g(static_cast<char*>(nullptr))); |
275 | G(g(static_cast<const char*>(nullptr))); |
276 | } |
277 | |
278 | // Test on recognizing multiple NULLs. |
279 | class H { |
280 | public: |
281 | H(bool); |
282 | }; |
283 | |
284 | #define T(expression) H(expression); |
285 | bool h(int *, int *, int * = nullptr); |
286 | void test_multiple_nulls() { |
287 | T(h(NULL, NULL)); |
288 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr |
289 | // CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use nullptr |
290 | // CHECK-FIXES: T(h(nullptr, nullptr)); |
291 | T(h(NULL, nullptr)); |
292 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr |
293 | // CHECK-FIXES: T(h(nullptr, nullptr)); |
294 | T(h(nullptr, NULL)); |
295 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
296 | // CHECK-FIXES: T(h(nullptr, nullptr)); |
297 | T(h(nullptr, nullptr)); |
298 | T(h(NULL, NULL, NULL)); |
299 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr |
300 | // CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use nullptr |
301 | // CHECK-MESSAGES: :[[@LINE-3]]:19: warning: use nullptr |
302 | // CHECK-FIXES: T(h(nullptr, nullptr, nullptr)); |
303 | } |
304 | #undef T |
305 | |