xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp (revision 11c423f9bebc3be27722225ca8120e8775be836c)
1 // RUN: %check_clang_tidy %s bugprone-unchecked-optional-access %t -- -- -I %S/Inputs/unchecked-optional-access
2 
3 #include "absl/types/optional.h"
4 #include "folly/types/Optional.h"
5 #include "bde/types/bsl_optional.h"
6 #include "bde/types/bdlb_nullablevalue.h"
7 
8 void unchecked_value_access(const absl::optional<int> &opt) {
9   opt.value();
10   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
11 }
12 
13 void unchecked_deref_operator_access(const absl::optional<int> &opt) {
14   *opt;
15   // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: unchecked access to optional value
16 }
17 
18 struct Foo {
19   void foo() const {}
20 };
21 
22 void unchecked_arrow_operator_access(const absl::optional<Foo> &opt) {
23   opt->foo();
24   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
25 }
26 
27 void folly_check_value_then_reset(folly::Optional<int> opt) {
28   if (opt) {
29     opt.reset();
30     opt.value();
31     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
32   }
33 }
34 
35 void folly_value_after_swap(folly::Optional<int> opt1, folly::Optional<int> opt2) {
36   if (opt1) {
37     opt1.swap(opt2);
38     opt1.value();
39     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
40   }
41 }
42 
43 void checked_access(const absl::optional<int> &opt) {
44   if (opt.has_value()) {
45     opt.value();
46   }
47 }
48 
49 void folly_checked_access(const folly::Optional<int> &opt) {
50   if (opt.hasValue()) {
51     opt.value();
52   }
53 }
54 
55 void bsl_optional_unchecked_value_access(const bsl::optional<int> &opt) {
56   opt.value();
57   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
58 
59   int x = *opt;
60   // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
61 
62   if (!opt) {
63     return;
64   }
65 
66   opt.value();
67   x = *opt;
68 }
69 
70 void bsl_optional_checked_access(const bsl::optional<int> &opt) {
71   if (opt.has_value()) {
72     opt.value();
73   }
74   if (opt) {
75     opt.value();
76   }
77 }
78 
79 void bsl_optional_value_after_swap(bsl::optional<int> &opt1, bsl::optional<int> &opt2) {
80   if (opt1) {
81     opt1.swap(opt2);
82     opt1.value();
83     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
84   }
85 }
86 
87 void nullable_value_unchecked_value_access(const BloombergLP::bdlb::NullableValue<int> &opt) {
88   opt.value();
89   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
90 
91   int x = *opt;
92   // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
93 
94   if (opt.isNull()) {
95     opt.value();
96   }
97   // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
98 
99   if (!opt) {
100     opt.value();
101   }
102   // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
103 
104   if (!opt) {
105     return;
106   }
107 
108   opt.value();
109   x = *opt;
110 }
111 
112 void nullable_value_optional_checked_access(const BloombergLP::bdlb::NullableValue<int> &opt) {
113   if (opt.has_value()) {
114     opt.value();
115   }
116   if (opt) {
117     opt.value();
118   }
119   if (!opt.isNull()) {
120     opt.value();
121   }
122 }
123 
124 void nullable_value_emplaced(BloombergLP::bdlb::NullableValue<int> &opt) {
125   opt.value();
126   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
127 
128   opt.emplace(1);
129   opt.value();
130 
131   opt.reset();
132   opt.value();
133   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value [bugprone-unchecked-optional-access]
134 }
135 
136 void nullable_value_after_swap(BloombergLP::bdlb::NullableValue<int> &opt1, BloombergLP::bdlb::NullableValue<int> &opt2) {
137   if (opt1) {
138     opt1.swap(opt2);
139     opt1.value();
140     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional value
141   }
142 }
143 
144 template <typename T>
145 void function_template_without_user(const absl::optional<T> &opt) {
146   opt.value(); // no-warning
147 }
148 
149 template <typename T>
150 void function_template_with_user(const absl::optional<T> &opt) {
151   opt.value();
152   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
153 }
154 
155 void function_template_user(const absl::optional<int> &opt) {
156   // Instantiate the f3 function template so that it gets matched by the check.
157   function_template_with_user(opt);
158 }
159 
160 template <typename T>
161 void function_template_with_specialization(const absl::optional<int> &opt) {
162   opt.value(); // no-warning
163 }
164 
165 template <>
166 void function_template_with_specialization<int>(
167     const absl::optional<int> &opt) {
168   opt.value();
169   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
170 }
171 
172 template <typename T>
173 class ClassTemplateWithSpecializations {
174   void f(const absl::optional<int> &opt) {
175     opt.value(); // no-warning
176   }
177 };
178 
179 template <typename T>
180 class ClassTemplateWithSpecializations<T *> {
181   void f(const absl::optional<int> &opt) {
182     opt.value(); // no-warning
183   }
184 };
185 
186 template <>
187 class ClassTemplateWithSpecializations<int> {
188   void f(const absl::optional<int> &opt) {
189     opt.value();
190     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional
191   }
192 };
193 
194 // The templates below are not instantiated and CFGs can not be properly built
195 // for them. They are here to make sure that the checker does not crash, but
196 // instead ignores non-instantiated templates.
197 
198 template <typename T>
199 struct C1 {};
200 
201 template <typename T>
202 struct C2 : public C1<T> {
203   ~C2() {}
204 };
205 
206 template <typename T, template <class> class B>
207 struct C3 : public B<T> {
208   ~C3() {}
209 };
210 
211 void multiple_unchecked_accesses(absl::optional<int> opt1,
212                                  absl::optional<int> opt2) {
213   for (int i = 0; i < 10; i++) {
214     opt1.value();
215     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: unchecked access to optional
216   }
217   opt2.value();
218   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional value
219 }
220 
221 class C4 {
222   explicit C4(absl::optional<int> opt) : foo_(opt.value()) {
223     // CHECK-MESSAGES: :[[@LINE-1]]:47: warning: unchecked access to optional
224   }
225   int foo_;
226 };
227 
228 // llvm#59705
229 namespace std
230 {
231   template <typename T>
232   constexpr T&& forward(T& type) noexcept {
233     return static_cast<T&&>(type);
234   }
235 
236   template <typename T>
237   constexpr T&& forward(T&& type) noexcept {
238     return static_cast<T&&>(type);
239   }
240 }
241 
242 void std_forward_copy(absl::optional<int> opt) {
243   std::forward<absl::optional<int>>(opt).value();
244   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional
245 }
246 
247 void std_forward_copy_safe(absl::optional<int> opt) {
248   if (!opt) return;
249 
250   std::forward<absl::optional<int>>(opt).value();
251 }
252 
253 void std_forward_copy(absl::optional<int>& opt) {
254   std::forward<absl::optional<int>>(opt).value();
255   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional
256 }
257 
258 void std_forward_lvalue_ref_safe(absl::optional<int>& opt) {
259   if (!opt) return;
260 
261   std::forward<absl::optional<int>>(opt).value();
262 }
263 
264 void std_forward_copy(absl::optional<int>&& opt) {
265   std::forward<absl::optional<int>>(opt).value();
266   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional
267 }
268 
269 void std_forward_rvalue_ref_safe(absl::optional<int>&& opt) {
270   if (!opt) return;
271 
272   std::forward<absl::optional<int>>(opt).value();
273 }
274 
275 namespace std {
276 
277 template <typename T> class vector {
278 public:
279   T &operator[](unsigned long index);
280   bool empty();
281 };
282 
283 } // namespace std
284 
285 struct S {
286   absl::optional<float> x;
287 };
288 std::vector<S> vec;
289 
290 void foo() {
291   if (!vec.empty())
292     vec[0].x = 0;
293 }
294