Separate analysis and diagnosis components for pointer nullability verification.

- `pointer_nullability_analysis.h/cc`: accummulate nullability information of pointers.
- `pointer_nullability_diagnosis.h/cc`: checks null safety (e.g. if a dereference is safe).
- `pointer_nullability.h/cc`: common functions for updating a PointerValue's nullability.

PiperOrigin-RevId: 464823057
diff --git a/nullability_verification/pointer_nullability_analysis.cc b/nullability_verification/pointer_nullability_analysis.cc
index c098111..11b8efd 100644
--- a/nullability_verification/pointer_nullability_analysis.cc
+++ b/nullability_verification/pointer_nullability_analysis.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "common/check.h"
+#include "nullability_verification/pointer_nullability.h"
 #include "nullability_verification/pointer_nullability_lattice.h"
 #include "nullability_verification/pointer_nullability_matchers.h"
 #include "clang/AST/ASTContext.h"
@@ -25,55 +26,19 @@
 namespace nullability {
 
 using ast_matchers::MatchFinder;
-using dataflow::AtomicBoolValue;
 using dataflow::BoolValue;
 using dataflow::Environment;
 using dataflow::MatchSwitchBuilder;
-using dataflow::PointerValue;
 using dataflow::SkipPast;
 using dataflow::TransferState;
 using dataflow::Value;
 
 namespace {
 
-constexpr llvm::StringLiteral kKnown = "is_known";
-constexpr llvm::StringLiteral kNotNull = "is_notnull";
-
-std::pair<AtomicBoolValue&, AtomicBoolValue&> getPointerNullState(
-    const Expr* PointerExpr, TransferState<PointerNullabilityLattice>& State) {
-  auto* PointerVal =
-      cast<PointerValue>(State.Env.getValue(*PointerExpr, SkipPast::Reference));
-  auto& PointerKnown = *cast<AtomicBoolValue>(PointerVal->getProperty(kKnown));
-  auto& PointerNotNull =
-      *cast<AtomicBoolValue>(PointerVal->getProperty(kNotNull));
-  return {PointerKnown, PointerNotNull};
-}
-
-void initPointerBoolProperty(PointerValue& PointerVal, llvm::StringRef Name,
-                             BoolValue* BoolVal, Environment& Env) {
-  if (PointerVal.getProperty(Name) == nullptr) {
-    PointerVal.setProperty(Name,
-                           BoolVal ? *BoolVal : Env.makeAtomicBoolValue());
-  }
-}
-
-/// The nullness information of a pointer is represented by two properties which
-/// indicate if a pointer's nullability (i.e. if the pointer can hold null) is
-/// `Known` and if the pointer's value is `NotNull`.
-void initPointerNullState(const Expr* PointerExpr,
-                          TransferState<PointerNullabilityLattice>& State,
-                          BoolValue* Known, BoolValue* NotNull = nullptr) {
-  if (auto* PointerVal = cast_or_null<PointerValue>(
-          State.Env.getValue(*PointerExpr, SkipPast::Reference))) {
-    initPointerBoolProperty(*PointerVal, kKnown, Known, State.Env);
-    initPointerBoolProperty(*PointerVal, kNotNull, NotNull, State.Env);
-  }
-}
-
 void transferInitNotNullPointer(
     const Expr* NotNullPointer, const MatchFinder::MatchResult&,
     TransferState<PointerNullabilityLattice>& State) {
-  initPointerNullState(NotNullPointer, State,
+  initPointerNullState(NotNullPointer, State.Env,
                        /*Known=*/&State.Env.getBoolLiteralValue(true),
                        /*NotNull=*/&State.Env.getBoolLiteralValue(true));
 }
@@ -81,7 +46,7 @@
 void transferInitNullPointer(const Expr* NullPointer,
                              const MatchFinder::MatchResult&,
                              TransferState<PointerNullabilityLattice>& State) {
-  initPointerNullState(NullPointer, State,
+  initPointerNullState(NullPointer, State.Env,
                        /*Known=*/&State.Env.getBoolLiteralValue(true),
                        /*NotNull=*/&State.Env.getBoolLiteralValue(false));
 }
@@ -89,50 +54,21 @@
 void transferInitNullablePointer(
     const Expr* NullablePointer,
     TransferState<PointerNullabilityLattice>& State) {
-  initPointerNullState(NullablePointer, State,
+  initPointerNullState(NullablePointer, State.Env,
                        /*Known=*/&State.Env.getBoolLiteralValue(true));
 }
 
 void transferInitPointerFromDecl(
     const Expr* PointerExpr, const MatchFinder::MatchResult&,
     TransferState<PointerNullabilityLattice>& State) {
-  // TODO(wyt): Implement processing of nullability annotations. The current
-  // implementation treats unnannotated pointers as nullable.
+  // TODO(b/233582219): Implement processing of nullability annotations. The
+  // current implementation treats unnannotated pointers as nullable.
   transferInitNullablePointer(PointerExpr, State);
 }
 
-void transferPointerAccess(const Expr* PointerExpr,
-                           TransferState<PointerNullabilityLattice>& State) {
-  auto [PointerKnown, PointerNotNull] = getPointerNullState(PointerExpr, State);
-  auto& PointerNotKnownNull = State.Env.makeNot(
-      State.Env.makeAnd(PointerKnown, State.Env.makeNot(PointerNotNull)));
-  if (!State.Env.flowConditionImplies(PointerNotKnownNull)) {
-    State.Lattice.addViolation(PointerExpr);
-  }
-}
-
-void transferDereference(const UnaryOperator* UnaryOp,
-                         const MatchFinder::MatchResult&,
-                         TransferState<PointerNullabilityLattice>& State) {
-  transferPointerAccess(UnaryOp->getSubExpr(), State);
-}
-
-void transferMemberExprInvolvingPointers(
-    const MemberExpr* MemberExpr, const MatchFinder::MatchResult& Result,
-    TransferState<PointerNullabilityLattice>& State) {
-  if (MemberExpr->isArrow()) {
-    // Base expr is a pointer, check that (->) access is safe
-    transferPointerAccess(MemberExpr->getBase(), State);
-  }
-  if (MemberExpr->getType()->isAnyPointerType()) {
-    // Accessed member is a pointer, initialise its nullability
-    transferInitPointerFromDecl(MemberExpr, Result, State);
-  }
-}
-
-// TODO(wyt): Implement promotion of nullability knownness for initially unknown
-// pointers when there is evidence that it is nullable, for example when the
-// pointer is compared to nullptr, or casted to boolean.
+// TODO(b/233582219): Implement promotion of nullability knownness for initially
+// unknown pointers when there is evidence that it is nullable, for example
+// when the pointer is compared to nullptr, or casted to boolean.
 void transferNullCheckComparison(
     const BinaryOperator* BinaryOp, const MatchFinder::MatchResult& result,
     TransferState<PointerNullabilityLattice>& State) {
@@ -149,8 +85,10 @@
                         ? State.Env.makeNot(PointerComparison)
                         : PointerComparison;
 
-  auto [LHSKnown, LHSNotNull] = getPointerNullState(BinaryOp->getLHS(), State);
-  auto [RHSKnown, RHSNotNull] = getPointerNullState(BinaryOp->getRHS(), State);
+  auto [LHSKnown, LHSNotNull] =
+      getPointerNullState(BinaryOp->getLHS(), State.Env);
+  auto [RHSKnown, RHSNotNull] =
+      getPointerNullState(BinaryOp->getRHS(), State.Env);
   auto& LHSKnownNotNull = State.Env.makeAnd(LHSKnown, LHSNotNull);
   auto& RHSKnownNotNull = State.Env.makeAnd(RHSKnown, RHSNotNull);
   auto& LHSKnownNull =
@@ -173,7 +111,7 @@
     const Expr* CastExpr, const MatchFinder::MatchResult&,
     TransferState<PointerNullabilityLattice>& State) {
   auto [PointerKnown, PointerNotNull] =
-      getPointerNullState(CastExpr->IgnoreImplicit(), State);
+      getPointerNullState(CastExpr->IgnoreImplicit(), State.Env);
   auto& CastExprLoc = State.Env.createStorageLocation(*CastExpr);
   State.Env.setValue(CastExprLoc, PointerNotNull);
   State.Env.setStorageLocation(*CastExpr, CastExprLoc);
@@ -186,12 +124,7 @@
       .CaseOf<Expr>(isCXXThisExpr(), transferInitNotNullPointer)
       .CaseOf<Expr>(isAddrOf(), transferInitNotNullPointer)
       .CaseOf<Expr>(isNullPointerLiteral(), transferInitNullPointer)
-      // Handles initialization of null states of member pointers and safety of
-      // member access (->) on pointers
-      .CaseOf<MemberExpr>(isMemberExprInvolvingPointers(),
-                          transferMemberExprInvolvingPointers)
-      // Handles pointer dereferencing (*ptr)
-      .CaseOf<UnaryOperator>(isPointerDereference(), transferDereference)
+      .CaseOf<MemberExpr>(isMemberOfPointerType(), transferInitPointerFromDecl)
       // Handles comparison between 2 pointers
       .CaseOf<BinaryOperator>(isPointerCheckBinOp(),
                               transferNullCheckComparison)