Skip to content

Commit cebb7c0

Browse files
authored
[clang-tidy] modernize-use-nullptr matches "NULL" in templates (#109169)
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 d01e336 commit cebb7c0

File tree

3 files changed

+40
-1
lines changed

3 files changed

+40
-1
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,20 @@ AST_MATCHER(Type, sugaredNullptrType) {
3535
/// to null within.
3636
/// Finding sequences of explicit casts is necessary so that an entire sequence
3737
/// can be replaced instead of just the inner-most implicit cast.
38+
///
39+
/// TODO/NOTE: The second "anyOf" below discards matches on a substituted type,
40+
/// since we don't know if that would _always_ be a pointer type for all other
41+
/// specializations, unless the expression was "__null", in which case we assume
42+
/// that all specializations are expected to be for pointer types. Ideally this
43+
/// would check for the "NULL" macro instead, but that'd be harder to express.
44+
/// In practice, "NULL" is often defined as "__null", and this is a useful
45+
/// condition.
3846
StatementMatcher makeCastSequenceMatcher(llvm::ArrayRef<StringRef> NameList) {
3947
auto ImplicitCastToNull = implicitCastExpr(
4048
anyOf(hasCastKind(CK_NullToPointer), hasCastKind(CK_NullToMemberPointer)),
41-
unless(hasImplicitDestinationType(qualType(substTemplateTypeParmType()))),
49+
anyOf(hasSourceExpression(gnuNullExpr()),
50+
unless(hasImplicitDestinationType(
51+
qualType(substTemplateTypeParmType())))),
4252
unless(hasSourceExpression(hasType(sugaredNullptrType()))),
4353
unless(hasImplicitDestinationType(
4454
qualType(matchers::matchesAnyListedTypeName(NameList)))));

clang-tools-extra/docs/ReleaseNotes.rst

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

169+
- Improved :doc:`modernize-use-nullptr
170+
<clang-tidy/checks/modernize/use-nullptr>` check to also recognize
171+
``NULL``/``__null`` (but not ``0``) when used with a templated type.
172+
169173
- Improved :doc:`modernize-use-std-print
170174
<clang-tidy/checks/modernize/use-std-print>` check to support replacing
171175
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)