# clang-tidy modernize-use-nullptr on repo: fix changes the outcome of the project's command

Evidence sheet generated by fixhunt from a repository scan. Not an issue text. A human re-verifies, checks the
duplicates below, and writes the upstream report in their own words following the project's AI policy.

- Tool: clang-tidy 21.1.8 (fix labelled unknown)
- Project: /home/sun/dev/diaghunt/demo/repo
- Command: `make -s -C native test` (exit 0 before, 0 after)
- Files changed by the fix: 2; smallest change that still reproduces: 1 of 2 hunk(s) in native/tests/tests.cpp
- Sites reported by the rule in the changed files: 2 before, 0 after the fix
- Judge (Nemotron 3 Ultra, advisory): introspection-only, severity low. The only difference is the test framework printing the rewritten source text 'nullptr' instead of 'NULL' in its diagnostic output. The rule replaces the NULL macro with nullptr, which is a source-text change that the test harness reflects in its 'ok' line. No runtime semantics, environment, or pre-existing failure is involved.

## Change (applies to the project with `git apply -p1`)

```diff
--- a/native/tests/tests.cpp
+++ b/native/tests/tests.cpp
@@ -16,7 +16,7 @@
   Window off(0);
   CHECK(disabled(off));
   CHECK(normalize("MiXed") == "mixed");
-  CHECK(first_or_null("") == NULL);
+  CHECK(first_or_null("") == nullptr);
   CHECK(std::strcmp(first_or_null("a"), "a") == 0);
   std::cout << (failures ? "FAILED" : "PASSED") << "\n";
   return failures ? 1 : 0;
```

## Observed

```
stdout lines only before the fix:
  ok   first_or_null("") == NULL
stdout lines only after the fix:
  ok   first_or_null("") == nullptr
```

## Output of the command (last 40 lines)

Before:

```
ok   !disabled(w)
ok   w.empty()
ok   w.sum() == 9
ok   disabled(off)
ok   normalize("MiXed") == "mixed"
ok   first_or_null("") == NULL
ok   std::strcmp(first_or_null("a"), "a") == 0
PASSED
```

After:

```
ok   !disabled(w)
ok   w.empty()
ok   w.sum() == 9
ok   disabled(off)
ok   normalize("MiXed") == "mixed"
ok   first_or_null("") == nullptr
ok   std::strcmp(first_or_null("a"), "a") == 0
PASSED
```

## Why the rewrite is not equivalent (model draft, verify before use)

The macro `NULL` expands to an integer constant expression of type int with value zero, while `nullptr` has type `std::nullptr_t`. When comparing via overloaded operators or templates—such as in a custom `CHECK` macro that may inspect types—the two expressions yield different compile-time properties, potentially causing distinct overload resolutions or template instantiations. This can alter runtime behavior if the test harness relies on type-specific logic, such as printing different messages based on the operand types, leading to divergent output despite identical logical values. Thus, the substitution changes observable program behavior.

## Upstream search

Queries: "modernize-use-nullptr fix", "modernize-use-nullptr equality comparison", "first_or_null function call null check", "CHECK macro assertion with literal"

- related: https://github.com/llvm/llvm-project/issues/23565

## Reproduce

```sh
clang-tidy-21 -checks=-*,modernize-use-nullptr --fix native/src/names.cpp -- -std=c++20 -Wall -Inative/include
clang-tidy-21 -checks=-*,modernize-use-nullptr --fix native/tests/tests.cpp -- -std=c++20 -Wall -Inative/include
make -s -C native test
```
