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