Rename /nullability_verification to /nullability in preparation for adding/relocating inference functionality here.
PiperOrigin-RevId: 528495113
diff --git a/nullability/test/function_pointers.cc b/nullability/test/function_pointers.cc
new file mode 100644
index 0000000..290ba15
--- /dev/null
+++ b/nullability/test/function_pointers.cc
@@ -0,0 +1,101 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// Tests for nullability of function pointers.
+
+#include "nullability/test/check_diagnostics.h"
+#include "third_party/llvm/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+namespace nullability {
+namespace {
+
+TEST(PointerNullabilityTest, FunctionToPointerDecayIsNonnull) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ void target() {
+ // Use `static_cast` to force function-to-pointer decay.
+ __assert_nullability<NK_nonnull>(static_cast<void (*)()>(target));
+ }
+ )cc"));
+}
+
+TEST(PointerNullabilityTest, CallExplicitlyDereferencedDirectCallee) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ void callee();
+ void target() { (*callee)(); }
+ )cc"));
+}
+
+TEST(PointerNullabilityTest, AnnotationsInReturnType) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ int* _Nullable target() {
+ // Use `static_cast` to force function-to-pointer decay.
+ __assert_nullability<NK_nonnull, NK_nullable>(
+ static_cast<int* (*)()>(target));
+ return nullptr;
+ }
+ )cc"));
+}
+
+TEST(PointerNullabilityTest, AnnotationsInParameters) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ void target(int *_Nullable) {
+ // Use `static_cast` to force function-to-pointer decay.
+ __assert_nullability<NK_nonnull, NK_nullable>(
+ static_cast<void (*)(int *)>(target));
+ }
+ )cc"));
+}
+
+TEST(PointerNullabilityTest, NonnullCallback) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ void target(void (*_Nonnull callback)()) {
+ // Both an explicit dereference and an implicit dereference done by a
+ // function call should be allowed.
+ (*callback)();
+ callback();
+ }
+ )cc"));
+}
+
+TEST(PointerNullabilityTest, NullableCallback) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ void target(void (*_Nullable callback)()) {
+ // Both an explicit dereference and an implicit dereference done by a
+ // function call should be marked as unsafe.
+ (*callback)(); // [[unsafe]]
+ callback(); // [[unsafe]]
+ }
+ )cc"));
+}
+
+TEST(PointerNullabilityTest, NonnullCallbackWithoutCalleeDecl) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ using NonnullCallbackType = void (*_Nonnull)();
+ NonnullCallbackType getCallback();
+ void target() {
+ __assert_nullability<NK_nonnull>(getCallback());
+ (*getCallback())();
+ getCallback()();
+ }
+ )cc"));
+}
+
+TEST(PointerNullabilityTest, NullableCallbackWithoutCalleeDecl) {
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ using NullableCallbackType = void (*_Nullable)();
+ NullableCallbackType getCallback();
+ void target(bool b) {
+ __assert_nullability<NK_nullable>(getCallback());
+ (*getCallback())(); // [[unsafe]]
+ getCallback()(); // [[unsafe]]
+ }
+ )cc"));
+}
+
+} // namespace
+} // namespace nullability
+} // namespace tidy
+} // namespace clang