| 1 | // RUN: %check_clang_tidy --match-partial-fixes %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 | template <typename T> struct pear { |
| 88 | // If you say __null (or NULL), we assume that T will always be a pointer |
| 89 | // type, so we suggest replacing it with nullptr. (We only check __null here, |
| 90 | // because in this test NULL is defined as 0, but real library implementations |
| 91 | // it is often defined as __null and the check will catch it.) |
| 92 | void f() { x = __null; } |
| 93 | // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr [modernize-use-nullptr] |
| 94 | // CHECK-FIXES: x = nullptr; |
| 95 | |
| 96 | // But if you say 0, we allow the possibility that T can be used with integral |
| 97 | // and pointer types, and "0" is an acceptable initializer (even if "{}" might |
| 98 | // be even better). |
| 99 | void g() { y = 0; } |
| 100 | // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use nullptr |
| 101 | |
| 102 | T x; |
| 103 | T y; |
| 104 | }; |
| 105 | void test_templated() { |
| 106 | pear<int*> p; |
| 107 | p.f(); |
| 108 | p.g(); |
| 109 | dummy(p.x); |
| 110 | } |
| 111 | |
| 112 | #define IS_EQ(x, y) if (x != y) return; |
| 113 | void test_macro_args() { |
| 114 | int i = 0; |
| 115 | int *Ptr; |
| 116 | |
| 117 | IS_EQ(static_cast<int*>(0), Ptr); |
| 118 | // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr |
| 119 | // CHECK-FIXES: IS_EQ(static_cast<int*>(nullptr), Ptr); |
| 120 | |
| 121 | IS_EQ(0, Ptr); // literal |
| 122 | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr |
| 123 | // CHECK-FIXES: IS_EQ(nullptr, Ptr); |
| 124 | |
| 125 | IS_EQ(NULL, Ptr); // macro |
| 126 | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr |
| 127 | // CHECK-FIXES: IS_EQ(nullptr, Ptr); |
| 128 | |
| 129 | // These are ok since the null literal is not spelled within a macro. |
| 130 | #define myassert(x) if (!(x)) return; |
| 131 | myassert(0 == Ptr); |
| 132 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr |
| 133 | // CHECK-FIXES: myassert(nullptr == Ptr); |
| 134 | |
| 135 | myassert(NULL == Ptr); |
| 136 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr |
| 137 | // CHECK-FIXES: myassert(nullptr == Ptr); |
| 138 | |
| 139 | // These are bad as the null literal is buried in a macro. |
| 140 | #define BLAH(X) myassert(0 == (X)); |
| 141 | #define BLAH2(X) myassert(NULL == (X)); |
| 142 | BLAH(Ptr); |
| 143 | BLAH2(Ptr); |
| 144 | |
| 145 | // Same as above but testing extra macro expansion. |
| 146 | #define EXPECT_NULL(X) IS_EQ(0, X); |
| 147 | #define EXPECT_NULL2(X) IS_EQ(NULL, X); |
| 148 | EXPECT_NULL(Ptr); |
| 149 | EXPECT_NULL2(Ptr); |
| 150 | |
| 151 | // Almost the same as above but now null literal is not in a macro so ok |
| 152 | // to transform. |
| 153 | #define EQUALS_PTR(X) IS_EQ(X, Ptr); |
| 154 | EQUALS_PTR(0); |
| 155 | // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr |
| 156 | // CHECK-FIXES: EQUALS_PTR(nullptr); |
| 157 | EQUALS_PTR(NULL); |
| 158 | // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr |
| 159 | // CHECK-FIXES: EQUALS_PTR(nullptr); |
| 160 | |
| 161 | // Same as above but testing extra macro expansion. |
| 162 | #define EQUALS_PTR_I(X) EQUALS_PTR(X) |
| 163 | EQUALS_PTR_I(0); |
| 164 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
| 165 | // CHECK-FIXES: EQUALS_PTR_I(nullptr); |
| 166 | EQUALS_PTR_I(NULL); |
| 167 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
| 168 | // CHECK-FIXES: EQUALS_PTR_I(nullptr); |
| 169 | |
| 170 | // Ok since null literal not within macro. However, now testing macro |
| 171 | // used as arg to another macro. |
| 172 | #define decorate(EXPR) side_effect(); EXPR; |
| 173 | decorate(IS_EQ(NULL, Ptr)); |
| 174 | // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr |
| 175 | // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr)); |
| 176 | decorate(IS_EQ(0, Ptr)); |
| 177 | // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr |
| 178 | // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr)); |
| 179 | |
| 180 | // This macro causes a NullToPointer cast to happen where 0 is assigned to z |
| 181 | // but the 0 literal cannot be replaced because it is also used as an |
| 182 | // integer in the comparison. |
| 183 | #define INT_AND_PTR_USE(X) do { int *z = X; if (X == 4) break; } while(false) |
| 184 | INT_AND_PTR_USE(0); |
| 185 | |
| 186 | // Both uses of X in this case result in NullToPointer casts so replacement |
| 187 | // is possible. |
| 188 | #define PTR_AND_PTR_USE(X) do { int *z = X; if (X != z) break; } while(false) |
| 189 | PTR_AND_PTR_USE(0); |
| 190 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr |
| 191 | // CHECK-FIXES: PTR_AND_PTR_USE(nullptr); |
| 192 | PTR_AND_PTR_USE(NULL); |
| 193 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr |
| 194 | // CHECK-FIXES: PTR_AND_PTR_USE(nullptr); |
| 195 | |
| 196 | #define OPTIONAL_CODE(...) __VA_ARGS__ |
| 197 | #define NOT_NULL dummy(0) |
| 198 | #define CALL(X) X |
| 199 | OPTIONAL_CODE(NOT_NULL); |
| 200 | CALL(NOT_NULL); |
| 201 | |
| 202 | #define ENTRY(X) {X} |
| 203 | struct A { |
| 204 | int *Ptr; |
| 205 | } a[2] = {ENTRY(0), {.Ptr: 0}}; |
| 206 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr |
| 207 | // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: use nullptr |
| 208 | // CHECK-FIXES: a[2] = {ENTRY(nullptr), {nullptr}}; |
| 209 | #undef ENTRY |
| 210 | |
| 211 | #define assert1(expr) (expr) ? 0 : 1 |
| 212 | #define assert2 assert1 |
| 213 | int *p; |
| 214 | assert2(p == 0); |
| 215 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
| 216 | // CHECK-FIXES: assert2(p == nullptr); |
| 217 | assert2(p == NULL); |
| 218 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
| 219 | // CHECK-FIXES: assert2(p == nullptr); |
| 220 | #undef assert2 |
| 221 | #undef assert1 |
| 222 | |
| 223 | #define ASSERT_EQ(a, b) a == b |
| 224 | #define ASSERT_NULL(x) ASSERT_EQ(static_cast<void *>(NULL), x) |
| 225 | int *pp; |
| 226 | ASSERT_NULL(pp); |
| 227 | ASSERT_NULL(NULL); |
| 228 | // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use nullptr |
| 229 | // CHECK-FIXES: ASSERT_NULL(nullptr); |
| 230 | #undef ASSERT_NULL |
| 231 | #undef ASSERT_EQ |
| 232 | } |
| 233 | |
| 234 | // One of the ancestor of the cast is a NestedNameSpecifierLoc. |
| 235 | class NoDef; |
| 236 | char function(NoDef *p); |
| 237 | #define F(x) (sizeof(function(x)) == 1) |
| 238 | template<class T, T t> |
| 239 | class C {}; |
| 240 | C<bool, F(0)> c; |
| 241 | // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr |
| 242 | // CHECK-FIXES: C<bool, F(nullptr)> c; |
| 243 | #undef F |
| 244 | |
| 245 | // Test default argument expression. |
| 246 | struct D { |
| 247 | explicit D(void *t, int *c = NULL) {} |
| 248 | // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use nullptr |
| 249 | // CHECK-FIXES: explicit D(void *t, int *c = nullptr) {} |
| 250 | }; |
| 251 | |
| 252 | void test_default_argument() { |
| 253 | D(nullptr); |
| 254 | } |
| 255 | |
| 256 | // Test on two neighbour CXXDefaultArgExprs nodes. |
| 257 | typedef unsigned long long uint64; |
| 258 | struct ZZ { |
| 259 | explicit ZZ(uint64, const uint64* = NULL) {} |
| 260 | // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: use nullptr |
| 261 | // CHECK-FIXES: explicit ZZ(uint64, const uint64* = nullptr) {} |
| 262 | operator bool() { return true; } |
| 263 | }; |
| 264 | |
| 265 | uint64 Hash(uint64 seed = 0) { return 0; } |
| 266 | |
| 267 | void f() { |
| 268 | bool a; |
| 269 | a = ZZ(Hash()); |
| 270 | } |
| 271 | |
| 272 | // Test on ignoring substituted template types. |
| 273 | template<typename T> |
| 274 | class TemplateClass { |
| 275 | public: |
| 276 | explicit TemplateClass(int a, T default_value = 0) {} |
| 277 | |
| 278 | void h(T *default_value = 0) {} |
| 279 | |
| 280 | void f(int* p = 0) {} |
| 281 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr |
| 282 | // CHECK-FIXES: void f(int* p = nullptr) {} |
| 283 | }; |
| 284 | |
| 285 | void IgnoreSubstTemplateType() { |
| 286 | TemplateClass<int*> a(1); |
| 287 | } |
| 288 | |
| 289 | // Test on casting nullptr. |
| 290 | struct G { |
| 291 | explicit G(bool, const char * = NULL) {} |
| 292 | // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use nullptr |
| 293 | // CHECK-FIXES: explicit G(bool, const char * = nullptr) {} |
| 294 | }; |
| 295 | bool g(const char*); |
| 296 | void test_cast_nullptr() { |
| 297 | G(g(nullptr)); |
| 298 | G(g((nullptr))); |
| 299 | G(g(static_cast<char*>(nullptr))); |
| 300 | G(g(static_cast<const char*>(nullptr))); |
| 301 | } |
| 302 | |
| 303 | // Test on recognizing multiple NULLs. |
| 304 | class H { |
| 305 | public: |
| 306 | H(bool); |
| 307 | }; |
| 308 | |
| 309 | #define T(expression) H(expression); |
| 310 | bool h(int *, int *, int * = nullptr); |
| 311 | void test_multiple_nulls() { |
| 312 | T(h(NULL, NULL)); |
| 313 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr |
| 314 | // CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use nullptr |
| 315 | // CHECK-FIXES: T(h(nullptr, nullptr)); |
| 316 | T(h(NULL, nullptr)); |
| 317 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr |
| 318 | // CHECK-FIXES: T(h(nullptr, nullptr)); |
| 319 | T(h(nullptr, NULL)); |
| 320 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr |
| 321 | // CHECK-FIXES: T(h(nullptr, nullptr)); |
| 322 | T(h(nullptr, nullptr)); |
| 323 | T(h(NULL, NULL, NULL)); |
| 324 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr |
| 325 | // CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use nullptr |
| 326 | // CHECK-MESSAGES: :[[@LINE-3]]:19: warning: use nullptr |
| 327 | // CHECK-FIXES: T(h(nullptr, nullptr, nullptr)); |
| 328 | } |
| 329 | #undef T |
| 330 | |