Implement parsing of nullability annotations to initialise the null state of PointerValues.

In this iteration, the default for unannotated pointers is nullable.

PiperOrigin-RevId: 464842661
diff --git a/nullability_verification/pointer_nullability_analysis.cc b/nullability_verification/pointer_nullability_analysis.cc
index 88f0add..25f3d31 100644
--- a/nullability_verification/pointer_nullability_analysis.cc
+++ b/nullability_verification/pointer_nullability_analysis.cc
@@ -20,6 +20,7 @@
 #include "clang/Analysis/FlowSensitive/NoopLattice.h"
 #include "clang/Analysis/FlowSensitive/Value.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/Specifiers.h"
 
 namespace clang {
 namespace tidy {
@@ -58,12 +59,21 @@
                        /*Known=*/&State.Env.getBoolLiteralValue(true));
 }
 
-void transferInitPointerFromDecl(const Expr* PointerExpr,
-                                 const MatchFinder::MatchResult&,
-                                 TransferState<NoopLattice>& State) {
-  // TODO(b/233582219): Implement processing of nullability annotations. The
-  // current implementation treats unnannotated pointers as nullable.
-  transferInitNullablePointer(PointerExpr, State);
+void transferPointerExpr(const Expr* PointerExpr,
+                         const MatchFinder::MatchResult& Result,
+                         TransferState<NoopLattice>& State) {
+  // TODO(b/233582219): Initialise unannotated pointers with unknown
+  // nullability. The current default for unnannotated pointers is nullable.
+  auto Nullability = PointerExpr->getType()
+                         ->getNullability(*Result.Context)
+                         .value_or(NullabilityKind::Nullable);
+  switch (Nullability) {
+    case NullabilityKind::NonNull:
+      transferInitNotNullPointer(PointerExpr, Result, State);
+      break;
+    default:
+      transferInitNullablePointer(PointerExpr, State);
+  }
 }
 
 // TODO(b/233582219): Implement promotion of nullability knownness for initially
@@ -120,11 +130,11 @@
 auto buildTransferer() {
   return MatchSwitchBuilder<TransferState<NoopLattice>>()
       // Handles initialization of the null states of pointers
-      .CaseOf<Expr>(isPointerVariableReference(), transferInitPointerFromDecl)
+      .CaseOf<Expr>(isPointerVariableReference(), transferPointerExpr)
       .CaseOf<Expr>(isCXXThisExpr(), transferInitNotNullPointer)
       .CaseOf<Expr>(isAddrOf(), transferInitNotNullPointer)
       .CaseOf<Expr>(isNullPointerLiteral(), transferInitNullPointer)
-      .CaseOf<MemberExpr>(isMemberOfPointerType(), transferInitPointerFromDecl)
+      .CaseOf<MemberExpr>(isMemberOfPointerType(), transferPointerExpr)
       // Handles comparison between 2 pointers
       .CaseOf<BinaryOperator>(isPointerCheckBinOp(),
                               transferNullCheckComparison)
diff --git a/nullability_verification/pointer_nullability_verification_test.cc b/nullability_verification/pointer_nullability_verification_test.cc
index 14c6c21..61391c8 100644
--- a/nullability_verification/pointer_nullability_verification_test.cc
+++ b/nullability_verification/pointer_nullability_verification_test.cc
@@ -107,7 +107,39 @@
   )");
 }
 
-TEST(PointerNullabilityTest, DerefNullablePtrWithoutACheck) {
+TEST(PointerNullabilityTest, DerefPtrAnnotatedNonNullWithoutACheck) {
+  checkDiagnostics(R"(
+    void target(int * _Nonnull x) {
+      *x;
+    }
+  )");
+
+  // transitive
+  checkDiagnostics(R"(
+    void target(int * _Nonnull x) {
+      int *y = x;
+      *y;
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, DerefPtrAnnotatedNullableWithoutACheck) {
+  checkDiagnostics(R"(
+    void target(int * _Nullable x) {
+      *x; // [[unsafe]]
+    }
+  )");
+
+  // transitive
+  checkDiagnostics(R"(
+    void target(int * _Nullable x) {
+      int *y = x;
+      *y; // [[unsafe]]
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, DerefUnannotatedPtrWithoutACheck) {
   checkDiagnostics(R"(
     void target(int *x) {
       *x; // [[unsafe]]
@@ -123,9 +155,66 @@
   )");
 }
 
+// TODO(b/233582219): Implement diagnosis of unreachable program points
+TEST(PointerNullabilityTest, NonNullPtrImplicitCastToBool) {
+  // x
+  checkDiagnostics(R"(
+    void target(int * _Nonnull x) {
+      *x;
+      if (x) {
+        *x;
+      } else {
+        *x; // unreachable
+      }
+      *x;
+    }
+  )");
+
+  // !x
+  checkDiagnostics(R"(
+    void target(int * _Nonnull x) {
+      *x;
+      if (!x) {
+        *x; // unreachable
+      } else {
+        *x;
+      }
+      *x;
+    }
+  )");
+}
+
 TEST(PointerNullabilityTest, NullablePtrImplicitCastToBool) {
   // x
   checkDiagnostics(R"(
+    void target(int * _Nullable x) {
+      *x; // [[unsafe]]
+      if (x) {
+        *x;
+      } else {
+        *x; // [[unsafe]]
+      }
+      *x; // [[unsafe]]
+    }
+  )");
+
+  // !x
+  checkDiagnostics(R"(
+    void target(int * _Nullable x) {
+      *x; // [[unsafe]]
+      if (!x) {
+        *x; // [[unsafe]]
+      } else {
+        *x;
+      }
+      *x; // [[unsafe]]
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, UnnannotatedPtrImplicitCastToBool) {
+  // x
+  checkDiagnostics(R"(
     void target(int *x) {
       *x; // [[unsafe]]
       if (x) {
@@ -151,10 +240,173 @@
   )");
 }
 
-TEST(PointerNullabilityTest, CompareNullablePtrAndNullPtr) {
-  // x == nullptr
+TEST(PointerNullabilityTest, CompareNonNullPtrAndNonNullPtr) {
+  // nonnull == nonnull
   checkDiagnostics(R"(
-    void target(int *x) {
+    void target(int * _Nonnull x, int * _Nonnull y) {
+      *x;
+      *y;
+      if (x == y) {
+        *x;
+        *y;
+      } else {
+        *x;
+        *y;
+      }
+      *x;
+      *y;
+    }
+  )");
+
+  // nonnull != nonnull
+  checkDiagnostics(R"(
+    void target(int * _Nonnull x, int * _Nonnull y) {
+      *x;
+      *y;
+      if (x != y) {
+        *x;
+        *y;
+      } else {
+        *x;
+        *y;
+      }
+      *x;
+      *y;
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, CompareNullablePtrAndNullablePtr) {
+  // nullable == nullable
+  checkDiagnostics(R"(
+    void target(int * _Nullable x, int * _Nullable y) {
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+      if (x == y) {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      } else {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      }
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+    }
+  )");
+
+  // nullable != nullable
+  checkDiagnostics(R"(
+    void target(int * _Nullable x, int * _Nullable y) {
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+      if (x != y) {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      } else {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      }
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, CompareUnannotatedPtrAndUnannotatedPtr) {
+  // unannotated == unannotated
+  checkDiagnostics(R"(
+    void target(int *x, int *y) {
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+      if (x == y) {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      } else {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      }
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+    }
+  )");
+
+  // unannotated != unannotated
+  checkDiagnostics(R"(
+    void target(int *x, int *y) {
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+      if (x != y) {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      } else {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      }
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+    }
+  )");
+}
+
+// TODO(b/233582219): Implement diagnosis of unreachable program points
+TEST(PointerNullabilityTest, CompareNonNullPtrAndNullPtr) {
+  // nonnull == nullptr
+  checkDiagnostics(R"(
+    void target(int * _Nonnull x) {
+      *x;
+      if (x == nullptr) {
+        *x; // unreachable
+      } else {
+        *x;
+      }
+      *x;
+    }
+  )");
+
+  // nullptr == nonnull
+  checkDiagnostics(R"(
+    void target(int * _Nonnull x) {
+      *x;
+      if (nullptr == x) {
+        *x; // unreachable
+      } else {
+        *x;
+      }
+      *x;
+    }
+  )");
+
+  // nonnull != nullptr
+  checkDiagnostics(R"(
+    void target(int * _Nonnull x) {
+      *x;
+      if (x != nullptr) {
+        *x;
+      } else {
+        *x; // unreachable
+      }
+      *x;
+    }
+  )");
+
+  // nullptr != nonnull
+  checkDiagnostics(R"(
+    void target(int * _Nonnull x) {
+      *x;
+      if (nullptr != x) {
+        *x;
+      } else {
+        *x; // unreachable
+      }
+      *x;
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, CompareNullablePtrAndNullPtr) {
+  // nullable == nullptr
+  checkDiagnostics(R"(
+    void target(int * _Nullable x) {
       *x; // [[unsafe]]
       if (x == nullptr) {
         *x; // [[unsafe]]
@@ -165,9 +417,9 @@
     }
   )");
 
-  // nullptr == x
+  // nullptr == nullable
   checkDiagnostics(R"(
-    void target(int *x) {
+    void target(int * _Nullable x) {
       *x; // [[unsafe]]
       if (nullptr == x) {
         *x; // [[unsafe]]
@@ -178,9 +430,9 @@
     }
   )");
 
-  // x != nullptr
+  // nullable != nullptr
   checkDiagnostics(R"(
-    void target(int *x) {
+    void target(int * _Nullable x) {
       *x; // [[unsafe]]
       if (x != nullptr) {
         *x;
@@ -191,9 +443,9 @@
     }
   )");
 
-  // nullptr != x
+  // nullptr != nullable
   checkDiagnostics(R"(
-    void target(int *x) {
+    void target(int * _Nullable x) {
       *x; // [[unsafe]]
       if (nullptr != x) {
         *x;
@@ -206,11 +458,9 @@
 }
 
 TEST(PointerNullabilityTest, CompareNullablePtrAndNonNullPtr) {
-  // x == nonnull
+  // nullable == nonnull
   checkDiagnostics(R"(
-    void target(int *x) {
-      int i = 0;
-      int *y = &i;
+    void target(int * _Nullable x, int * _Nonnull y) {
       *x; // [[unsafe]]
       *y;
       if (x == y) {
@@ -225,11 +475,9 @@
     }
   )");
 
-  // nonnull == x
+  // nonnull == nullable
   checkDiagnostics(R"(
-    void target(int *x) {
-      int i = 0;
-      int *y = &i;
+    void target(int * _Nullable x, int * _Nonnull y) {
       *x; // [[unsafe]]
       *y;
       if (y == x) {
@@ -243,13 +491,10 @@
       *y;
     }
   )");
-}
 
-TEST(PointerNullabilityTest, CheckByComparisonToOtherNullPtr) {
+  // nullable != nonnull
   checkDiagnostics(R"(
-    void target(int *x) {
-      int i = 0;
-      int *y = &i;
+    void target(int * _Nullable x, int * _Nonnull y) {
       *x; // [[unsafe]]
       *y;
       if (x != y) {
@@ -264,11 +509,9 @@
     }
   )");
 
-  // nonnull != x
+  // nonnull != nullable
   checkDiagnostics(R"(
-    void target(int *x) {
-      int i = 0;
-      int *y = &i;
+    void target(int * _Nullable x, int * _Nonnull y) {
       *x; // [[unsafe]]
       *y;
       if (y != x) {
@@ -284,10 +527,10 @@
   )");
 }
 
-TEST(PointerNullabilityTest, CompareNullablePtrAndNullablePtr) {
-  // x == y
+TEST(PointerNullabilityTest, CompareNullablePtrAndUnannotatedPtr) {
+  // nullable == unannotated
   checkDiagnostics(R"(
-    void target(int *x, int *y) {
+    void target(int * _Nullable x, int *y) {
       *x; // [[unsafe]]
       *y; // [[unsafe]]
       if (x == y) {
@@ -302,9 +545,26 @@
     }
   )");
 
-  // x != y
+  // unannotated == nullable
   checkDiagnostics(R"(
-    void target(int *x, int *y) {
+    void target(int * _Nullable x, int *y) {
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+      if (y == x) {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      } else {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      }
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+    }
+  )");
+
+  // nullable != unannotated
+  checkDiagnostics(R"(
+    void target(int * _Nullable x, int *y) {
       *x; // [[unsafe]]
       *y; // [[unsafe]]
       if (x != y) {
@@ -318,6 +578,147 @@
       *y; // [[unsafe]]
     }
   )");
+
+  // unannotated != nullable
+  checkDiagnostics(R"(
+    void target(int * _Nullable x, int *y) {
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+      if (y != x) {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      } else {
+        *x; // [[unsafe]]
+        *y; // [[unsafe]]
+      }
+      *x; // [[unsafe]]
+      *y; // [[unsafe]]
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, CompareUnannotatedPtrAndNullPtr) {
+  // unannotated == nullptr
+  checkDiagnostics(R"(
+    void target(int *x) {
+      *x; // [[unsafe]]
+      if (x == nullptr) {
+        *x; // [[unsafe]]
+      } else {
+        *x;
+      }
+      *x; // [[unsafe]]
+    }
+  )");
+
+  // nullptr == unannotated
+  checkDiagnostics(R"(
+    void target(int *x) {
+      *x; // [[unsafe]]
+      if (nullptr == x) {
+        *x; // [[unsafe]]
+      } else {
+        *x;
+      }
+      *x; // [[unsafe]]
+    }
+  )");
+
+  // unannotated != nullptr
+  checkDiagnostics(R"(
+    void target(int *x) {
+      *x; // [[unsafe]]
+      if (x != nullptr) {
+        *x;
+      } else {
+        *x; // [[unsafe]]
+      }
+      *x; // [[unsafe]]
+    }
+  )");
+
+  // nullptr != unannotated
+  checkDiagnostics(R"(
+    void target(int *x) {
+      *x; // [[unsafe]]
+      if (nullptr != x) {
+        *x;
+      } else {
+        *x; // [[unsafe]]
+      }
+      *x; // [[unsafe]]
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, CompareUnannotatedPtrAndNonNullPtr) {
+  // unannotated == nonnull
+  checkDiagnostics(R"(
+    void target(int *x, int * _Nonnull y) {
+      *x; // [[unsafe]]
+      *y;
+      if (x == y) {
+        *x;
+        *y;
+      } else {
+        *x; // [[unsafe]]
+        *y;
+      }
+      *x; // [[unsafe]]
+      *y;
+    }
+  )");
+
+  // nonnull == unannotated
+  checkDiagnostics(R"(
+    void target(int *x, int * _Nonnull y) {
+      *x; // [[unsafe]]
+      *y;
+      if (y == x) {
+        *x;
+        *y;
+      } else {
+        *x; // [[unsafe]]
+        *y;
+      }
+      *x; // [[unsafe]]
+      *y;
+    }
+  )");
+
+  // unannotated != nonnull
+  checkDiagnostics(R"(
+    void target(int *x, int * _Nonnull y) {
+      *x; // [[unsafe]]
+      *y;
+      if (x != y) {
+        *x; // [[unsafe]]
+        *y;
+      } else {
+        *x;
+        *y;
+      }
+      *x; // [[unsafe]]
+      *y;
+    }
+  )");
+
+  // nonnull != unannotated
+  checkDiagnostics(R"(
+    void target(int *x, int * _Nonnull y) {
+      *x; // [[unsafe]]
+      *y;
+      if (y != x) {
+        *x; // [[unsafe]]
+        *y;
+      } else {
+        *x;
+        *y;
+      }
+      *x; // [[unsafe]]
+      *y;
+    }
+  )");
 }
 
 TEST(PointerNullabilityTest, TransitiveNullCheck) {
@@ -418,7 +819,63 @@
   )");
 }
 
-TEST(PointerNullabilityTest, ArrowOperator) {
+TEST(PointerNullabilityTest, ArrowOperatorOnNonNullPtr) {
+  // (->) member field
+  checkDiagnostics(R"(
+    struct Foo {
+      Foo *foo;
+    };
+    void target(Foo * _Nonnull foo) {
+      foo->foo;
+    }
+  )");
+
+  // (->) member function
+  checkDiagnostics(R"(
+    struct Foo {
+      Foo *foo();
+    };
+    void target(Foo * _Nonnull foo) {
+      foo->foo();
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, ArrowOperatorOnNullablePtr) {
+  // (->) member field
+  checkDiagnostics(R"(
+    struct Foo {
+      Foo *foo;
+    };
+    void target(Foo * _Nullable foo) {
+      foo->foo; // [[unsafe]]
+      if (foo) {
+        foo->foo;
+      } else {
+        foo->foo; // [[unsafe]]
+      }
+      foo->foo; // [[unsafe]]
+    }
+  )");
+
+  // (->) member function
+  checkDiagnostics(R"(
+    struct Foo {
+      Foo *foo();
+    };
+    void target(Foo * _Nullable foo) {
+      foo->foo(); // [[unsafe]]
+      if (foo) {
+        foo->foo();
+      } else {
+        foo->foo(); // [[unsafe]]
+      }
+      foo->foo(); // [[unsafe]]
+    }
+  )");
+}
+
+TEST(PointerNullabilityTest, ArrowOperatorOnUnannotatedPtr) {
   // (->) member field
   checkDiagnostics(R"(
     struct Foo {
@@ -474,7 +931,63 @@
   )");
 }
 
-TEST(PointerNullabilityTest, FieldsOfPointerType) {
+TEST(PointerNullabilityTest, NonNullFieldsOfPointerType) {
+  // dereference field of pointer type
+  checkDiagnostics(R"(
+    struct Foo {
+      Foo * _Nonnull ptr;
+    };
+    void target(Foo foo) {
+      *foo.ptr;
+    }
+  )");
+
+  // dereference field of pointer type in member function
+  checkDiagnostics(R"(
+    struct Foo {
+      Foo * _Nonnull ptr;
+      void target() {
+        *ptr;
+      }
+    };
+  )");
+}
+
+TEST(PointerNullabilityTest, NullableFieldsOfPointerType) {
+  // dereference field of pointer type
+  checkDiagnostics(R"(
+    struct Foo {
+      Foo * _Nullable ptr;
+    };
+    void target(Foo foo) {
+      *foo.ptr; // [[unsafe]]
+      if (foo.ptr) {
+        *foo.ptr;
+      } else {
+        *foo.ptr; // [[unsafe]]
+      }
+      *foo.ptr; // [[unsafe]]
+    }
+  )");
+
+  // dereference field of pointer type in member function
+  checkDiagnostics(R"(
+    struct Foo {
+      Foo * _Nullable ptr;
+      void target() {
+        *ptr; // [[unsafe]]
+        if (ptr) {
+          *ptr;
+        } else {
+          *ptr; // [[unsafe]]
+        }
+        *ptr; // [[unsafe]]
+      }
+    };
+  )");
+}
+
+TEST(PointerNullabilityTest, UnannotatedFieldsOfPointerType) {
   // dereference field of pointer type
   checkDiagnostics(R"(
     struct Foo {