From 5668c20e027f161eeb0b0bfe6ddbc814705c1c6b Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 20 Jun 2023 07:29:20 -0700 Subject: Add Nullability annotations to Abseil. PiperOrigin-RevId: 541915097 Change-Id: I7ebfbafc36db38b59b30ab5b312cd7e22082a805 --- absl/base/internal/nullability_impl.h | 106 ++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 absl/base/internal/nullability_impl.h (limited to 'absl/base/internal/nullability_impl.h') diff --git a/absl/base/internal/nullability_impl.h b/absl/base/internal/nullability_impl.h new file mode 100644 index 00000000..74f4a417 --- /dev/null +++ b/absl/base/internal/nullability_impl.h @@ -0,0 +1,106 @@ +// Copyright 2023 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_ +#define ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_ + +#include +#include + +#include "absl/base/attributes.h" +#include "absl/meta/type_traits.h" + +namespace absl { + +namespace nullability_internal { + +// `IsNullabilityCompatible` checks whether its first argument is a class +// explicitly tagged as supporting nullability annotations. The tag is the type +// declaration `absl_nullability_compatible`. +template +struct IsNullabilityCompatible : std::false_type {}; + +template +struct IsNullabilityCompatible< + T, absl::void_t> : std::true_type { +}; + +template +constexpr bool IsSupportedType = IsNullabilityCompatible::value; + +template +constexpr bool IsSupportedType = true; + +template +constexpr bool IsSupportedType = true; + +template +constexpr bool IsSupportedType> = true; + +template +constexpr bool IsSupportedType> = true; + +template +struct EnableNullable { + static_assert(nullability_internal::IsSupportedType>, + "Template argument must be a raw or supported smart pointer " + "type. See absl/base/nullability.h."); + using type = T; +}; + +template +struct EnableNonNull { + static_assert(nullability_internal::IsSupportedType>, + "Template argument must be a raw or supported smart pointer " + "type. See absl/base/nullability.h."); + using type = T; +}; + +template +struct EnableNullabilityUnknown { + static_assert(nullability_internal::IsSupportedType>, + "Template argument must be a raw or supported smart pointer " + "type. See absl/base/nullability.h."); + using type = T; +}; + +// Note: we do not apply Clang nullability attributes (e.g. _Nullable). These +// only support raw pointers, and conditionally enabling them only for raw +// pointers inhibits template arg deduction. Ideally, they would support all +// pointer-like types. +template ::type> +using NullableImpl +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) + [[clang::annotate("Nullable")]] +#endif + = T; + +template ::type> +using NonNullImpl +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) + [[clang::annotate("Nonnull")]] +#endif + = T; + +template ::type> +using NullabilityUnknownImpl +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) + [[clang::annotate("Nullability_Unspecified")]] +#endif + = T; + +} // namespace nullability_internal +} // namespace absl + +#endif // ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_ -- cgit v1.2.3 From 93ef827f6160dd41e11042ce638e052272f77d7b Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 6 Jul 2023 10:49:58 -0700 Subject: Rename `absl::NonNull` to `absl::Nonnull`. The current spelling is inconsistent with standard casing rules: "nonnull" is a single word, not two. PiperOrigin-RevId: 546034114 Change-Id: I04e5a204f4a74ebaa76031dd0b0874ca9cfa902c --- absl/base/internal/nullability_impl.h | 6 +++--- absl/base/nullability.h | 18 +++++++++--------- absl/base/nullability_test.cc | 26 +++++++++++++------------- 3 files changed, 25 insertions(+), 25 deletions(-) (limited to 'absl/base/internal/nullability_impl.h') diff --git a/absl/base/internal/nullability_impl.h b/absl/base/internal/nullability_impl.h index 74f4a417..36e1b33d 100644 --- a/absl/base/internal/nullability_impl.h +++ b/absl/base/internal/nullability_impl.h @@ -60,7 +60,7 @@ struct EnableNullable { }; template -struct EnableNonNull { +struct EnableNonnull { static_assert(nullability_internal::IsSupportedType>, "Template argument must be a raw or supported smart pointer " "type. See absl/base/nullability.h."); @@ -86,8 +86,8 @@ using NullableImpl #endif = T; -template ::type> -using NonNullImpl +template ::type> +using NonnullImpl #if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) [[clang::annotate("Nonnull")]] #endif diff --git a/absl/base/nullability.h b/absl/base/nullability.h index 42525dd0..17553d0c 100644 --- a/absl/base/nullability.h +++ b/absl/base/nullability.h @@ -20,7 +20,7 @@ // expected nullability of pointers. These annotations allow you to designate // pointers in one of three classification states: // -// * "Non-null" (for pointers annotated `NonNull`), indicating that it is +// * "Non-null" (for pointers annotated `Nonnull`), indicating that it is // invalid for the given pointer to ever be null. // * "Nullable" (for pointers annotated `Nullable`), indicating that it is // valid for the given pointer to be null. @@ -69,7 +69,7 @@ // // It is important to note that these annotations are not distinct strong // *types*. They are alias templates defined to be equal to the underlying -// pointer type. A pointer annotated `NonNull`, for example, is simply a +// pointer type. A pointer annotated `Nonnull`, for example, is simply a // pointer of type `T*`. Each annotation acts as a form of documentation about // the contract for the given pointer. Each annotation requires providers or // consumers of these pointers across API boundaries to take appropriate steps @@ -91,13 +91,13 @@ // Example: // // // PaySalary() requires the passed pointer to an `Employee` to be non-null. -// void PaySalary(absl::NonNull e) { +// void PaySalary(absl::Nonnull e) { // pay(e->salary); // OK to dereference // } // // // CompleteTransaction() guarantees the returned pointer to an `Account` to // // be non-null. -// absl::NonNull balance CompleteTransaction(double fee) { +// absl::Nonnull balance CompleteTransaction(double fee) { // ... // } // @@ -144,8 +144,8 @@ // These nullability annotations are primarily a human readable signal about the // intended contract of the pointer. They are not *types* and do not currently // provide any correctness guarantees. For example, a pointer annotated as -// `NonNull` is *not guaranteed* to be non-null, and the compiler won't -// alert or prevent assignment of a `Nullable` to a `NonNull`. +// `Nonnull` is *not guaranteed* to be non-null, and the compiler won't +// alert or prevent assignment of a `Nullable` to a `Nonnull`. // =========================================================================== #ifndef ABSL_BASE_NULLABILITY_H_ #define ABSL_BASE_NULLABILITY_H_ @@ -154,7 +154,7 @@ namespace absl { -// absl::NonNull +// absl::Nonnull // // The indicated pointer is never null. It is the responsibility of the provider // of this pointer across an API boundary to ensure that the pointer is never be @@ -168,7 +168,7 @@ namespace absl { // pay(*employee); // OK to dereference // } template -using NonNull = nullability_internal::NonNullImpl; +using Nonnull = nullability_internal::NonnullImpl; // absl::Nullable // @@ -195,7 +195,7 @@ using Nullable = nullability_internal::NullableImpl; // Consumers of these pointers across an API boundary should treat such pointers // with the same caution they treat currently unannotated pointers. Most // existing code will have "unknown" pointers, which should eventually be -// migrated into one of the above two nullability states: `NonNull` or +// migrated into one of the above two nullability states: `Nonnull` or // `Nullable`. // // NOTE: Because this annotation is the global default state, pointers without diff --git a/absl/base/nullability_test.cc b/absl/base/nullability_test.cc index 6edd7cd1..028ea6ca 100644 --- a/absl/base/nullability_test.cc +++ b/absl/base/nullability_test.cc @@ -22,73 +22,73 @@ #include "absl/base/attributes.h" namespace { -using ::absl::NonNull; +using ::absl::Nonnull; using ::absl::NullabilityUnknown; using ::absl::Nullable; -void funcWithNonnullArg(NonNull /*arg*/) {} +void funcWithNonnullArg(Nonnull /*arg*/) {} template -void funcWithDeducedNonnullArg(NonNull /*arg*/) {} +void funcWithDeducedNonnullArg(Nonnull /*arg*/) {} -TEST(NonNullTest, NonNullArgument) { +TEST(NonnullTest, NonnullArgument) { int var = 0; funcWithNonnullArg(&var); funcWithDeducedNonnullArg(&var); } -NonNull funcWithNonnullReturn() { +Nonnull funcWithNonnullReturn() { static int var = 0; return &var; } -TEST(NonNullTest, NonNullReturn) { +TEST(NonnullTest, NonnullReturn) { auto var = funcWithNonnullReturn(); (void)var; } TEST(PassThroughTest, PassesThroughRawPointerToInt) { - EXPECT_TRUE((std::is_same, int*>::value)); + EXPECT_TRUE((std::is_same, int*>::value)); EXPECT_TRUE((std::is_same, int*>::value)); EXPECT_TRUE((std::is_same, int*>::value)); } TEST(PassThroughTest, PassesThroughRawPointerToVoid) { - EXPECT_TRUE((std::is_same, void*>::value)); + EXPECT_TRUE((std::is_same, void*>::value)); EXPECT_TRUE((std::is_same, void*>::value)); EXPECT_TRUE((std::is_same, void*>::value)); } TEST(PassThroughTest, PassesThroughUniquePointerToInt) { using T = std::unique_ptr; - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } TEST(PassThroughTest, PassesThroughSharedPointerToInt) { using T = std::shared_ptr; - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } TEST(PassThroughTest, PassesThroughSharedPointerToVoid) { using T = std::shared_ptr; - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } TEST(PassThroughTest, PassesThroughPointerToMemberObject) { using T = decltype(&std::pair::first); - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } TEST(PassThroughTest, PassesThroughPointerToMemberFunction) { using T = decltype(&std::unique_ptr::reset); - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } -- cgit v1.2.3