Author: Kay Hicketts
Date: 2026-06-30T17:57:07Z
New Revision: 166209c3b05c5e3c3eb930ae0e613b18c43797a9

URL: 
https://github.com/llvm/llvm-project/commit/166209c3b05c5e3c3eb930ae0e613b18c43797a9
DIFF: 
https://github.com/llvm/llvm-project/commit/166209c3b05c5e3c3eb930ae0e613b18c43797a9.diff

LOG: Fix false match on nullPointerConstant for array indices (#201893)

# Problem Detail
In the code

```
int *p[1];
(void) p[0];
```

The AST tree for ```p[0]```  looks like
```
    |-CStyleCastExpr 0xc0ae6f1d8 <line:3:3, col:13> 'void' <ToVoid>
    | `-ArraySubscriptExpr 0xc0ae6f1a8 <col:10, col:13> 'int *' lvalue
    |   |-ImplicitCastExpr 0xc0ae6f190 <col:10> 'int **' <ArrayToPointerDecay>
    |   | `-DeclRefExpr 0xc0ae6f118 <col:10> 'int *[1]' lvalue Var 0xc0ae6f098 
'p' 'int *[1]'
    |   `-IntegerLiteral 0xc0ae6f138 <col:12> 'int' 0
```
    
So the previous matcher was finding the integer literal and then seeing
that the parent was a pointer type and thus we were getting a positive
match for something that should be replaced by a null pointer, even
though the index is just an integer.
  
 # Solution
 
 In a real null pointer scenario in cpp
 
 ```int *sausage = 0;```
 
 The AST is like 
 ```     
    | `-VarDecl 0xc0ae6f218 <col:3, col:18> col:8 sausage 'int *' cinit
    |   `-ImplicitCastExpr 0xc0ae6f2a0 <col:18> 'int *' <NullToPointer>
    |     `-IntegerLiteral 0xc0ae6f280 <col:18> 'int' 0 
```
    
 In C it's the same but with the exception of explicit casts
 
 e.g.
 
 ```char *beans = (char*)0;```
 
 which are represented as
 
 ```     
    | `-DeclStmt 0xacee134e8 <line:11:3, col:25>
    |    `-VarDecl 0xacee13420 <col:3, col:24> col:9 beans 'char *' cinit
    |        `-CStyleCastExpr 0xacee134c0 <col:17, col:24> 'char *' 
<NullToPointer>
    |         `-IntegerLiteral 0xacee13488 <col:24> 'int' 0 
```
          
So the new matcher looks for an IntegerLiteral with value 0 that has a
parent that does any kind of cast to a null pointer

I used AI tools to help me build and understand the code.


# Original Issue

clang-tidy tools replace 0 with nullptr in index references due to
misinterpreting index numbers as pointers

Fixes: https://github.com/llvm/llvm-project/issues/87008

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.md
    clang/include/clang/ASTMatchers/ASTMatchers.h
    clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 31e7979612a76..26d5d08979391 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -981,6 +981,8 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
 
 ### AST Matchers
 
+- Fixed `nullPointerConstant` matcher falsely matching integer literal `0`
+  in non-null-pointer contexts such as array subscripts and pointer arithmetic.
 - Add `functionTypeLoc` matcher for matching `FunctionTypeLoc`.
 - Add missing support for `TraversalKind` in some `addMatcher()` overloads.
 

diff  --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index bc0f35898a2c9..8108ee559acea 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -8367,9 +8367,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, 
CUDAKernelCallExpr>
 ///   matches the initializer for v1, v2, v3, cp, and ip. Does not match the
 ///   initializer for i.
 AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
-  return anyOf(
-      gnuNullExpr(), cxxNullPtrLiteralExpr(),
-      integerLiteral(equals(0), hasParent(expr(hasType(pointerType())))));
+  return anyOf(gnuNullExpr(), cxxNullPtrLiteralExpr(),
+               integerLiteral(equals(0), hasParent(castExpr(
+                                             hasCastKind(CK_NullToPointer)))));
 }
 
 /// Matches the DecompositionDecl the binding belongs to.

diff  --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index d9647c201fc30..2c27ab0805625 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -4049,6 +4049,12 @@ TEST_P(ASTMatchersTest, NullPointerConstant) {
   EXPECT_TRUE(matches("char *cp = (char *)0;", expr(nullPointerConstant())));
   EXPECT_TRUE(matches("int *ip = 0;", expr(nullPointerConstant())));
   EXPECT_FALSE(matches("int i = 0;", expr(nullPointerConstant())));
+  EXPECT_FALSE(
+      matches("void f(){int *p[1]; (void)p[0];}", 
expr(nullPointerConstant())));
+  EXPECT_TRUE(matches("void f(){int index; (void)index[(int*)0];}",
+                      expr(nullPointerConstant())));
+  EXPECT_FALSE(matches("void f(){int* ptr; (void)(ptr + 0);}",
+                       expr(nullPointerConstant())));
 }
 
 TEST_P(ASTMatchersTest, NullPointerConstant_GNUNull) {


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to