Check that assignment to parameters in function calls are null-safe.

For example, it is unsafe to pass a nullable value as a nonnull parameter.
```
void foo(int * _Nonnull x);
int * _Nullable x = ...;
foo(x); // Unsafe
```

PiperOrigin-RevId: 468782730
diff --git a/nullability_verification/pointer_nullability_diagnosis.cc b/nullability_verification/pointer_nullability_diagnosis.cc
index 82167f9..7387eef 100644
--- a/nullability_verification/pointer_nullability_diagnosis.cc
+++ b/nullability_verification/pointer_nullability_diagnosis.cc
@@ -8,6 +8,7 @@
 #include "nullability_verification/pointer_nullability_matchers.h"
 #include "clang/AST/Expr.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/Specifiers.h"
 
 namespace clang {
 namespace tidy {
@@ -22,12 +23,7 @@
                                                   const Expr* PointerExpr,
                                                   const Environment& Env) {
   auto* PointerVal = getPointerValueFromExpr(PointerExpr, Env);
-  if (!PointerVal) return PointerAccessExpr;
-
-  auto [PointerKnown, PointerNotNull] = getPointerNullState(*PointerVal, Env);
-  auto& PointerNotKnownNull =
-      Env.makeNot(Env.makeAnd(PointerKnown, Env.makeNot(PointerNotNull)));
-  if (!Env.flowConditionImplies(PointerNotKnownNull)) {
+  if (!PointerVal || isNullable(*PointerVal, Env)) {
     return PointerAccessExpr;
   }
   return llvm::None;
@@ -45,6 +41,38 @@
   return diagnosePointerAccess(MemberExpr, MemberExpr->getBase(), Env);
 }
 
+// TODO(b/233582219): Handle call expressions whose callee is not a decl (e.g.
+// a function returned from another function), or when the callee cannot be
+// interpreted as a function type (e.g. a pointer to a function pointer).
+llvm::Optional<const Stmt*> diagnoseCallExpr(
+    const CallExpr* CE, const MatchFinder::MatchResult& Result,
+    const Environment& Env) {
+  auto* Callee = CE->getCalleeDecl();
+  if (!Callee) return llvm::None;
+
+  auto* CalleeType = Callee->getFunctionType();
+  if (!CalleeType) return llvm::None;
+
+  auto ParamTypes = CalleeType->getAs<FunctionProtoType>()->getParamTypes();
+
+  for (unsigned int I = 0; I < ParamTypes.size(); ++I) {
+    auto ParamType = ParamTypes[I];
+    if (!ParamType->isAnyPointerType() ||
+        ParamType->getNullability(*Result.Context)
+                .value_or(NullabilityKind::Unspecified) !=
+            NullabilityKind::NonNull) {
+      continue;
+    }
+    auto* Arg = CE->getArg(I);
+    auto* PointerVal = getPointerValueFromExpr(Arg, Env);
+    if (!PointerVal || isNullable(*PointerVal, Env)) {
+      return llvm::Optional<const Stmt*>(CE);
+    }
+  }
+
+  return llvm::None;
+}
+
 auto buildDiagnoser() {
   return dataflow::MatchSwitchBuilder<const Environment,
                                       llvm::Optional<const Stmt*>>()
@@ -52,6 +80,8 @@
       .CaseOf<UnaryOperator>(isPointerDereference(), diagnoseDereference)
       // (->)
       .CaseOf<MemberExpr>(isPointerArrow(), diagnoseArrow)
+      // Check compatibility of parameter assignments
+      .CaseOf<CallExpr>(isCallExpr(), diagnoseCallExpr)
       .Build();
 }