332 lines · cpp
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 05 6namespace std {7 8typedef decltype(nullptr) nullptr_t;9 10} // namespace std11 12// Just to make sure make_null() could have side effects.13void external();14 15std::nullptr_t make_null() {16 external();17 return nullptr;18}19 20void 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 29void dummy(int*) {}30void side_effect() {}31 32#define MACRO_EXPANSION_HAS_NULL \33 void foo() { \34 dummy(0); \35 dummy(NULL); \36 side_effect(); \37 }38 39MACRO_EXPANSION_HAS_NULL;40#undef MACRO_EXPANSION_HAS_NULL41 42 43void 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_NULL51}52 53// Test macro expansion with cast sequence, PR15572.54void 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_NULL62}63 64void 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_MACRO76#undef MACRO_EXPANSION_HAS_NULL77}78 79void test_macro_expansion4() {80#define MY_NULL NULL81 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_NULL85}86 87template <typename T> struct pear {88 // If you say __null (or NULL), we assume that T will always be a pointer89 // 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 implementations91 // 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: void f() { x = nullptr; }95 96 // But if you say 0, we allow the possibility that T can be used with integral97 // and pointer types, and "0" is an acceptable initializer (even if "{}" might98 // be even better).99 void g() { y = 0; }100 // CHECK-MESSAGES-NOT: :[[@LINE-1]] warning: use nullptr101 102 T x;103 T y;104};105void 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;113void 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 nullptr119 // CHECK-FIXES: IS_EQ(static_cast<int*>(nullptr), Ptr);120 121 // literal122 IS_EQ(0, Ptr);123 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr124 // CHECK-FIXES: IS_EQ(nullptr, Ptr);125 126 // macro127 IS_EQ(NULL, Ptr);128 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr129 // CHECK-FIXES: IS_EQ(nullptr, Ptr);130 131 // These are ok since the null literal is not spelled within a macro.132#define myassert(x) if (!(x)) return;133 myassert(0 == Ptr);134 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr135 // CHECK-FIXES: myassert(nullptr == Ptr);136 137 myassert(NULL == Ptr);138 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr139 // CHECK-FIXES: myassert(nullptr == Ptr);140 141 // These are bad as the null literal is buried in a macro.142#define BLAH(X) myassert(0 == (X));143#define BLAH2(X) myassert(NULL == (X));144 BLAH(Ptr);145 BLAH2(Ptr);146 147 // Same as above but testing extra macro expansion.148#define EXPECT_NULL(X) IS_EQ(0, X);149#define EXPECT_NULL2(X) IS_EQ(NULL, X);150 EXPECT_NULL(Ptr);151 EXPECT_NULL2(Ptr);152 153 // Almost the same as above but now null literal is not in a macro so ok154 // to transform.155#define EQUALS_PTR(X) IS_EQ(X, Ptr);156 EQUALS_PTR(0);157 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr158 // CHECK-FIXES: EQUALS_PTR(nullptr);159 EQUALS_PTR(NULL);160 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr161 // CHECK-FIXES: EQUALS_PTR(nullptr);162 163 // Same as above but testing extra macro expansion.164#define EQUALS_PTR_I(X) EQUALS_PTR(X)165 EQUALS_PTR_I(0);166 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr167 // CHECK-FIXES: EQUALS_PTR_I(nullptr);168 EQUALS_PTR_I(NULL);169 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr170 // CHECK-FIXES: EQUALS_PTR_I(nullptr);171 172 // Ok since null literal not within macro. However, now testing macro173 // used as arg to another macro.174#define decorate(EXPR) side_effect(); EXPR;175 decorate(IS_EQ(NULL, Ptr));176 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr177 // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr));178 decorate(IS_EQ(0, Ptr));179 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr180 // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr));181 182 // This macro causes a NullToPointer cast to happen where 0 is assigned to z183 // but the 0 literal cannot be replaced because it is also used as an184 // integer in the comparison.185#define INT_AND_PTR_USE(X) do { int *z = X; if (X == 4) break; } while(false)186 INT_AND_PTR_USE(0);187 188 // Both uses of X in this case result in NullToPointer casts so replacement189 // is possible.190#define PTR_AND_PTR_USE(X) do { int *z = X; if (X != z) break; } while(false)191 PTR_AND_PTR_USE(0);192 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr193 // CHECK-FIXES: PTR_AND_PTR_USE(nullptr);194 PTR_AND_PTR_USE(NULL);195 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr196 // CHECK-FIXES: PTR_AND_PTR_USE(nullptr);197 198#define OPTIONAL_CODE(...) __VA_ARGS__199#define NOT_NULL dummy(0)200#define CALL(X) X201 OPTIONAL_CODE(NOT_NULL);202 CALL(NOT_NULL);203 204#define ENTRY(X) {X}205 struct A {206 int *Ptr;207 } a[2] = {ENTRY(0), {0}};208 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr209 // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: use nullptr210 // CHECK-FIXES: } a[2] = {ENTRY(nullptr), {nullptr}};211#undef ENTRY212 213#define assert1(expr) (expr) ? 0 : 1214#define assert2 assert1215 int *p;216 assert2(p == 0);217 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr218 // CHECK-FIXES: assert2(p == nullptr);219 assert2(p == NULL);220 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr221 // CHECK-FIXES: assert2(p == nullptr);222#undef assert2223#undef assert1224 225#define ASSERT_EQ(a, b) a == b226#define ASSERT_NULL(x) ASSERT_EQ(static_cast<void *>(NULL), x)227 int *pp;228 ASSERT_NULL(pp);229 ASSERT_NULL(NULL);230 // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use nullptr231 // CHECK-FIXES: ASSERT_NULL(nullptr);232#undef ASSERT_NULL233#undef ASSERT_EQ234}235 236// One of the ancestor of the cast is a NestedNameSpecifierLoc.237class NoDef;238char function(NoDef *p);239#define F(x) (sizeof(function(x)) == 1)240template<class T, T t>241class C {};242C<bool, F(0)> c;243// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr244// CHECK-FIXES: C<bool, F(nullptr)> c;245#undef F246 247// Test default argument expression.248struct D {249 explicit D(void *t, int *c = NULL) {}250 // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use nullptr251 // CHECK-FIXES: explicit D(void *t, int *c = nullptr) {}252};253 254void test_default_argument() {255 D(nullptr);256}257 258// Test on two neighbour CXXDefaultArgExprs nodes.259typedef unsigned long long uint64;260struct ZZ {261 explicit ZZ(uint64, const uint64* = NULL) {}262// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: use nullptr263// CHECK-FIXES: explicit ZZ(uint64, const uint64* = nullptr) {}264 operator bool() { return true; }265};266 267uint64 Hash(uint64 seed = 0) { return 0; }268 269void f() {270 bool a;271 a = ZZ(Hash());272}273 274// Test on ignoring substituted template types.275template<typename T>276class TemplateClass {277 public:278 explicit TemplateClass(int a, T default_value = 0) {}279 280 void h(T *default_value = 0) {}281 282 void f(int* p = 0) {}283// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr284// CHECK-FIXES: void f(int* p = nullptr) {}285};286 287void IgnoreSubstTemplateType() {288 TemplateClass<int*> a(1);289}290 291// Test on casting nullptr.292struct G {293 explicit G(bool, const char * = NULL) {}294 // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use nullptr295 // CHECK-FIXES: explicit G(bool, const char * = nullptr) {}296};297bool g(const char*);298void test_cast_nullptr() {299 G(g(nullptr));300 G(g((nullptr)));301 G(g(static_cast<char*>(nullptr)));302 G(g(static_cast<const char*>(nullptr)));303}304 305// Test on recognizing multiple NULLs.306class H {307public:308 H(bool);309};310 311#define T(expression) H(expression);312bool h(int *, int *, int * = nullptr);313void test_multiple_nulls() {314 T(h(NULL, NULL));315// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr316// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use nullptr317// CHECK-FIXES: T(h(nullptr, nullptr));318 T(h(NULL, nullptr));319// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr320// CHECK-FIXES: T(h(nullptr, nullptr));321 T(h(nullptr, NULL));322// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr323// CHECK-FIXES: T(h(nullptr, nullptr));324 T(h(nullptr, nullptr));325 T(h(NULL, NULL, NULL));326// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr327// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use nullptr328// CHECK-MESSAGES: :[[@LINE-3]]:19: warning: use nullptr329// CHECK-FIXES: T(h(nullptr, nullptr, nullptr));330}331#undef T332