[NFC] [FlowSensitive] [StatusOr] Add tests for pointer receivers



Reviewers: jvoung

Reviewed By: jvoung

Pull Request: https://github.com/llvm/llvm-project/pull/180079
diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp
index f842abe..9c804b7 100644
--- a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp
@@ -3984,6 +3984,134 @@
   )cc");
 }
 
+TEST_P(UncheckedStatusOrAccessModelTest, PointerReceivers) {
+  // The following examples are not sound as there could be opaque calls between
+  // the ok() and the value() calls that change the StatusOr value. However,
+  // this is the behavior that users expect so it is here to stay.
+  ExpectDiagnosticsFor(R"cc(
+#include "unchecked_statusor_access_test_defs.h"
+
+    void target(STATUSOR_INT* sor) {
+      sor->value();  // [[unsafe]]
+    }
+  )cc");
+  ExpectDiagnosticsFor(R"cc(
+#include "unchecked_statusor_access_test_defs.h"
+
+    void target(STATUSOR_INT* sor) {
+      sor->emplace(1);
+      sor->value();
+    }
+  )cc");
+  ExpectDiagnosticsFor(R"cc(
+#include "unchecked_statusor_access_test_defs.h"
+
+    void target(STATUSOR_INT* sor) {
+      if (sor->ok())
+        sor->value();
+      else
+        sor->value();  // [[unsafe]]
+    }
+  )cc");
+  ExpectDiagnosticsFor(R"cc(
+#include "unchecked_statusor_access_test_defs.h"
+
+    void target(STATUS* s) {
+      STATUSOR_INT* sor = Make<STATUSOR_INT*>();
+      if (!s->ok()) return;
+      if (*s == sor->status())
+        sor->value();
+      else
+        sor->value();  // [[unsafe]]
+    }
+  )cc");
+  ExpectDiagnosticsFor(R"cc(
+#include "unchecked_statusor_access_test_defs.h"
+
+    struct Foo {
+      STATUSOR_INT* sor;
+    };
+
+    void target(Foo foo) {
+      if (foo.sor->ok())
+        foo.sor->value();
+      else
+        foo.sor->value();  // [[unsafe]]
+    }
+  )cc");
+  ExpectDiagnosticsFor(R"cc(
+#include "unchecked_statusor_access_test_defs.h"
+
+    struct Foo {
+      STATUSOR_INT* sor;
+    };
+
+    void target(Foo foo) {
+      if (foo.sor->status().ok())
+        foo.sor->value();
+      else
+        foo.sor->value();  // [[unsafe]]
+    }
+  )cc");
+}
+
+TEST_P(UncheckedStatusOrAccessModelTest, PointerReceiversWithSelfReferentials) {
+  // Same as PointerReceivers, but with a self-referential pointer.
+  ExpectDiagnosticsFor(R"cc(
+#include "unchecked_statusor_access_test_defs.h"
+
+    struct Bar;
+    struct Foo {
+      STATUSOR_INT* sor;
+      Bar* bar;
+    };
+    struct Bar {
+      Foo* foo;
+    };
+
+    void target(Bar* bar) {
+      if (bar->foo->sor->status().ok())
+        bar->foo->sor->value();
+      else
+        bar->foo->sor->value();  // [[unsafe]]
+    }
+  )cc");
+
+  ExpectDiagnosticsFor(R"cc(
+#include "unchecked_statusor_access_test_defs.h"
+
+    struct Foo {
+      Foo* next;
+      STATUSOR_INT* sor;
+    };
+
+    void target(Foo* foo) {
+      if (foo->next->sor->status().ok())
+        // False positive, should be safe.
+        foo->next->sor->value();  // [[unsafe]]
+      else
+        foo->next->sor->value();  // [[unsafe]]
+    }
+  )cc");
+}
+
+TEST_P(UncheckedStatusOrAccessModelTest, PointerReceiversWithUnion) {
+  ExpectDiagnosticsFor(R"cc(
+#include "unchecked_statusor_access_test_defs.h"
+
+    union Foo {
+      STATUSOR_INT* sor;
+    };
+
+    void target(Foo foo) {
+      if (foo.sor->ok())
+        foo.sor->value();
+      else
+        foo.sor->value();  // [[unsafe]]
+    }
+  )cc");
+}
+
 TEST_P(UncheckedStatusOrAccessModelTest, PointerLike) {
   ExpectDiagnosticsFor(R"cc(
 #include "unchecked_statusor_access_test_defs.h"