Skip to content

Commit 1149cba

Browse files
committed
[clang-tidy] Make modernize-use-nullptr matcher also match "NULL", but not "0", when it appears on a substituted type of a template specialization.
Previously, any matches on a substituted type were excluded, but this meant that a situation like the following is not diagnosed: ```c++ template <typename T> struct X { T val; X() { val = NULL; } // should diagnose }; ``` When the user says `NULL`, we expect that the destination type is always meant to be a pointer type, so this should be converted to `nullptr`. By contrast, we do not propose changing a literal `0` in that case, which appears as initializers of both pointer and integer specializations in reasonable real code. (If `NULL` is used erroneously in such a situation, it should be changed to `0` or `{}`.)
1 parent d7c69c2 commit 1149cba

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ AST_MATCHER(Type, sugaredNullptrType) {
3838
StatementMatcher makeCastSequenceMatcher(llvm::ArrayRef<StringRef> NameList) {
3939
auto ImplicitCastToNull = implicitCastExpr(
4040
anyOf(hasCastKind(CK_NullToPointer), hasCastKind(CK_NullToMemberPointer)),
41-
unless(hasImplicitDestinationType(qualType(substTemplateTypeParmType()))),
41+
anyOf(hasSourceExpression(gnuNullExpr()),
42+
unless(hasImplicitDestinationType(
43+
qualType(substTemplateTypeParmType())))),
4244
unless(hasSourceExpression(hasType(sugaredNullptrType()))),
4345
unless(hasImplicitDestinationType(
4446
qualType(matchers::matchesAnyListedTypeName(NameList)))));

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ Changes in existing checks
157157
a false positive when only an implicit conversion happened inside an
158158
initializer list.
159159

160+
- Improved :doc:`modernize-use-nullptr
161+
<clang-tidy/checks/modernize/use-nullptr>` check to also recognize
162+
``NULL``/``__null`` (but not ``0``) when used with a templated type.
163+
160164
- Improved :doc:`modernize-use-std-print
161165
<clang-tidy/checks/modernize/use-std-print>` check to support replacing
162166
member function calls too.

clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,31 @@ void test_macro_expansion4() {
8484
#undef MY_NULL
8585
}
8686

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+
87112
#define IS_EQ(x, y) if (x != y) return;
88113
void test_macro_args() {
89114
int i = 0;

0 commit comments

Comments
 (0)