1 | // Copyright 2023 The Abseil Authors. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | // |
15 | // ----------------------------------------------------------------------------- |
16 | // File: nullability.h |
17 | // ----------------------------------------------------------------------------- |
18 | // |
19 | // This header file defines a set of "templated annotations" for designating the |
20 | // expected nullability of pointers. These annotations allow you to designate |
21 | // pointers in one of three classification states: |
22 | // |
23 | // * "Non-null" (for pointers annotated `Nonnull<T>`), indicating that it is |
24 | // invalid for the given pointer to ever be null. |
25 | // * "Nullable" (for pointers annotated `Nullable<T>`), indicating that it is |
26 | // valid for the given pointer to be null. |
27 | // * "Unknown" (for pointers annotated `NullabilityUnknown<T>`), indicating |
28 | // that the given pointer has not been yet classified as either nullable or |
29 | // non-null. This is the default state of unannotated pointers. |
30 | // |
31 | // NOTE: unannotated pointers implicitly bear the annotation |
32 | // `NullabilityUnknown<T>`; you should rarely, if ever, see this annotation used |
33 | // in the codebase explicitly. |
34 | // |
35 | // ----------------------------------------------------------------------------- |
36 | // Nullability and Contracts |
37 | // ----------------------------------------------------------------------------- |
38 | // |
39 | // These nullability annotations allow you to more clearly specify contracts on |
40 | // software components by narrowing the *preconditions*, *postconditions*, and |
41 | // *invariants* of pointer state(s) in any given interface. It then depends on |
42 | // context who is responsible for fulfilling the annotation's requirements. |
43 | // |
44 | // For example, a function may receive a pointer argument. Designating that |
45 | // pointer argument as "non-null" tightens the precondition of the contract of |
46 | // that function. It is then the responsibility of anyone calling such a |
47 | // function to ensure that the passed pointer is not null. |
48 | // |
49 | // Similarly, a function may have a pointer as a return value. Designating that |
50 | // return value as "non-null" tightens the postcondition of the contract of that |
51 | // function. In this case, however, it is the responsibility of the function |
52 | // itself to ensure that the returned pointer is not null. |
53 | // |
54 | // Clearly defining these contracts allows providers (and consumers) of such |
55 | // pointers to have more confidence in their null state. If a function declares |
56 | // a return value as "non-null", for example, the caller should not need to |
57 | // check whether the returned value is `nullptr`; it can simply assume the |
58 | // pointer is valid. |
59 | // |
60 | // Of course most interfaces already have expectations on the nullability state |
61 | // of pointers, and these expectations are, in effect, a contract; often, |
62 | // however, those contracts are either poorly or partially specified, assumed, |
63 | // or misunderstood. These nullability annotations are designed to allow you to |
64 | // formalize those contracts within the codebase. |
65 | // |
66 | // ----------------------------------------------------------------------------- |
67 | // Using Nullability Annotations |
68 | // ----------------------------------------------------------------------------- |
69 | // |
70 | // It is important to note that these annotations are not distinct strong |
71 | // *types*. They are alias templates defined to be equal to the underlying |
72 | // pointer type. A pointer annotated `Nonnull<T*>`, for example, is simply a |
73 | // pointer of type `T*`. Each annotation acts as a form of documentation about |
74 | // the contract for the given pointer. Each annotation requires providers or |
75 | // consumers of these pointers across API boundaries to take appropriate steps |
76 | // when setting or using these pointers: |
77 | // |
78 | // * "Non-null" pointers should never be null. It is the responsibility of the |
79 | // provider of this pointer to ensure that the pointer may never be set to |
80 | // null. Consumers of such pointers can treat such pointers as non-null. |
81 | // * "Nullable" pointers may or may not be null. Consumers of such pointers |
82 | // should precede any usage of that pointer (e.g. a dereference operation) |
83 | // with a a `nullptr` check. |
84 | // * "Unknown" pointers may be either "non-null" or "nullable" but have not been |
85 | // definitively determined to be in either classification state. Providers of |
86 | // such pointers across API boundaries should determine -- over time -- to |
87 | // annotate the pointer in either of the above two states. Consumers of such |
88 | // pointers across an API boundary should continue to treat such pointers as |
89 | // they currently do. |
90 | // |
91 | // Example: |
92 | // |
93 | // // PaySalary() requires the passed pointer to an `Employee` to be non-null. |
94 | // void PaySalary(absl::Nonnull<Employee *> e) { |
95 | // pay(e->salary); // OK to dereference |
96 | // } |
97 | // |
98 | // // CompleteTransaction() guarantees the returned pointer to an `Account` to |
99 | // // be non-null. |
100 | // absl::Nonnull<Account *> balance CompleteTransaction(double fee) { |
101 | // ... |
102 | // } |
103 | // |
104 | // // Note that specifying a nullability annotation does not prevent someone |
105 | // // from violating the contract: |
106 | // |
107 | // Nullable<Employee *> find(Map& employees, std::string_view name); |
108 | // |
109 | // void g(Map& employees) { |
110 | // Employee *e = find(employees, "Pat"); |
111 | // // `e` can now be null. |
112 | // PaySalary(e); // Violates contract, but compiles! |
113 | // } |
114 | // |
115 | // Nullability annotations, in other words, are useful for defining and |
116 | // narrowing contracts; *enforcement* of those contracts depends on use and any |
117 | // additional (static or dynamic analysis) tooling. |
118 | // |
119 | // NOTE: The "unknown" annotation state indicates that a pointer's contract has |
120 | // not yet been positively identified. The unknown state therefore acts as a |
121 | // form of documentation of your technical debt, and a codebase that adopts |
122 | // nullability annotations should aspire to annotate every pointer as either |
123 | // "non-null" or "nullable". |
124 | // |
125 | // ----------------------------------------------------------------------------- |
126 | // Applicability of Nullability Annotations |
127 | // ----------------------------------------------------------------------------- |
128 | // |
129 | // By default, nullability annotations are applicable to raw and smart |
130 | // pointers. User-defined types can indicate compatibility with nullability |
131 | // annotations by providing an `absl_nullability_compatible` nested type. The |
132 | // actual definition of this inner type is not relevant as it is used merely as |
133 | // a marker. It is common to use a using declaration of |
134 | // `absl_nullability_compatible` set to void. |
135 | // |
136 | // // Example: |
137 | // struct MyPtr { |
138 | // using absl_nullability_compatible = void; |
139 | // ... |
140 | // }; |
141 | // |
142 | // DISCLAIMER: |
143 | // =========================================================================== |
144 | // These nullability annotations are primarily a human readable signal about the |
145 | // intended contract of the pointer. They are not *types* and do not currently |
146 | // provide any correctness guarantees. For example, a pointer annotated as |
147 | // `Nonnull<T*>` is *not guaranteed* to be non-null, and the compiler won't |
148 | // alert or prevent assignment of a `Nullable<T*>` to a `Nonnull<T*>`. |
149 | // =========================================================================== |
150 | #ifndef ABSL_BASE_NULLABILITY_H_ |
151 | #define ABSL_BASE_NULLABILITY_H_ |
152 | |
153 | #include "absl/base/internal/nullability_impl.h" |
154 | |
155 | namespace absl { |
156 | |
157 | // absl::Nonnull |
158 | // |
159 | // The indicated pointer is never null. It is the responsibility of the provider |
160 | // of this pointer across an API boundary to ensure that the pointer is never be |
161 | // set to null. Consumers of this pointer across an API boundary may safely |
162 | // dereference the pointer. |
163 | // |
164 | // Example: |
165 | // |
166 | // // `employee` is designated as not null. |
167 | // void PaySalary(absl::Nonnull<Employee *> employee) { |
168 | // pay(*employee); // OK to dereference |
169 | // } |
170 | template <typename T> |
171 | using Nonnull = nullability_internal::NonnullImpl<T>; |
172 | |
173 | // absl::Nullable |
174 | // |
175 | // The indicated pointer may, by design, be either null or non-null. Consumers |
176 | // of this pointer across an API boundary should perform a `nullptr` check |
177 | // before performing any operation using the pointer. |
178 | // |
179 | // Example: |
180 | // |
181 | // // `employee` may be null. |
182 | // void PaySalary(absl::Nullable<Employee *> employee) { |
183 | // if (employee != nullptr) { |
184 | // Pay(*employee); // OK to dereference |
185 | // } |
186 | // } |
187 | template <typename T> |
188 | using Nullable = nullability_internal::NullableImpl<T>; |
189 | |
190 | // absl::NullabilityUnknown (default) |
191 | // |
192 | // The indicated pointer has not yet been determined to be definitively |
193 | // "non-null" or "nullable." Providers of such pointers across API boundaries |
194 | // should, over time, annotate such pointers as either "non-null" or "nullable." |
195 | // Consumers of these pointers across an API boundary should treat such pointers |
196 | // with the same caution they treat currently unannotated pointers. Most |
197 | // existing code will have "unknown" pointers, which should eventually be |
198 | // migrated into one of the above two nullability states: `Nonnull<T>` or |
199 | // `Nullable<T>`. |
200 | // |
201 | // NOTE: Because this annotation is the global default state, pointers without |
202 | // any annotation are assumed to have "unknown" semantics. This assumption is |
203 | // designed to minimize churn and reduce clutter within the codebase. |
204 | // |
205 | // Example: |
206 | // |
207 | // // `employee`s nullability state is unknown. |
208 | // void PaySalary(absl::NullabilityUnknown<Employee *> employee) { |
209 | // Pay(*employee); // Potentially dangerous. API provider should investigate. |
210 | // } |
211 | // |
212 | // Note that a pointer without an annotation, by default, is assumed to have the |
213 | // annotation `NullabilityUnknown`. |
214 | // |
215 | // // `employee`s nullability state is unknown. |
216 | // void PaySalary(Employee* employee) { |
217 | // Pay(*employee); // Potentially dangerous. API provider should investigate. |
218 | // } |
219 | template <typename T> |
220 | using NullabilityUnknown = nullability_internal::NullabilityUnknownImpl<T>; |
221 | |
222 | } // namespace absl |
223 | |
224 | #endif // ABSL_BASE_NULLABILITY_H_ |
225 | |