Fix inconsistency between initPointerNullState and getPointerNullState

The former allows any booleans, the latter asserts that they were atoms.
Resolve this by supporting any booleans, and converting them to atoms.
While it appears that the production values are always atoms, this seems to be
a fragile almost-coincidence, and it's not clear how to statically guarantee it.

PiperOrigin-RevId: 528755942
diff --git a/nullability/BUILD b/nullability/BUILD
index 0fffa9b..1227e8c 100644
--- a/nullability/BUILD
+++ b/nullability/BUILD
@@ -76,6 +76,7 @@
     srcs = ["pointer_nullability_test.cc"],
     deps = [
         ":pointer_nullability",
+        "@llvm-project//clang:analysis",
         "@llvm-project//clang:testing",
         "@llvm-project//llvm:Support",
         "@llvm-project//third-party/unittest:gmock",
diff --git a/nullability/pointer_nullability.cc b/nullability/pointer_nullability.cc
index ae3e024..5c3bb52 100644
--- a/nullability/pointer_nullability.cc
+++ b/nullability/pointer_nullability.cc
@@ -46,10 +46,14 @@
 
 void initPointerBoolProperty(PointerValue& PointerVal, llvm::StringRef Name,
                              BoolValue* BoolVal, Environment& Env) {
-  if (PointerVal.getProperty(Name) == nullptr) {
-    PointerVal.setProperty(Name,
-                           BoolVal ? *BoolVal : Env.makeAtomicBoolValue());
+  if (PointerVal.getProperty(Name) != nullptr) return;
+  // The property must always be a non-null boolean atom.
+  if (!isa_and_nonnull<AtomicBoolValue>(BoolVal)) {
+    auto& Atom = Env.makeAtomicBoolValue();
+    if (BoolVal) Env.addToFlowCondition(Env.makeIff(Atom, *BoolVal));
+    BoolVal = &Atom;
   }
+  PointerVal.setProperty(Name, BoolVal ? *BoolVal : Env.makeAtomicBoolValue());
 }
 
 void initPointerNullState(PointerValue& PointerVal, Environment& Env,
diff --git a/nullability/pointer_nullability_test.cc b/nullability/pointer_nullability_test.cc
index e44ae74..82fb128 100644
--- a/nullability/pointer_nullability_test.cc
+++ b/nullability/pointer_nullability_test.cc
@@ -4,6 +4,7 @@
 
 #include "nullability/pointer_nullability.h"
 
+#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
 #include "clang/Testing/TestAST.h"
 #include "llvm/ADT/StringRef.h"
 #include "third_party/llvm/llvm-project/third-party/unittest/googlemock/include/gmock/gmock.h"
@@ -13,5 +14,32 @@
 namespace {
 using testing::ElementsAre;
 
+TEST(NullabilityPropertiesTest, Test) {
+  dataflow::DataflowAnalysisContext DACtx(
+      std::make_unique<dataflow::WatchedLiteralsSolver>());
+  dataflow::Environment Env(DACtx);
+
+  auto &True = DACtx.arena().makeLiteral(true);
+  auto &False = DACtx.arena().makeLiteral(false);
+  auto &False2 = DACtx.arena().makeNot(True);
+
+  auto MakePointer =
+      [&](dataflow::BoolValue &Known,
+          dataflow::BoolValue &Null) -> dataflow::PointerValue & {
+    auto &P = Env.create<dataflow::PointerValue>(
+        DACtx.createStorageLocation(QualType()));
+    initPointerNullState(P, Env, &Known, &Null);
+    return P;
+  };
+
+  EXPECT_TRUE(isNullable(MakePointer(/*Known=*/True, /*Null=*/True), Env));
+  EXPECT_FALSE(isNullable(MakePointer(/*Known=*/True, /*Null=*/False), Env));
+  EXPECT_FALSE(isNullable(MakePointer(/*Known=*/False, /*Null=*/True), Env));
+  EXPECT_FALSE(isNullable(MakePointer(/*Known=*/False, /*Null=*/False), Env));
+
+  EXPECT_FALSE(isNullable(MakePointer(/*Known=*/True, /*Null=*/False2), Env));
+  EXPECT_FALSE(isNullable(MakePointer(/*Known=*/False2, /*Null=*/True), Env));
+}
+
 }  // namespace
 }  // namespace clang::tidy::nullability