xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (revision 092a530ca1878df08dc616cb43072044a39fb132)
1 //===- UncheckedOptionalAccessModelTest.cpp -------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // FIXME: Move this to clang/unittests/Analysis/FlowSensitive/Models.
9 
10 #include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h"
11 #include "TestingSupport.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h"
15 #include "clang/Tooling/Tooling.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/Support/Error.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include <string>
22 #include <utility>
23 #include <vector>
24 
25 using namespace clang;
26 using namespace dataflow;
27 using namespace test;
28 
29 using ::testing::Pair;
30 using ::testing::UnorderedElementsAre;
31 
32 // FIXME: Move header definitions in separate file(s).
33 static constexpr char StdTypeTraitsHeader[] = R"(
34 #ifndef STD_TYPE_TRAITS_H
35 #define STD_TYPE_TRAITS_H
36 
37 namespace std {
38 
39 typedef decltype(sizeof(char)) size_t;
40 
41 template <typename T, T V>
42 struct integral_constant {
43   static constexpr T value = V;
44 };
45 
46 using true_type = integral_constant<bool, true>;
47 using false_type = integral_constant<bool, false>;
48 
49 template< class T > struct remove_reference      {typedef T type;};
50 template< class T > struct remove_reference<T&>  {typedef T type;};
51 template< class T > struct remove_reference<T&&> {typedef T type;};
52 
53 template <class T>
54   using remove_reference_t = typename remove_reference<T>::type;
55 
56 template <class T>
57 struct remove_extent {
58   typedef T type;
59 };
60 
61 template <class T>
62 struct remove_extent<T[]> {
63   typedef T type;
64 };
65 
66 template <class T, size_t N>
67 struct remove_extent<T[N]> {
68   typedef T type;
69 };
70 
71 template <class T>
72 struct is_array : false_type {};
73 
74 template <class T>
75 struct is_array<T[]> : true_type {};
76 
77 template <class T, size_t N>
78 struct is_array<T[N]> : true_type {};
79 
80 template <class>
81 struct is_function : false_type {};
82 
83 template <class Ret, class... Args>
84 struct is_function<Ret(Args...)> : true_type {};
85 
86 namespace detail {
87 
88 template <class T>
89 struct type_identity {
90   using type = T;
91 };  // or use type_identity (since C++20)
92 
93 template <class T>
94 auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>;
95 template <class T>
96 auto try_add_pointer(...) -> type_identity<T>;
97 
98 }  // namespace detail
99 
100 template <class T>
101 struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
102 
103 template <bool B, class T, class F>
104 struct conditional {
105   typedef T type;
106 };
107 
108 template <class T, class F>
109 struct conditional<false, T, F> {
110   typedef F type;
111 };
112 
113 template <class T>
114 struct remove_cv {
115   typedef T type;
116 };
117 template <class T>
118 struct remove_cv<const T> {
119   typedef T type;
120 };
121 template <class T>
122 struct remove_cv<volatile T> {
123   typedef T type;
124 };
125 template <class T>
126 struct remove_cv<const volatile T> {
127   typedef T type;
128 };
129 
130 template <class T>
131 using remove_cv_t = typename remove_cv<T>::type;
132 
133 template <class T>
134 struct decay {
135  private:
136   typedef typename remove_reference<T>::type U;
137 
138  public:
139   typedef typename conditional<
140       is_array<U>::value, typename remove_extent<U>::type*,
141       typename conditional<is_function<U>::value, typename add_pointer<U>::type,
142                            typename remove_cv<U>::type>::type>::type type;
143 };
144 
145 template <bool B, class T = void>
146 struct enable_if {};
147 
148 template <class T>
149 struct enable_if<true, T> {
150   typedef T type;
151 };
152 
153 template <bool B, class T = void>
154 using enable_if_t = typename enable_if<B, T>::type;
155 
156 template <class T, class U>
157 struct is_same : false_type {};
158 
159 template <class T>
160 struct is_same<T, T> : true_type {};
161 
162 template <class T>
163 struct is_void : is_same<void, typename remove_cv<T>::type> {};
164 
165 namespace detail {
166 
167 template <class T>
168 auto try_add_rvalue_reference(int) -> type_identity<T&&>;
169 template <class T>
170 auto try_add_rvalue_reference(...) -> type_identity<T>;
171 
172 }  // namespace detail
173 
174 template <class T>
175 struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {
176 };
177 
178 template <class T>
179 typename add_rvalue_reference<T>::type declval() noexcept;
180 
181 namespace detail {
182 
183 template <class T>
184 auto test_returnable(int)
185     -> decltype(void(static_cast<T (*)()>(nullptr)), true_type{});
186 template <class>
187 auto test_returnable(...) -> false_type;
188 
189 template <class From, class To>
190 auto test_implicitly_convertible(int)
191     -> decltype(void(declval<void (&)(To)>()(declval<From>())), true_type{});
192 template <class, class>
193 auto test_implicitly_convertible(...) -> false_type;
194 
195 }  // namespace detail
196 
197 template <class From, class To>
198 struct is_convertible
199     : integral_constant<bool,
200                         (decltype(detail::test_returnable<To>(0))::value &&
201                          decltype(detail::test_implicitly_convertible<From, To>(
202                              0))::value) ||
203                             (is_void<From>::value && is_void<To>::value)> {};
204 
205 template <class From, class To>
206 inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
207 
208 template <class...>
209 using void_t = void;
210 
211 template <class, class T, class... Args>
212 struct is_constructible_ : false_type {};
213 
214 template <class T, class... Args>
215 struct is_constructible_<void_t<decltype(T(declval<Args>()...))>, T, Args...>
216     : true_type {};
217 
218 template <class T, class... Args>
219 using is_constructible = is_constructible_<void_t<>, T, Args...>;
220 
221 template <class T, class... Args>
222 inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
223 
224 template <class _Tp>
225 struct __uncvref {
226   typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type;
227 };
228 
229 template <class _Tp>
230 using __uncvref_t = typename __uncvref<_Tp>::type;
231 
232 template <bool _Val>
233 using _BoolConstant = integral_constant<bool, _Val>;
234 
235 template <class _Tp, class _Up>
236 using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>;
237 
238 template <class _Tp, class _Up>
239 using _IsNotSame = _BoolConstant<!__is_same(_Tp, _Up)>;
240 
241 template <bool>
242 struct _MetaBase;
243 template <>
244 struct _MetaBase<true> {
245   template <class _Tp, class _Up>
246   using _SelectImpl = _Tp;
247   template <template <class...> class _FirstFn, template <class...> class,
248             class... _Args>
249   using _SelectApplyImpl = _FirstFn<_Args...>;
250   template <class _First, class...>
251   using _FirstImpl = _First;
252   template <class, class _Second, class...>
253   using _SecondImpl = _Second;
254   template <class _Result, class _First, class... _Rest>
255   using _OrImpl =
256       typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>::
257           template _OrImpl<_First, _Rest...>;
258 };
259 
260 template <>
261 struct _MetaBase<false> {
262   template <class _Tp, class _Up>
263   using _SelectImpl = _Up;
264   template <template <class...> class, template <class...> class _SecondFn,
265             class... _Args>
266   using _SelectApplyImpl = _SecondFn<_Args...>;
267   template <class _Result, class...>
268   using _OrImpl = _Result;
269 };
270 
271 template <bool _Cond, class _IfRes, class _ElseRes>
272 using _If = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;
273 
274 template <class... _Rest>
275 using _Or = typename _MetaBase<sizeof...(_Rest) !=
276                                0>::template _OrImpl<false_type, _Rest...>;
277 
278 template <bool _Bp, class _Tp = void>
279 using __enable_if_t = typename enable_if<_Bp, _Tp>::type;
280 
281 template <class...>
282 using __expand_to_true = true_type;
283 template <class... _Pred>
284 __expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int);
285 template <class...>
286 false_type __and_helper(...);
287 template <class... _Pred>
288 using _And = decltype(__and_helper<_Pred...>(0));
289 
290 struct __check_tuple_constructor_fail {
291   static constexpr bool __enable_explicit_default() { return false; }
292   static constexpr bool __enable_implicit_default() { return false; }
293   template <class...>
294   static constexpr bool __enable_explicit() {
295     return false;
296   }
297   template <class...>
298   static constexpr bool __enable_implicit() {
299     return false;
300   }
301 };
302 
303 } // namespace std
304 
305 #endif // STD_TYPE_TRAITS_H
306 )";
307 
308 static constexpr char AbslTypeTraitsHeader[] = R"(
309 #ifndef ABSL_TYPE_TRAITS_H
310 #define ABSL_TYPE_TRAITS_H
311 
312 #include "std_type_traits.h"
313 
314 namespace absl {
315 
316 template <typename... Ts>
317 struct conjunction : std::true_type {};
318 
319 template <typename T, typename... Ts>
320 struct conjunction<T, Ts...>
321     : std::conditional<T::value, conjunction<Ts...>, T>::type {};
322 
323 template <typename T>
324 struct conjunction<T> : T {};
325 
326 template <typename T>
327 struct negation : std::integral_constant<bool, !T::value> {};
328 
329 template <bool B, typename T = void>
330 using enable_if_t = typename std::enable_if<B, T>::type;
331 
332 } // namespace absl
333 
334 #endif // ABSL_TYPE_TRAITS_H
335 )";
336 
337 static constexpr char StdUtilityHeader[] = R"(
338 #ifndef UTILITY_H
339 #define UTILITY_H
340 
341 #include "std_type_traits.h"
342 
343 namespace std {
344 
345 template <typename T>
346 constexpr remove_reference_t<T>&& move(T&& x);
347 
348 } // namespace std
349 
350 #endif // UTILITY_H
351 )";
352 
353 static constexpr char StdInitializerListHeader[] = R"(
354 #ifndef INITIALIZER_LIST_H
355 #define INITIALIZER_LIST_H
356 
357 namespace std {
358 
359 template <typename T>
360 class initializer_list {
361  public:
362   initializer_list() noexcept;
363 };
364 
365 } // namespace std
366 
367 #endif // INITIALIZER_LIST_H
368 )";
369 
370 static constexpr char StdOptionalHeader[] = R"(
371 #include "std_initializer_list.h"
372 #include "std_type_traits.h"
373 #include "std_utility.h"
374 
375 namespace std {
376 
377 struct in_place_t {};
378 constexpr in_place_t in_place;
379 
380 struct nullopt_t {
381   constexpr explicit nullopt_t() {}
382 };
383 constexpr nullopt_t nullopt;
384 
385 template <class _Tp>
386 struct __optional_destruct_base {
387   constexpr void reset() noexcept;
388 };
389 
390 template <class _Tp>
391 struct __optional_storage_base : __optional_destruct_base<_Tp> {
392   constexpr bool has_value() const noexcept;
393 };
394 
395 template <typename _Tp>
396 class optional : private __optional_storage_base<_Tp> {
397   using __base = __optional_storage_base<_Tp>;
398 
399  public:
400   using value_type = _Tp;
401 
402  private:
403   struct _CheckOptionalArgsConstructor {
404     template <class _Up>
405     static constexpr bool __enable_implicit() {
406       return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
407     }
408 
409     template <class _Up>
410     static constexpr bool __enable_explicit() {
411       return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
412     }
413   };
414   template <class _Up>
415   using _CheckOptionalArgsCtor =
416       _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value &&
417               _IsNotSame<__uncvref_t<_Up>, optional>::value,
418           _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>;
419   template <class _QualUp>
420   struct _CheckOptionalLikeConstructor {
421     template <class _Up, class _Opt = optional<_Up>>
422     using __check_constructible_from_opt =
423         _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>,
424             is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>,
425             is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>,
426             is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>;
427     template <class _Up, class _QUp = _QualUp>
428     static constexpr bool __enable_implicit() {
429       return is_convertible<_QUp, _Tp>::value &&
430              !__check_constructible_from_opt<_Up>::value;
431     }
432     template <class _Up, class _QUp = _QualUp>
433     static constexpr bool __enable_explicit() {
434       return !is_convertible<_QUp, _Tp>::value &&
435              !__check_constructible_from_opt<_Up>::value;
436     }
437   };
438 
439   template <class _Up, class _QualUp>
440   using _CheckOptionalLikeCtor =
441       _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value,
442           _CheckOptionalLikeConstructor<_QualUp>,
443           __check_tuple_constructor_fail>;
444 
445  public:
446   constexpr optional() noexcept {}
447   constexpr optional(const optional&) = default;
448   constexpr optional(optional&&) = default;
449   constexpr optional(nullopt_t) noexcept {}
450 
451   template <
452       class _InPlaceT, class... _Args,
453       class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>,
454                              is_constructible<value_type, _Args...>>::value>>
455   constexpr explicit optional(_InPlaceT, _Args&&... __args);
456 
457   template <class _Up, class... _Args,
458             class = enable_if_t<is_constructible_v<
459                 value_type, initializer_list<_Up>&, _Args...>>>
460   constexpr explicit optional(in_place_t, initializer_list<_Up> __il,
461                               _Args&&... __args);
462 
463   template <
464       class _Up = value_type,
465       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(),
466                 int> = 0>
467   constexpr optional(_Up&& __v);
468 
469   template <
470       class _Up,
471       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(),
472                 int> = 0>
473   constexpr explicit optional(_Up&& __v);
474 
475   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
476                                      template __enable_implicit<_Up>(),
477                                  int> = 0>
478   constexpr optional(const optional<_Up>& __v);
479 
480   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
481                                      template __enable_explicit<_Up>(),
482                                  int> = 0>
483   constexpr explicit optional(const optional<_Up>& __v);
484 
485   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
486                                      template __enable_implicit<_Up>(),
487                                  int> = 0>
488   constexpr optional(optional<_Up>&& __v);
489 
490   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
491                                      template __enable_explicit<_Up>(),
492                                  int> = 0>
493   constexpr explicit optional(optional<_Up>&& __v);
494 
495   const _Tp& operator*() const&;
496   _Tp& operator*() &;
497   const _Tp&& operator*() const&&;
498   _Tp&& operator*() &&;
499 
500   const _Tp* operator->() const;
501   _Tp* operator->();
502 
503   const _Tp& value() const&;
504   _Tp& value() &;
505   const _Tp&& value() const&&;
506   _Tp&& value() &&;
507 
508   template <typename U>
509   constexpr _Tp value_or(U&& v) const&;
510   template <typename U>
511   _Tp value_or(U&& v) &&;
512 
513   template <typename... Args>
514   _Tp& emplace(Args&&... args);
515 
516   template <typename U, typename... Args>
517   _Tp& emplace(std::initializer_list<U> ilist, Args&&... args);
518 
519   using __base::reset;
520 
521   constexpr explicit operator bool() const noexcept;
522   using __base::has_value;
523 };
524 
525 template <typename T>
526 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
527 
528 template <typename T, typename... Args>
529 constexpr optional<T> make_optional(Args&&... args);
530 
531 template <typename T, typename U, typename... Args>
532 constexpr optional<T> make_optional(std::initializer_list<U> il,
533                                     Args&&... args);
534 
535 } // namespace std
536 )";
537 
538 static constexpr char AbslOptionalHeader[] = R"(
539 #include "absl_type_traits.h"
540 #include "std_initializer_list.h"
541 #include "std_type_traits.h"
542 #include "std_utility.h"
543 
544 namespace absl {
545 
546 struct nullopt_t {
547   constexpr explicit nullopt_t() {}
548 };
549 constexpr nullopt_t nullopt;
550 
551 struct in_place_t {};
552 constexpr in_place_t in_place;
553 
554 template <typename T>
555 class optional;
556 
557 namespace optional_internal {
558 
559 // Whether T is constructible or convertible from optional<U>.
560 template <typename T, typename U>
561 struct is_constructible_convertible_from_optional
562     : std::integral_constant<
563           bool, std::is_constructible<T, optional<U>&>::value ||
564                     std::is_constructible<T, optional<U>&&>::value ||
565                     std::is_constructible<T, const optional<U>&>::value ||
566                     std::is_constructible<T, const optional<U>&&>::value ||
567                     std::is_convertible<optional<U>&, T>::value ||
568                     std::is_convertible<optional<U>&&, T>::value ||
569                     std::is_convertible<const optional<U>&, T>::value ||
570                     std::is_convertible<const optional<U>&&, T>::value> {};
571 
572 }  // namespace optional_internal
573 
574 template <typename T>
575 class optional {
576  public:
577   constexpr optional() noexcept;
578 
579   constexpr optional(nullopt_t) noexcept;
580 
581   optional(const optional&) = default;
582 
583   optional(optional&&) = default;
584 
585   template <typename InPlaceT, typename... Args,
586             absl::enable_if_t<absl::conjunction<
587                 std::is_same<InPlaceT, in_place_t>,
588                 std::is_constructible<T, Args&&...>>::value>* = nullptr>
589   constexpr explicit optional(InPlaceT, Args&&... args);
590 
591   template <typename U, typename... Args,
592             typename = typename std::enable_if<std::is_constructible<
593                 T, std::initializer_list<U>&, Args&&...>::value>::type>
594   constexpr explicit optional(in_place_t, std::initializer_list<U> il,
595                               Args&&... args);
596 
597   template <
598       typename U = T,
599       typename std::enable_if<
600           absl::conjunction<absl::negation<std::is_same<
601                                 in_place_t, typename std::decay<U>::type>>,
602                             absl::negation<std::is_same<
603                                 optional<T>, typename std::decay<U>::type>>,
604                             std::is_convertible<U&&, T>,
605                             std::is_constructible<T, U&&>>::value,
606           bool>::type = false>
607   constexpr optional(U&& v);
608 
609   template <
610       typename U = T,
611       typename std::enable_if<
612           absl::conjunction<absl::negation<std::is_same<
613                                 in_place_t, typename std::decay<U>::type>>,
614                             absl::negation<std::is_same<
615                                 optional<T>, typename std::decay<U>::type>>,
616                             absl::negation<std::is_convertible<U&&, T>>,
617                             std::is_constructible<T, U&&>>::value,
618           bool>::type = false>
619   explicit constexpr optional(U&& v);
620 
621   template <typename U,
622             typename std::enable_if<
623                 absl::conjunction<
624                     absl::negation<std::is_same<T, U>>,
625                     std::is_constructible<T, const U&>,
626                     absl::negation<
627                         optional_internal::
628                             is_constructible_convertible_from_optional<T, U>>,
629                     std::is_convertible<const U&, T>>::value,
630                 bool>::type = false>
631   optional(const optional<U>& rhs);
632 
633   template <typename U,
634             typename std::enable_if<
635                 absl::conjunction<
636                     absl::negation<std::is_same<T, U>>,
637                     std::is_constructible<T, const U&>,
638                     absl::negation<
639                         optional_internal::
640                             is_constructible_convertible_from_optional<T, U>>,
641                     absl::negation<std::is_convertible<const U&, T>>>::value,
642                 bool>::type = false>
643   explicit optional(const optional<U>& rhs);
644 
645   template <
646       typename U,
647       typename std::enable_if<
648           absl::conjunction<
649               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
650               absl::negation<
651                   optional_internal::is_constructible_convertible_from_optional<
652                       T, U>>,
653               std::is_convertible<U&&, T>>::value,
654           bool>::type = false>
655   optional(optional<U>&& rhs);
656 
657   template <
658       typename U,
659       typename std::enable_if<
660           absl::conjunction<
661               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
662               absl::negation<
663                   optional_internal::is_constructible_convertible_from_optional<
664                       T, U>>,
665               absl::negation<std::is_convertible<U&&, T>>>::value,
666           bool>::type = false>
667   explicit optional(optional<U>&& rhs);
668 
669   const T& operator*() const&;
670   T& operator*() &;
671   const T&& operator*() const&&;
672   T&& operator*() &&;
673 
674   const T* operator->() const;
675   T* operator->();
676 
677   const T& value() const&;
678   T& value() &;
679   const T&& value() const&&;
680   T&& value() &&;
681 
682   template <typename U>
683   constexpr T value_or(U&& v) const&;
684   template <typename U>
685   T value_or(U&& v) &&;
686 
687   template <typename... Args>
688   T& emplace(Args&&... args);
689 
690   template <typename U, typename... Args>
691   T& emplace(std::initializer_list<U> ilist, Args&&... args);
692 
693   void reset() noexcept;
694 
695   constexpr explicit operator bool() const noexcept;
696   constexpr bool has_value() const noexcept;
697 };
698 
699 template <typename T>
700 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
701 
702 template <typename T, typename... Args>
703 constexpr optional<T> make_optional(Args&&... args);
704 
705 template <typename T, typename U, typename... Args>
706 constexpr optional<T> make_optional(std::initializer_list<U> il,
707                                     Args&&... args);
708 
709 } // namespace absl
710 )";
711 
712 static constexpr char BaseOptionalHeader[] = R"(
713 #include "std_initializer_list.h"
714 #include "std_type_traits.h"
715 #include "std_utility.h"
716 
717 namespace base {
718 
719 struct in_place_t {};
720 constexpr in_place_t in_place;
721 
722 struct nullopt_t {
723   constexpr explicit nullopt_t() {}
724 };
725 constexpr nullopt_t nullopt;
726 
727 template <typename T>
728 class Optional;
729 
730 namespace internal {
731 
732 template <typename T>
733 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
734 
735 template <typename T, typename U>
736 struct IsConvertibleFromOptional
737     : std::integral_constant<
738           bool, std::is_constructible<T, Optional<U>&>::value ||
739                     std::is_constructible<T, const Optional<U>&>::value ||
740                     std::is_constructible<T, Optional<U>&&>::value ||
741                     std::is_constructible<T, const Optional<U>&&>::value ||
742                     std::is_convertible<Optional<U>&, T>::value ||
743                     std::is_convertible<const Optional<U>&, T>::value ||
744                     std::is_convertible<Optional<U>&&, T>::value ||
745                     std::is_convertible<const Optional<U>&&, T>::value> {};
746 
747 }  // namespace internal
748 
749 template <typename T>
750 class Optional {
751  public:
752   using value_type = T;
753 
754   constexpr Optional() = default;
755   constexpr Optional(const Optional& other) noexcept = default;
756   constexpr Optional(Optional&& other) noexcept = default;
757 
758   constexpr Optional(nullopt_t);
759 
760   template <typename U,
761             typename std::enable_if<
762                 std::is_constructible<T, const U&>::value &&
763                     !internal::IsConvertibleFromOptional<T, U>::value &&
764                     std::is_convertible<const U&, T>::value,
765                 bool>::type = false>
766   Optional(const Optional<U>& other) noexcept;
767 
768   template <typename U,
769             typename std::enable_if<
770                 std::is_constructible<T, const U&>::value &&
771                     !internal::IsConvertibleFromOptional<T, U>::value &&
772                     !std::is_convertible<const U&, T>::value,
773                 bool>::type = false>
774   explicit Optional(const Optional<U>& other) noexcept;
775 
776   template <typename U,
777             typename std::enable_if<
778                 std::is_constructible<T, U&&>::value &&
779                     !internal::IsConvertibleFromOptional<T, U>::value &&
780                     std::is_convertible<U&&, T>::value,
781                 bool>::type = false>
782   Optional(Optional<U>&& other) noexcept;
783 
784   template <typename U,
785             typename std::enable_if<
786                 std::is_constructible<T, U&&>::value &&
787                     !internal::IsConvertibleFromOptional<T, U>::value &&
788                     !std::is_convertible<U&&, T>::value,
789                 bool>::type = false>
790   explicit Optional(Optional<U>&& other) noexcept;
791 
792   template <class... Args>
793   constexpr explicit Optional(in_place_t, Args&&... args);
794 
795   template <class U, class... Args,
796             class = typename std::enable_if<std::is_constructible<
797                 value_type, std::initializer_list<U>&, Args...>::value>::type>
798   constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
799                               Args&&... args);
800 
801   template <
802       typename U = value_type,
803       typename std::enable_if<
804           std::is_constructible<T, U&&>::value &&
805               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
806               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
807               std::is_convertible<U&&, T>::value,
808           bool>::type = false>
809   constexpr Optional(U&& value);
810 
811   template <
812       typename U = value_type,
813       typename std::enable_if<
814           std::is_constructible<T, U&&>::value &&
815               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
816               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
817               !std::is_convertible<U&&, T>::value,
818           bool>::type = false>
819   constexpr explicit Optional(U&& value);
820 
821   const T& operator*() const&;
822   T& operator*() &;
823   const T&& operator*() const&&;
824   T&& operator*() &&;
825 
826   const T* operator->() const;
827   T* operator->();
828 
829   const T& value() const&;
830   T& value() &;
831   const T&& value() const&&;
832   T&& value() &&;
833 
834   template <typename U>
835   constexpr T value_or(U&& v) const&;
836   template <typename U>
837   T value_or(U&& v) &&;
838 
839   template <typename... Args>
840   T& emplace(Args&&... args);
841 
842   template <typename U, typename... Args>
843   T& emplace(std::initializer_list<U> ilist, Args&&... args);
844 
845   void reset() noexcept;
846 
847   constexpr explicit operator bool() const noexcept;
848   constexpr bool has_value() const noexcept;
849 };
850 
851 template <typename T>
852 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v);
853 
854 template <typename T, typename... Args>
855 constexpr Optional<T> make_optional(Args&&... args);
856 
857 template <typename T, typename U, typename... Args>
858 constexpr Optional<T> make_optional(std::initializer_list<U> il,
859                                     Args&&... args);
860 
861 } // namespace base
862 )";
863 
864 /// Converts `L` to string.
865 static std::string ConvertToString(const SourceLocationsLattice &L,
866                                    const ASTContext &Ctx) {
867   return L.getSourceLocations().empty() ? "safe"
868                                         : "unsafe: " + DebugString(L, Ctx);
869 }
870 
871 /// Replaces all occurrences of `Pattern` in `S` with `Replacement`.
872 static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern,
873                                   const std::string &Replacement) {
874   size_t Pos = 0;
875   while (true) {
876     Pos = S.find(Pattern, Pos);
877     if (Pos == std::string::npos)
878       break;
879     S.replace(Pos, Pattern.size(), Replacement);
880   }
881 }
882 
883 struct OptionalTypeIdentifier {
884   std::string NamespaceName;
885   std::string TypeName;
886 };
887 
888 class UncheckedOptionalAccessTest
889     : public ::testing::TestWithParam<OptionalTypeIdentifier> {
890 protected:
891   template <typename LatticeChecksMatcher>
892   void ExpectLatticeChecksFor(std::string SourceCode,
893                               LatticeChecksMatcher MatchesLatticeChecks) {
894     ExpectLatticeChecksFor(SourceCode, ast_matchers::hasName("target"),
895                            MatchesLatticeChecks);
896   }
897 
898 private:
899   template <typename FuncDeclMatcher, typename LatticeChecksMatcher>
900   void ExpectLatticeChecksFor(std::string SourceCode,
901                               FuncDeclMatcher FuncMatcher,
902                               LatticeChecksMatcher MatchesLatticeChecks) {
903     ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName);
904     ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName);
905 
906     std::vector<std::pair<std::string, std::string>> Headers;
907     Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader);
908     Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader);
909     Headers.emplace_back("std_utility.h", StdUtilityHeader);
910     Headers.emplace_back("std_optional.h", StdOptionalHeader);
911     Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader);
912     Headers.emplace_back("absl_optional.h", AbslOptionalHeader);
913     Headers.emplace_back("base_optional.h", BaseOptionalHeader);
914     Headers.emplace_back("unchecked_optional_access_test.h", R"(
915       #include "absl_optional.h"
916       #include "base_optional.h"
917       #include "std_initializer_list.h"
918       #include "std_optional.h"
919       #include "std_utility.h"
920 
921       template <typename T>
922       T Make();
923     )");
924     const tooling::FileContentMappings FileContents(Headers.begin(),
925                                                     Headers.end());
926     llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
927         SourceCode, FuncMatcher,
928         [](ASTContext &Ctx, Environment &) {
929           return UncheckedOptionalAccessModel(Ctx);
930         },
931         [&MatchesLatticeChecks](
932             llvm::ArrayRef<std::pair<
933                 std::string, DataflowAnalysisState<SourceLocationsLattice>>>
934                 CheckToLatticeMap,
935             ASTContext &Ctx) {
936           // FIXME: Consider using a matcher instead of translating
937           // `CheckToLatticeMap` to `CheckToStringifiedLatticeMap`.
938           std::vector<std::pair<std::string, std::string>>
939               CheckToStringifiedLatticeMap;
940           for (const auto &E : CheckToLatticeMap) {
941             CheckToStringifiedLatticeMap.emplace_back(
942                 E.first, ConvertToString(E.second.Lattice, Ctx));
943           }
944           EXPECT_THAT(CheckToStringifiedLatticeMap, MatchesLatticeChecks);
945         },
946         {"-fsyntax-only", "-std=c++17", "-Wno-undefined-inline"}, FileContents);
947     if (Error)
948       FAIL() << llvm::toString(std::move(Error));
949   }
950 };
951 
952 INSTANTIATE_TEST_SUITE_P(
953     UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
954     ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
955                       OptionalTypeIdentifier{"absl", "optional"},
956                       OptionalTypeIdentifier{"base", "Optional"}),
957     [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
958       return Info.param.NamespaceName;
959     });
960 
961 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
962   ExpectLatticeChecksFor(R"(
963     void target() {
964       (void)0;
965       /*[[check]]*/
966     }
967   )",
968                          UnorderedElementsAre(Pair("check", "safe")));
969 }
970 
971 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
972   ExpectLatticeChecksFor(
973       R"(
974     #include "unchecked_optional_access_test.h"
975 
976     void target($ns::$optional<int> opt) {
977       opt.value();
978       /*[[check]]*/
979     }
980   )",
981       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
982 
983   ExpectLatticeChecksFor(
984       R"(
985     #include "unchecked_optional_access_test.h"
986 
987     void target($ns::$optional<int> opt) {
988       std::move(opt).value();
989       /*[[check]]*/
990     }
991   )",
992       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
993 }
994 
995 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
996   ExpectLatticeChecksFor(
997       R"(
998     #include "unchecked_optional_access_test.h"
999 
1000     void target($ns::$optional<int> opt) {
1001       *opt;
1002       /*[[check]]*/
1003     }
1004   )",
1005       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8")));
1006 
1007   ExpectLatticeChecksFor(
1008       R"(
1009     #include "unchecked_optional_access_test.h"
1010 
1011     void target($ns::$optional<int> opt) {
1012       *std::move(opt);
1013       /*[[check]]*/
1014     }
1015   )",
1016       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8")));
1017 }
1018 
1019 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
1020   ExpectLatticeChecksFor(
1021       R"(
1022     #include "unchecked_optional_access_test.h"
1023 
1024     struct Foo {
1025       void foo();
1026     };
1027 
1028     void target($ns::$optional<Foo> opt) {
1029       opt->foo();
1030       /*[[check]]*/
1031     }
1032   )",
1033       UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7")));
1034 
1035   ExpectLatticeChecksFor(
1036       R"(
1037     #include "unchecked_optional_access_test.h"
1038 
1039     struct Foo {
1040       void foo();
1041     };
1042 
1043     void target($ns::$optional<Foo> opt) {
1044       std::move(opt)->foo();
1045       /*[[check]]*/
1046     }
1047   )",
1048       UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7")));
1049 }
1050 
1051 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
1052   ExpectLatticeChecksFor(R"(
1053     #include "unchecked_optional_access_test.h"
1054 
1055     void target($ns::$optional<int> opt) {
1056       if (opt.has_value()) {
1057         opt.value();
1058         /*[[check]]*/
1059       }
1060     }
1061   )",
1062                          UnorderedElementsAre(Pair("check", "safe")));
1063 }
1064 
1065 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
1066   ExpectLatticeChecksFor(R"(
1067     #include "unchecked_optional_access_test.h"
1068 
1069     void target($ns::$optional<int> opt) {
1070       if (opt) {
1071         opt.value();
1072         /*[[check]]*/
1073       }
1074     }
1075   )",
1076                          UnorderedElementsAre(Pair("check", "safe")));
1077 }
1078 
1079 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
1080   ExpectLatticeChecksFor(
1081       R"(
1082     #include "unchecked_optional_access_test.h"
1083 
1084     void target() {
1085       Make<$ns::$optional<int>>().value();
1086       (void)0;
1087       /*[[check]]*/
1088     }
1089   )",
1090       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1091 
1092   ExpectLatticeChecksFor(
1093       R"(
1094     #include "unchecked_optional_access_test.h"
1095 
1096     void target($ns::$optional<int> opt) {
1097       std::move(opt).value();
1098       /*[[check]]*/
1099     }
1100   )",
1101       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1102 }
1103 
1104 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
1105   ExpectLatticeChecksFor(
1106       R"(
1107     #include "unchecked_optional_access_test.h"
1108 
1109     void target() {
1110       $ns::$optional<int> opt;
1111       opt.value();
1112       /*[[check]]*/
1113     }
1114   )",
1115       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1116 }
1117 
1118 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
1119   ExpectLatticeChecksFor(
1120       R"(
1121     #include "unchecked_optional_access_test.h"
1122 
1123     void target() {
1124       $ns::$optional<int> opt($ns::nullopt);
1125       opt.value();
1126       /*[[check]]*/
1127     }
1128   )",
1129       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1130 }
1131 
1132 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
1133   ExpectLatticeChecksFor(R"(
1134     #include "unchecked_optional_access_test.h"
1135 
1136     void target() {
1137       $ns::$optional<int> opt($ns::in_place, 3);
1138       opt.value();
1139       /*[[check]]*/
1140     }
1141   )",
1142                          UnorderedElementsAre(Pair("check", "safe")));
1143 
1144   ExpectLatticeChecksFor(R"(
1145     #include "unchecked_optional_access_test.h"
1146 
1147     struct Foo {};
1148 
1149     void target() {
1150       $ns::$optional<Foo> opt($ns::in_place);
1151       opt.value();
1152       /*[[check]]*/
1153     }
1154   )",
1155                          UnorderedElementsAre(Pair("check", "safe")));
1156 
1157   ExpectLatticeChecksFor(R"(
1158     #include "unchecked_optional_access_test.h"
1159 
1160     struct Foo {
1161       explicit Foo(int, bool);
1162     };
1163 
1164     void target() {
1165       $ns::$optional<Foo> opt($ns::in_place, 3, false);
1166       opt.value();
1167       /*[[check]]*/
1168     }
1169   )",
1170                          UnorderedElementsAre(Pair("check", "safe")));
1171 
1172   ExpectLatticeChecksFor(R"(
1173     #include "unchecked_optional_access_test.h"
1174 
1175     struct Foo {
1176       explicit Foo(std::initializer_list<int>);
1177     };
1178 
1179     void target() {
1180       $ns::$optional<Foo> opt($ns::in_place, {3});
1181       opt.value();
1182       /*[[check]]*/
1183     }
1184   )",
1185                          UnorderedElementsAre(Pair("check", "safe")));
1186 }
1187 
1188 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
1189   ExpectLatticeChecksFor(R"(
1190     #include "unchecked_optional_access_test.h"
1191 
1192     void target() {
1193       $ns::$optional<int> opt(21);
1194       opt.value();
1195       /*[[check]]*/
1196     }
1197   )",
1198                          UnorderedElementsAre(Pair("check", "safe")));
1199 
1200   ExpectLatticeChecksFor(R"(
1201     #include "unchecked_optional_access_test.h"
1202 
1203     void target() {
1204       $ns::$optional<int> opt = $ns::$optional<int>(21);
1205       opt.value();
1206       /*[[check]]*/
1207     }
1208   )",
1209                          UnorderedElementsAre(Pair("check", "safe")));
1210   ExpectLatticeChecksFor(R"(
1211     #include "unchecked_optional_access_test.h"
1212 
1213     void target() {
1214       $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1215       opt.value();
1216       /*[[check]]*/
1217     }
1218   )",
1219                          UnorderedElementsAre(Pair("check", "safe")));
1220 
1221   ExpectLatticeChecksFor(R"(
1222     #include "unchecked_optional_access_test.h"
1223 
1224     struct MyString {
1225       MyString(const char*);
1226     };
1227 
1228     void target() {
1229       $ns::$optional<MyString> opt("foo");
1230       opt.value();
1231       /*[[check]]*/
1232     }
1233   )",
1234                          UnorderedElementsAre(Pair("check", "safe")));
1235 
1236   ExpectLatticeChecksFor(R"(
1237     #include "unchecked_optional_access_test.h"
1238 
1239     struct Foo {};
1240 
1241     struct Bar {
1242       Bar(const Foo&);
1243     };
1244 
1245     void target() {
1246       $ns::$optional<Bar> opt(Make<Foo>());
1247       opt.value();
1248       /*[[check]]*/
1249     }
1250   )",
1251                          UnorderedElementsAre(Pair("check", "safe")));
1252 
1253   ExpectLatticeChecksFor(R"(
1254     #include "unchecked_optional_access_test.h"
1255 
1256     struct Foo {
1257       explicit Foo(int);
1258     };
1259 
1260     void target() {
1261       $ns::$optional<Foo> opt(3);
1262       opt.value();
1263       /*[[check]]*/
1264     }
1265   )",
1266                          UnorderedElementsAre(Pair("check", "safe")));
1267 }
1268 
1269 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
1270   ExpectLatticeChecksFor(
1271       R"(
1272     #include "unchecked_optional_access_test.h"
1273 
1274     struct Foo {};
1275 
1276     struct Bar {
1277       Bar(const Foo&);
1278     };
1279 
1280     void target() {
1281       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1282       opt.value();
1283       /*[[check]]*/
1284     }
1285   )",
1286       UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7")));
1287 
1288   ExpectLatticeChecksFor(
1289       R"(
1290     #include "unchecked_optional_access_test.h"
1291 
1292     struct Foo {};
1293 
1294     struct Bar {
1295       explicit Bar(const Foo&);
1296     };
1297 
1298     void target() {
1299       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1300       opt.value();
1301       /*[[check]]*/
1302     }
1303   )",
1304       UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7")));
1305 
1306   ExpectLatticeChecksFor(
1307       R"(
1308     #include "unchecked_optional_access_test.h"
1309 
1310     struct Foo {};
1311 
1312     struct Bar {
1313       Bar(const Foo&);
1314     };
1315 
1316     void target() {
1317       $ns::$optional<Foo> opt1 = $ns::nullopt;
1318       $ns::$optional<Bar> opt2(opt1);
1319       opt2.value();
1320       /*[[check]]*/
1321     }
1322   )",
1323       UnorderedElementsAre(Pair("check", "unsafe: input.cc:13:7")));
1324 
1325   ExpectLatticeChecksFor(R"(
1326     #include "unchecked_optional_access_test.h"
1327 
1328     struct Foo {};
1329 
1330     struct Bar {
1331       Bar(const Foo&);
1332     };
1333 
1334     void target() {
1335       $ns::$optional<Foo> opt1(Make<Foo>());
1336       $ns::$optional<Bar> opt2(opt1);
1337       opt2.value();
1338       /*[[check]]*/
1339     }
1340   )",
1341                          UnorderedElementsAre(Pair("check", "safe")));
1342 
1343   ExpectLatticeChecksFor(R"(
1344     #include "unchecked_optional_access_test.h"
1345 
1346     struct Foo {};
1347 
1348     struct Bar {
1349       explicit Bar(const Foo&);
1350     };
1351 
1352     void target() {
1353       $ns::$optional<Foo> opt1(Make<Foo>());
1354       $ns::$optional<Bar> opt2(opt1);
1355       opt2.value();
1356       /*[[check]]*/
1357     }
1358   )",
1359                          UnorderedElementsAre(Pair("check", "safe")));
1360 }
1361 
1362 TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
1363   ExpectLatticeChecksFor(R"(
1364     #include "unchecked_optional_access_test.h"
1365 
1366     void target() {
1367       $ns::$optional<int> opt = $ns::make_optional(0);
1368       opt.value();
1369       /*[[check]]*/
1370     }
1371   )",
1372                          UnorderedElementsAre(Pair("check", "safe")));
1373 
1374   ExpectLatticeChecksFor(R"(
1375     #include "unchecked_optional_access_test.h"
1376 
1377     struct Foo {
1378       Foo(int, int);
1379     };
1380 
1381     void target() {
1382       $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1383       opt.value();
1384       /*[[check]]*/
1385     }
1386   )",
1387                          UnorderedElementsAre(Pair("check", "safe")));
1388 
1389   ExpectLatticeChecksFor(R"(
1390     #include "unchecked_optional_access_test.h"
1391 
1392     struct Foo {
1393       constexpr Foo(std::initializer_list<char>);
1394     };
1395 
1396     void target() {
1397       char a = 'a';
1398       $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1399       opt.value();
1400       /*[[check]]*/
1401     }
1402   )",
1403                          UnorderedElementsAre(Pair("check", "safe")));
1404 }
1405 
1406 TEST_P(UncheckedOptionalAccessTest, ValueOr) {
1407   ExpectLatticeChecksFor(R"(
1408     #include "unchecked_optional_access_test.h"
1409 
1410     void target() {
1411       $ns::$optional<int> opt;
1412       opt.value_or(0);
1413       (void)0;
1414       /*[[check]]*/
1415     }
1416   )",
1417                          UnorderedElementsAre(Pair("check", "safe")));
1418 }
1419 
1420 TEST_P(UncheckedOptionalAccessTest, Emplace) {
1421   ExpectLatticeChecksFor(R"(
1422     #include "unchecked_optional_access_test.h"
1423 
1424     void target() {
1425       $ns::$optional<int> opt;
1426       opt.emplace(0);
1427       opt.value();
1428       /*[[check]]*/
1429     }
1430   )",
1431                          UnorderedElementsAre(Pair("check", "safe")));
1432 
1433   ExpectLatticeChecksFor(R"(
1434     #include "unchecked_optional_access_test.h"
1435 
1436     void target($ns::$optional<int> *opt) {
1437       opt->emplace(0);
1438       opt->value();
1439       /*[[check]]*/
1440     }
1441   )",
1442                          UnorderedElementsAre(Pair("check", "safe")));
1443 
1444   // FIXME: Add tests that call `emplace` in conditional branches.
1445 }
1446 
1447 TEST_P(UncheckedOptionalAccessTest, Reset) {
1448   ExpectLatticeChecksFor(
1449       R"(
1450     #include "unchecked_optional_access_test.h"
1451 
1452     void target() {
1453       $ns::$optional<int> opt = $ns::make_optional(0);
1454       opt.reset();
1455       opt.value();
1456       /*[[check]]*/
1457     }
1458   )",
1459       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7")));
1460 
1461   ExpectLatticeChecksFor(
1462       R"(
1463     #include "unchecked_optional_access_test.h"
1464 
1465     void target($ns::$optional<int> &opt) {
1466       if (opt.has_value()) {
1467         opt.reset();
1468         opt.value();
1469         /*[[check]]*/
1470       }
1471     }
1472   )",
1473       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:9")));
1474 
1475   // FIXME: Add tests that call `reset` in conditional branches.
1476 }
1477 
1478 // FIXME: Add support for:
1479 // - constructors (copy, move)
1480 // - assignment operators (default, copy, move, non-standard)
1481 // - swap
1482 // - invalidation (passing optional by non-const reference/pointer)
1483 // - `value_or(nullptr) != nullptr`, `value_or(0) != 0`, `value_or("").empty()`
1484 // - nested `optional` values
1485