123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- // 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.
- //
- // -----------------------------------------------------------------------------
- // File: nullability.h
- // -----------------------------------------------------------------------------
- //
- // This header file defines a set of "templated annotations" for designating the
- // expected nullability of pointers. These annotations allow you to designate
- // pointers in one of three classification states:
- //
- // * "Non-null" (for pointers annotated `Nonnull<T>`), indicating that it is
- // invalid for the given pointer to ever be null.
- // * "Nullable" (for pointers annotated `Nullable<T>`), indicating that it is
- // valid for the given pointer to be null.
- // * "Unknown" (for pointers annotated `NullabilityUnknown<T>`), indicating
- // that the given pointer has not been yet classified as either nullable or
- // non-null. This is the default state of unannotated pointers.
- //
- // NOTE: unannotated pointers implicitly bear the annotation
- // `NullabilityUnknown<T>`; you should rarely, if ever, see this annotation used
- // in the codebase explicitly.
- //
- // -----------------------------------------------------------------------------
- // Nullability and Contracts
- // -----------------------------------------------------------------------------
- //
- // These nullability annotations allow you to more clearly specify contracts on
- // software components by narrowing the *preconditions*, *postconditions*, and
- // *invariants* of pointer state(s) in any given interface. It then depends on
- // context who is responsible for fulfilling the annotation's requirements.
- //
- // For example, a function may receive a pointer argument. Designating that
- // pointer argument as "non-null" tightens the precondition of the contract of
- // that function. It is then the responsibility of anyone calling such a
- // function to ensure that the passed pointer is not null.
- //
- // Similarly, a function may have a pointer as a return value. Designating that
- // return value as "non-null" tightens the postcondition of the contract of that
- // function. In this case, however, it is the responsibility of the function
- // itself to ensure that the returned pointer is not null.
- //
- // Clearly defining these contracts allows providers (and consumers) of such
- // pointers to have more confidence in their null state. If a function declares
- // a return value as "non-null", for example, the caller should not need to
- // check whether the returned value is `nullptr`; it can simply assume the
- // pointer is valid.
- //
- // Of course most interfaces already have expectations on the nullability state
- // of pointers, and these expectations are, in effect, a contract; often,
- // however, those contracts are either poorly or partially specified, assumed,
- // or misunderstood. These nullability annotations are designed to allow you to
- // formalize those contracts within the codebase.
- //
- // -----------------------------------------------------------------------------
- // Using Nullability Annotations
- // -----------------------------------------------------------------------------
- //
- // 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<T*>`, 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
- // when setting or using these pointers:
- //
- // * "Non-null" pointers should never be null. It is the responsibility of the
- // provider of this pointer to ensure that the pointer may never be set to
- // null. Consumers of such pointers can treat such pointers as non-null.
- // * "Nullable" pointers may or may not be null. Consumers of such pointers
- // should precede any usage of that pointer (e.g. a dereference operation)
- // with a a `nullptr` check.
- // * "Unknown" pointers may be either "non-null" or "nullable" but have not been
- // definitively determined to be in either classification state. Providers of
- // such pointers across API boundaries should determine -- over time -- to
- // annotate the pointer in either of the above two states. Consumers of such
- // pointers across an API boundary should continue to treat such pointers as
- // they currently do.
- //
- // Example:
- //
- // // PaySalary() requires the passed pointer to an `Employee` to be non-null.
- // void PaySalary(absl::Nonnull<Employee *> e) {
- // pay(e->salary); // OK to dereference
- // }
- //
- // // CompleteTransaction() guarantees the returned pointer to an `Account` to
- // // be non-null.
- // absl::Nonnull<Account *> balance CompleteTransaction(double fee) {
- // ...
- // }
- //
- // // Note that specifying a nullability annotation does not prevent someone
- // // from violating the contract:
- //
- // Nullable<Employee *> find(Map& employees, std::string_view name);
- //
- // void g(Map& employees) {
- // Employee *e = find(employees, "Pat");
- // // `e` can now be null.
- // PaySalary(e); // Violates contract, but compiles!
- // }
- //
- // Nullability annotations, in other words, are useful for defining and
- // narrowing contracts; *enforcement* of those contracts depends on use and any
- // additional (static or dynamic analysis) tooling.
- //
- // NOTE: The "unknown" annotation state indicates that a pointer's contract has
- // not yet been positively identified. The unknown state therefore acts as a
- // form of documentation of your technical debt, and a codebase that adopts
- // nullability annotations should aspire to annotate every pointer as either
- // "non-null" or "nullable".
- //
- // -----------------------------------------------------------------------------
- // Applicability of Nullability Annotations
- // -----------------------------------------------------------------------------
- //
- // By default, nullability annotations are applicable to raw and smart
- // pointers. User-defined types can indicate compatibility with nullability
- // annotations by providing an `absl_nullability_compatible` nested type. The
- // actual definition of this inner type is not relevant as it is used merely as
- // a marker. It is common to use a using declaration of
- // `absl_nullability_compatible` set to void.
- //
- // // Example:
- // struct MyPtr {
- // using absl_nullability_compatible = void;
- // ...
- // };
- //
- // DISCLAIMER:
- // ===========================================================================
- // 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<T*>` is *not guaranteed* to be non-null, and the compiler won't
- // alert or prevent assignment of a `Nullable<T*>` to a `Nonnull<T*>`.
- // ===========================================================================
- #ifndef ABSL_BASE_NULLABILITY_H_
- #define ABSL_BASE_NULLABILITY_H_
- #include "absl/base/internal/nullability_impl.h"
- namespace absl {
- // 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
- // set to null. Consumers of this pointer across an API boundary may safely
- // dereference the pointer.
- //
- // Example:
- //
- // // `employee` is designated as not null.
- // void PaySalary(absl::Nonnull<Employee *> employee) {
- // pay(*employee); // OK to dereference
- // }
- template <typename T>
- using Nonnull = nullability_internal::NonnullImpl<T>;
- // absl::Nullable
- //
- // The indicated pointer may, by design, be either null or non-null. Consumers
- // of this pointer across an API boundary should perform a `nullptr` check
- // before performing any operation using the pointer.
- //
- // Example:
- //
- // // `employee` may be null.
- // void PaySalary(absl::Nullable<Employee *> employee) {
- // if (employee != nullptr) {
- // Pay(*employee); // OK to dereference
- // }
- // }
- template <typename T>
- using Nullable = nullability_internal::NullableImpl<T>;
- // absl::NullabilityUnknown (default)
- //
- // The indicated pointer has not yet been determined to be definitively
- // "non-null" or "nullable." Providers of such pointers across API boundaries
- // should, over time, annotate such pointers as either "non-null" or "nullable."
- // 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<T>` or
- // `Nullable<T>`.
- //
- // NOTE: Because this annotation is the global default state, pointers without
- // any annotation are assumed to have "unknown" semantics. This assumption is
- // designed to minimize churn and reduce clutter within the codebase.
- //
- // Example:
- //
- // // `employee`s nullability state is unknown.
- // void PaySalary(absl::NullabilityUnknown<Employee *> employee) {
- // Pay(*employee); // Potentially dangerous. API provider should investigate.
- // }
- //
- // Note that a pointer without an annotation, by default, is assumed to have the
- // annotation `NullabilityUnknown`.
- //
- // // `employee`s nullability state is unknown.
- // void PaySalary(Employee* employee) {
- // Pay(*employee); // Potentially dangerous. API provider should investigate.
- // }
- template <typename T>
- using NullabilityUnknown = nullability_internal::NullabilityUnknownImpl<T>;
- } // namespace absl
- #endif // ABSL_BASE_NULLABILITY_H_
|