xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (revision 65e710c3fc036706ec20b357a1bfce9cbadf5705)
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 CSDtdDefHeader[] = R"(
34 #ifndef CSTDDEF_H
35 #define CSTDDEF_H
36 
37 namespace std {
38 
39 typedef decltype(sizeof(char)) size_t;
40 
41 using nullptr_t = decltype(nullptr);
42 
43 } // namespace std
44 
45 #endif // CSTDDEF_H
46 )";
47 
48 static constexpr char StdTypeTraitsHeader[] = R"(
49 #ifndef STD_TYPE_TRAITS_H
50 #define STD_TYPE_TRAITS_H
51 
52 #include "cstddef.h"
53 
54 namespace std {
55 
56 template <typename T, T V>
57 struct integral_constant {
58   static constexpr T value = V;
59 };
60 
61 using true_type = integral_constant<bool, true>;
62 using false_type = integral_constant<bool, false>;
63 
64 template< class T > struct remove_reference      {typedef T type;};
65 template< class T > struct remove_reference<T&>  {typedef T type;};
66 template< class T > struct remove_reference<T&&> {typedef T type;};
67 
68 template <class T>
69   using remove_reference_t = typename remove_reference<T>::type;
70 
71 template <class T>
72 struct remove_extent {
73   typedef T type;
74 };
75 
76 template <class T>
77 struct remove_extent<T[]> {
78   typedef T type;
79 };
80 
81 template <class T, size_t N>
82 struct remove_extent<T[N]> {
83   typedef T type;
84 };
85 
86 template <class T>
87 struct is_array : false_type {};
88 
89 template <class T>
90 struct is_array<T[]> : true_type {};
91 
92 template <class T, size_t N>
93 struct is_array<T[N]> : true_type {};
94 
95 template <class>
96 struct is_function : false_type {};
97 
98 template <class Ret, class... Args>
99 struct is_function<Ret(Args...)> : true_type {};
100 
101 namespace detail {
102 
103 template <class T>
104 struct type_identity {
105   using type = T;
106 };  // or use type_identity (since C++20)
107 
108 template <class T>
109 auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>;
110 template <class T>
111 auto try_add_pointer(...) -> type_identity<T>;
112 
113 }  // namespace detail
114 
115 template <class T>
116 struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
117 
118 template <bool B, class T, class F>
119 struct conditional {
120   typedef T type;
121 };
122 
123 template <class T, class F>
124 struct conditional<false, T, F> {
125   typedef F type;
126 };
127 
128 template <class T>
129 struct remove_cv {
130   typedef T type;
131 };
132 template <class T>
133 struct remove_cv<const T> {
134   typedef T type;
135 };
136 template <class T>
137 struct remove_cv<volatile T> {
138   typedef T type;
139 };
140 template <class T>
141 struct remove_cv<const volatile T> {
142   typedef T type;
143 };
144 
145 template <class T>
146 using remove_cv_t = typename remove_cv<T>::type;
147 
148 template <class T>
149 struct decay {
150  private:
151   typedef typename remove_reference<T>::type U;
152 
153  public:
154   typedef typename conditional<
155       is_array<U>::value, typename remove_extent<U>::type*,
156       typename conditional<is_function<U>::value, typename add_pointer<U>::type,
157                            typename remove_cv<U>::type>::type>::type type;
158 };
159 
160 template <bool B, class T = void>
161 struct enable_if {};
162 
163 template <class T>
164 struct enable_if<true, T> {
165   typedef T type;
166 };
167 
168 template <bool B, class T = void>
169 using enable_if_t = typename enable_if<B, T>::type;
170 
171 template <class T, class U>
172 struct is_same : false_type {};
173 
174 template <class T>
175 struct is_same<T, T> : true_type {};
176 
177 template <class T>
178 struct is_void : is_same<void, typename remove_cv<T>::type> {};
179 
180 namespace detail {
181 
182 template <class T>
183 auto try_add_rvalue_reference(int) -> type_identity<T&&>;
184 template <class T>
185 auto try_add_rvalue_reference(...) -> type_identity<T>;
186 
187 }  // namespace detail
188 
189 template <class T>
190 struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {
191 };
192 
193 template <class T>
194 typename add_rvalue_reference<T>::type declval() noexcept;
195 
196 namespace detail {
197 
198 template <class T>
199 auto test_returnable(int)
200     -> decltype(void(static_cast<T (*)()>(nullptr)), true_type{});
201 template <class>
202 auto test_returnable(...) -> false_type;
203 
204 template <class From, class To>
205 auto test_implicitly_convertible(int)
206     -> decltype(void(declval<void (&)(To)>()(declval<From>())), true_type{});
207 template <class, class>
208 auto test_implicitly_convertible(...) -> false_type;
209 
210 }  // namespace detail
211 
212 template <class From, class To>
213 struct is_convertible
214     : integral_constant<bool,
215                         (decltype(detail::test_returnable<To>(0))::value &&
216                          decltype(detail::test_implicitly_convertible<From, To>(
217                              0))::value) ||
218                             (is_void<From>::value && is_void<To>::value)> {};
219 
220 template <class From, class To>
221 inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
222 
223 template <class...>
224 using void_t = void;
225 
226 template <class, class T, class... Args>
227 struct is_constructible_ : false_type {};
228 
229 template <class T, class... Args>
230 struct is_constructible_<void_t<decltype(T(declval<Args>()...))>, T, Args...>
231     : true_type {};
232 
233 template <class T, class... Args>
234 using is_constructible = is_constructible_<void_t<>, T, Args...>;
235 
236 template <class T, class... Args>
237 inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
238 
239 template <class _Tp>
240 struct __uncvref {
241   typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type;
242 };
243 
244 template <class _Tp>
245 using __uncvref_t = typename __uncvref<_Tp>::type;
246 
247 template <bool _Val>
248 using _BoolConstant = integral_constant<bool, _Val>;
249 
250 template <class _Tp, class _Up>
251 using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>;
252 
253 template <class _Tp, class _Up>
254 using _IsNotSame = _BoolConstant<!__is_same(_Tp, _Up)>;
255 
256 template <bool>
257 struct _MetaBase;
258 template <>
259 struct _MetaBase<true> {
260   template <class _Tp, class _Up>
261   using _SelectImpl = _Tp;
262   template <template <class...> class _FirstFn, template <class...> class,
263             class... _Args>
264   using _SelectApplyImpl = _FirstFn<_Args...>;
265   template <class _First, class...>
266   using _FirstImpl = _First;
267   template <class, class _Second, class...>
268   using _SecondImpl = _Second;
269   template <class _Result, class _First, class... _Rest>
270   using _OrImpl =
271       typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>::
272           template _OrImpl<_First, _Rest...>;
273 };
274 
275 template <>
276 struct _MetaBase<false> {
277   template <class _Tp, class _Up>
278   using _SelectImpl = _Up;
279   template <template <class...> class, template <class...> class _SecondFn,
280             class... _Args>
281   using _SelectApplyImpl = _SecondFn<_Args...>;
282   template <class _Result, class...>
283   using _OrImpl = _Result;
284 };
285 
286 template <bool _Cond, class _IfRes, class _ElseRes>
287 using _If = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;
288 
289 template <class... _Rest>
290 using _Or = typename _MetaBase<sizeof...(_Rest) !=
291                                0>::template _OrImpl<false_type, _Rest...>;
292 
293 template <bool _Bp, class _Tp = void>
294 using __enable_if_t = typename enable_if<_Bp, _Tp>::type;
295 
296 template <class...>
297 using __expand_to_true = true_type;
298 template <class... _Pred>
299 __expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int);
300 template <class...>
301 false_type __and_helper(...);
302 template <class... _Pred>
303 using _And = decltype(__and_helper<_Pred...>(0));
304 
305 template <class _Pred>
306 struct _Not : _BoolConstant<!_Pred::value> {};
307 
308 struct __check_tuple_constructor_fail {
309   static constexpr bool __enable_explicit_default() { return false; }
310   static constexpr bool __enable_implicit_default() { return false; }
311   template <class...>
312   static constexpr bool __enable_explicit() {
313     return false;
314   }
315   template <class...>
316   static constexpr bool __enable_implicit() {
317     return false;
318   }
319 };
320 
321 template <typename, typename _Tp>
322 struct __select_2nd {
323   typedef _Tp type;
324 };
325 template <class _Tp, class _Arg>
326 typename __select_2nd<decltype((declval<_Tp>() = declval<_Arg>())),
327                       true_type>::type
328 __is_assignable_test(int);
329 template <class, class>
330 false_type __is_assignable_test(...);
331 template <class _Tp, class _Arg,
332           bool = is_void<_Tp>::value || is_void<_Arg>::value>
333 struct __is_assignable_imp
334     : public decltype((__is_assignable_test<_Tp, _Arg>(0))) {};
335 template <class _Tp, class _Arg>
336 struct __is_assignable_imp<_Tp, _Arg, true> : public false_type {};
337 template <class _Tp, class _Arg>
338 struct is_assignable : public __is_assignable_imp<_Tp, _Arg> {};
339 
340 template <class _Tp>
341 struct __libcpp_is_integral : public false_type {};
342 template <>
343 struct __libcpp_is_integral<bool> : public true_type {};
344 template <>
345 struct __libcpp_is_integral<char> : public true_type {};
346 template <>
347 struct __libcpp_is_integral<signed char> : public true_type {};
348 template <>
349 struct __libcpp_is_integral<unsigned char> : public true_type {};
350 template <>
351 struct __libcpp_is_integral<wchar_t> : public true_type {};
352 template <>
353 struct __libcpp_is_integral<short> : public true_type {};  // NOLINT
354 template <>
355 struct __libcpp_is_integral<unsigned short> : public true_type {};  // NOLINT
356 template <>
357 struct __libcpp_is_integral<int> : public true_type {};
358 template <>
359 struct __libcpp_is_integral<unsigned int> : public true_type {};
360 template <>
361 struct __libcpp_is_integral<long> : public true_type {};  // NOLINT
362 template <>
363 struct __libcpp_is_integral<unsigned long> : public true_type {};  // NOLINT
364 template <>
365 struct __libcpp_is_integral<long long> : public true_type {};  // NOLINT
366 template <>                                                    // NOLINTNEXTLINE
367 struct __libcpp_is_integral<unsigned long long> : public true_type {};
368 template <class _Tp>
369 struct is_integral
370     : public __libcpp_is_integral<typename remove_cv<_Tp>::type> {};
371 
372 template <class _Tp>
373 struct __libcpp_is_floating_point : public false_type {};
374 template <>
375 struct __libcpp_is_floating_point<float> : public true_type {};
376 template <>
377 struct __libcpp_is_floating_point<double> : public true_type {};
378 template <>
379 struct __libcpp_is_floating_point<long double> : public true_type {};
380 template <class _Tp>
381 struct is_floating_point
382     : public __libcpp_is_floating_point<typename remove_cv<_Tp>::type> {};
383 
384 template <class _Tp>
385 struct is_arithmetic
386     : public integral_constant<bool, is_integral<_Tp>::value ||
387                                          is_floating_point<_Tp>::value> {};
388 
389 template <class _Tp>
390 struct __libcpp_is_pointer : public false_type {};
391 template <class _Tp>
392 struct __libcpp_is_pointer<_Tp*> : public true_type {};
393 template <class _Tp>
394 struct is_pointer : public __libcpp_is_pointer<typename remove_cv<_Tp>::type> {
395 };
396 
397 template <class _Tp>
398 struct __libcpp_is_member_pointer : public false_type {};
399 template <class _Tp, class _Up>
400 struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type {};
401 template <class _Tp>
402 struct is_member_pointer
403     : public __libcpp_is_member_pointer<typename remove_cv<_Tp>::type> {};
404 
405 template <class _Tp>
406 struct __libcpp_union : public false_type {};
407 template <class _Tp>
408 struct is_union : public __libcpp_union<typename remove_cv<_Tp>::type> {};
409 
410 template <class T>
411 struct is_reference : false_type {};
412 template <class T>
413 struct is_reference<T&> : true_type {};
414 template <class T>
415 struct is_reference<T&&> : true_type {};
416 
417 template <class T>
418 inline constexpr bool is_reference_v = is_reference<T>::value;
419 
420 struct __two {
421   char __lx[2];
422 };
423 
424 namespace __is_class_imp {
425 template <class _Tp>
426 char __test(int _Tp::*);
427 template <class _Tp>
428 __two __test(...);
429 }  // namespace __is_class_imp
430 template <class _Tp>
431 struct is_class
432     : public integral_constant<bool,
433                                sizeof(__is_class_imp::__test<_Tp>(0)) == 1 &&
434                                    !is_union<_Tp>::value> {};
435 
436 template <class _Tp>
437 struct __is_nullptr_t_impl : public false_type {};
438 template <>
439 struct __is_nullptr_t_impl<nullptr_t> : public true_type {};
440 template <class _Tp>
441 struct __is_nullptr_t
442     : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
443 template <class _Tp>
444 struct is_null_pointer
445     : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
446 
447 template <class _Tp>
448 struct is_enum
449     : public integral_constant<
450           bool, !is_void<_Tp>::value && !is_integral<_Tp>::value &&
451                     !is_floating_point<_Tp>::value && !is_array<_Tp>::value &&
452                     !is_pointer<_Tp>::value && !is_reference<_Tp>::value &&
453                     !is_member_pointer<_Tp>::value && !is_union<_Tp>::value &&
454                     !is_class<_Tp>::value && !is_function<_Tp>::value> {};
455 
456 template <class _Tp>
457 struct is_scalar
458     : public integral_constant<
459           bool, is_arithmetic<_Tp>::value || is_member_pointer<_Tp>::value ||
460                     is_pointer<_Tp>::value || __is_nullptr_t<_Tp>::value ||
461                     is_enum<_Tp>::value> {};
462 template <>
463 struct is_scalar<nullptr_t> : public true_type {};
464 
465 } // namespace std
466 
467 #endif // STD_TYPE_TRAITS_H
468 )";
469 
470 static constexpr char AbslTypeTraitsHeader[] = R"(
471 #ifndef ABSL_TYPE_TRAITS_H
472 #define ABSL_TYPE_TRAITS_H
473 
474 #include "std_type_traits.h"
475 
476 namespace absl {
477 
478 template <typename... Ts>
479 struct conjunction : std::true_type {};
480 
481 template <typename T, typename... Ts>
482 struct conjunction<T, Ts...>
483     : std::conditional<T::value, conjunction<Ts...>, T>::type {};
484 
485 template <typename T>
486 struct conjunction<T> : T {};
487 
488 template <typename T>
489 struct negation : std::integral_constant<bool, !T::value> {};
490 
491 template <bool B, typename T = void>
492 using enable_if_t = typename std::enable_if<B, T>::type;
493 
494 } // namespace absl
495 
496 #endif // ABSL_TYPE_TRAITS_H
497 )";
498 
499 static constexpr char StdStringHeader[] = R"(
500 #ifndef STRING_H
501 #define STRING_H
502 
503 namespace std {
504 
505 struct string {
506   string(const char*);
507   ~string();
508   bool empty();
509 };
510 bool operator!=(const string &LHS, const char *RHS);
511 
512 } // namespace std
513 
514 #endif // STRING_H
515 )";
516 
517 static constexpr char StdUtilityHeader[] = R"(
518 #ifndef UTILITY_H
519 #define UTILITY_H
520 
521 #include "std_type_traits.h"
522 
523 namespace std {
524 
525 template <typename T>
526 constexpr remove_reference_t<T>&& move(T&& x);
527 
528 template <typename T>
529 void swap(T& a, T& b) noexcept;
530 
531 } // namespace std
532 
533 #endif // UTILITY_H
534 )";
535 
536 static constexpr char StdInitializerListHeader[] = R"(
537 #ifndef INITIALIZER_LIST_H
538 #define INITIALIZER_LIST_H
539 
540 namespace std {
541 
542 template <typename T>
543 class initializer_list {
544  public:
545   initializer_list() noexcept;
546 };
547 
548 } // namespace std
549 
550 #endif // INITIALIZER_LIST_H
551 )";
552 
553 static constexpr char StdOptionalHeader[] = R"(
554 #include "std_initializer_list.h"
555 #include "std_type_traits.h"
556 #include "std_utility.h"
557 
558 namespace std {
559 
560 struct in_place_t {};
561 constexpr in_place_t in_place;
562 
563 struct nullopt_t {
564   constexpr explicit nullopt_t() {}
565 };
566 constexpr nullopt_t nullopt;
567 
568 template <class _Tp>
569 struct __optional_destruct_base {
570   constexpr void reset() noexcept;
571 };
572 
573 template <class _Tp>
574 struct __optional_storage_base : __optional_destruct_base<_Tp> {
575   constexpr bool has_value() const noexcept;
576 };
577 
578 template <typename _Tp>
579 class optional : private __optional_storage_base<_Tp> {
580   using __base = __optional_storage_base<_Tp>;
581 
582  public:
583   using value_type = _Tp;
584 
585  private:
586   struct _CheckOptionalArgsConstructor {
587     template <class _Up>
588     static constexpr bool __enable_implicit() {
589       return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
590     }
591 
592     template <class _Up>
593     static constexpr bool __enable_explicit() {
594       return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
595     }
596   };
597   template <class _Up>
598   using _CheckOptionalArgsCtor =
599       _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value &&
600               _IsNotSame<__uncvref_t<_Up>, optional>::value,
601           _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>;
602   template <class _QualUp>
603   struct _CheckOptionalLikeConstructor {
604     template <class _Up, class _Opt = optional<_Up>>
605     using __check_constructible_from_opt =
606         _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>,
607             is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>,
608             is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>,
609             is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>;
610     template <class _Up, class _QUp = _QualUp>
611     static constexpr bool __enable_implicit() {
612       return is_convertible<_QUp, _Tp>::value &&
613              !__check_constructible_from_opt<_Up>::value;
614     }
615     template <class _Up, class _QUp = _QualUp>
616     static constexpr bool __enable_explicit() {
617       return !is_convertible<_QUp, _Tp>::value &&
618              !__check_constructible_from_opt<_Up>::value;
619     }
620   };
621 
622   template <class _Up, class _QualUp>
623   using _CheckOptionalLikeCtor =
624       _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value,
625           _CheckOptionalLikeConstructor<_QualUp>,
626           __check_tuple_constructor_fail>;
627 
628 
629   template <class _Up, class _QualUp>
630   using _CheckOptionalLikeAssign = _If<
631       _And<
632           _IsNotSame<_Up, _Tp>,
633           is_constructible<_Tp, _QualUp>,
634           is_assignable<_Tp&, _QualUp>
635       >::value,
636       _CheckOptionalLikeConstructor<_QualUp>,
637       __check_tuple_constructor_fail
638     >;
639 
640  public:
641   constexpr optional() noexcept {}
642   constexpr optional(const optional&) = default;
643   constexpr optional(optional&&) = default;
644   constexpr optional(nullopt_t) noexcept {}
645 
646   template <
647       class _InPlaceT, class... _Args,
648       class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>,
649                              is_constructible<value_type, _Args...>>::value>>
650   constexpr explicit optional(_InPlaceT, _Args&&... __args);
651 
652   template <class _Up, class... _Args,
653             class = enable_if_t<is_constructible_v<
654                 value_type, initializer_list<_Up>&, _Args...>>>
655   constexpr explicit optional(in_place_t, initializer_list<_Up> __il,
656                               _Args&&... __args);
657 
658   template <
659       class _Up = value_type,
660       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(),
661                 int> = 0>
662   constexpr optional(_Up&& __v);
663 
664   template <
665       class _Up,
666       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(),
667                 int> = 0>
668   constexpr explicit optional(_Up&& __v);
669 
670   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
671                                      template __enable_implicit<_Up>(),
672                                  int> = 0>
673   constexpr optional(const optional<_Up>& __v);
674 
675   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
676                                      template __enable_explicit<_Up>(),
677                                  int> = 0>
678   constexpr explicit optional(const optional<_Up>& __v);
679 
680   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
681                                      template __enable_implicit<_Up>(),
682                                  int> = 0>
683   constexpr optional(optional<_Up>&& __v);
684 
685   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
686                                      template __enable_explicit<_Up>(),
687                                  int> = 0>
688   constexpr explicit optional(optional<_Up>&& __v);
689 
690   constexpr optional& operator=(nullopt_t) noexcept;
691 
692   optional& operator=(const optional&);
693 
694   optional& operator=(optional&&);
695 
696   template <class _Up = value_type,
697             class = enable_if_t<_And<_IsNotSame<__uncvref_t<_Up>, optional>,
698                                    _Or<_IsNotSame<__uncvref_t<_Up>, value_type>,
699                                        _Not<is_scalar<value_type>>>,
700                                    is_constructible<value_type, _Up>,
701                                    is_assignable<value_type&, _Up>>::value>>
702   constexpr optional& operator=(_Up&& __v);
703 
704   template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>::
705                                      template __enable_assign<_Up>(),
706                                  int> = 0>
707   constexpr optional& operator=(const optional<_Up>& __v);
708 
709   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
710                                      template __enable_assign<_Up>(),
711                                  int> = 0>
712   constexpr optional& operator=(optional<_Up>&& __v);
713 
714   const _Tp& operator*() const&;
715   _Tp& operator*() &;
716   const _Tp&& operator*() const&&;
717   _Tp&& operator*() &&;
718 
719   const _Tp* operator->() const;
720   _Tp* operator->();
721 
722   const _Tp& value() const&;
723   _Tp& value() &;
724   const _Tp&& value() const&&;
725   _Tp&& value() &&;
726 
727   template <typename U>
728   constexpr _Tp value_or(U&& v) const&;
729   template <typename U>
730   _Tp value_or(U&& v) &&;
731 
732   template <typename... Args>
733   _Tp& emplace(Args&&... args);
734 
735   template <typename U, typename... Args>
736   _Tp& emplace(std::initializer_list<U> ilist, Args&&... args);
737 
738   using __base::reset;
739 
740   constexpr explicit operator bool() const noexcept;
741   using __base::has_value;
742 
743   constexpr void swap(optional& __opt) noexcept;
744 };
745 
746 template <typename T>
747 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
748 
749 template <typename T, typename... Args>
750 constexpr optional<T> make_optional(Args&&... args);
751 
752 template <typename T, typename U, typename... Args>
753 constexpr optional<T> make_optional(std::initializer_list<U> il,
754                                     Args&&... args);
755 
756 } // namespace std
757 )";
758 
759 static constexpr char AbslOptionalHeader[] = R"(
760 #include "absl_type_traits.h"
761 #include "std_initializer_list.h"
762 #include "std_type_traits.h"
763 #include "std_utility.h"
764 
765 namespace absl {
766 
767 struct nullopt_t {
768   constexpr explicit nullopt_t() {}
769 };
770 constexpr nullopt_t nullopt;
771 
772 struct in_place_t {};
773 constexpr in_place_t in_place;
774 
775 template <typename T>
776 class optional;
777 
778 namespace optional_internal {
779 
780 template <typename T, typename U>
781 struct is_constructible_convertible_from_optional
782     : std::integral_constant<
783           bool, std::is_constructible<T, optional<U>&>::value ||
784                     std::is_constructible<T, optional<U>&&>::value ||
785                     std::is_constructible<T, const optional<U>&>::value ||
786                     std::is_constructible<T, const optional<U>&&>::value ||
787                     std::is_convertible<optional<U>&, T>::value ||
788                     std::is_convertible<optional<U>&&, T>::value ||
789                     std::is_convertible<const optional<U>&, T>::value ||
790                     std::is_convertible<const optional<U>&&, T>::value> {};
791 
792 template <typename T, typename U>
793 struct is_constructible_convertible_assignable_from_optional
794     : std::integral_constant<
795           bool, is_constructible_convertible_from_optional<T, U>::value ||
796                     std::is_assignable<T&, optional<U>&>::value ||
797                     std::is_assignable<T&, optional<U>&&>::value ||
798                     std::is_assignable<T&, const optional<U>&>::value ||
799                     std::is_assignable<T&, const optional<U>&&>::value> {};
800 
801 }  // namespace optional_internal
802 
803 template <typename T>
804 class optional {
805  public:
806   constexpr optional() noexcept;
807 
808   constexpr optional(nullopt_t) noexcept;
809 
810   optional(const optional&) = default;
811 
812   optional(optional&&) = default;
813 
814   template <typename InPlaceT, typename... Args,
815             absl::enable_if_t<absl::conjunction<
816                 std::is_same<InPlaceT, in_place_t>,
817                 std::is_constructible<T, Args&&...>>::value>* = nullptr>
818   constexpr explicit optional(InPlaceT, Args&&... args);
819 
820   template <typename U, typename... Args,
821             typename = typename std::enable_if<std::is_constructible<
822                 T, std::initializer_list<U>&, Args&&...>::value>::type>
823   constexpr explicit optional(in_place_t, std::initializer_list<U> il,
824                               Args&&... args);
825 
826   template <
827       typename U = T,
828       typename std::enable_if<
829           absl::conjunction<absl::negation<std::is_same<
830                                 in_place_t, typename std::decay<U>::type>>,
831                             absl::negation<std::is_same<
832                                 optional<T>, typename std::decay<U>::type>>,
833                             std::is_convertible<U&&, T>,
834                             std::is_constructible<T, U&&>>::value,
835           bool>::type = false>
836   constexpr optional(U&& v);
837 
838   template <
839       typename U = T,
840       typename std::enable_if<
841           absl::conjunction<absl::negation<std::is_same<
842                                 in_place_t, typename std::decay<U>::type>>,
843                             absl::negation<std::is_same<
844                                 optional<T>, typename std::decay<U>::type>>,
845                             absl::negation<std::is_convertible<U&&, T>>,
846                             std::is_constructible<T, U&&>>::value,
847           bool>::type = false>
848   explicit constexpr optional(U&& v);
849 
850   template <typename U,
851             typename std::enable_if<
852                 absl::conjunction<
853                     absl::negation<std::is_same<T, U>>,
854                     std::is_constructible<T, const U&>,
855                     absl::negation<
856                         optional_internal::
857                             is_constructible_convertible_from_optional<T, U>>,
858                     std::is_convertible<const U&, T>>::value,
859                 bool>::type = false>
860   optional(const optional<U>& rhs);
861 
862   template <typename U,
863             typename std::enable_if<
864                 absl::conjunction<
865                     absl::negation<std::is_same<T, U>>,
866                     std::is_constructible<T, const U&>,
867                     absl::negation<
868                         optional_internal::
869                             is_constructible_convertible_from_optional<T, U>>,
870                     absl::negation<std::is_convertible<const U&, T>>>::value,
871                 bool>::type = false>
872   explicit optional(const optional<U>& rhs);
873 
874   template <
875       typename U,
876       typename std::enable_if<
877           absl::conjunction<
878               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
879               absl::negation<
880                   optional_internal::is_constructible_convertible_from_optional<
881                       T, U>>,
882               std::is_convertible<U&&, T>>::value,
883           bool>::type = false>
884   optional(optional<U>&& rhs);
885 
886   template <
887       typename U,
888       typename std::enable_if<
889           absl::conjunction<
890               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
891               absl::negation<
892                   optional_internal::is_constructible_convertible_from_optional<
893                       T, U>>,
894               absl::negation<std::is_convertible<U&&, T>>>::value,
895           bool>::type = false>
896   explicit optional(optional<U>&& rhs);
897 
898   optional& operator=(nullopt_t) noexcept;
899 
900   optional& operator=(const optional& src);
901 
902   optional& operator=(optional&& src);
903 
904   template <
905       typename U = T,
906       typename = typename std::enable_if<absl::conjunction<
907           absl::negation<
908               std::is_same<optional<T>, typename std::decay<U>::type>>,
909           absl::negation<
910               absl::conjunction<std::is_scalar<T>,
911                                 std::is_same<T, typename std::decay<U>::type>>>,
912           std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
913   optional& operator=(U&& v);
914 
915   template <
916       typename U,
917       typename = typename std::enable_if<absl::conjunction<
918           absl::negation<std::is_same<T, U>>,
919           std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
920           absl::negation<
921               optional_internal::
922                   is_constructible_convertible_assignable_from_optional<
923                       T, U>>>::value>::type>
924   optional& operator=(const optional<U>& rhs);
925 
926   template <typename U,
927             typename = typename std::enable_if<absl::conjunction<
928                 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
929                 std::is_assignable<T&, U>,
930                 absl::negation<
931                     optional_internal::
932                         is_constructible_convertible_assignable_from_optional<
933                             T, U>>>::value>::type>
934   optional& operator=(optional<U>&& rhs);
935 
936   const T& operator*() const&;
937   T& operator*() &;
938   const T&& operator*() const&&;
939   T&& operator*() &&;
940 
941   const T* operator->() const;
942   T* operator->();
943 
944   const T& value() const&;
945   T& value() &;
946   const T&& value() const&&;
947   T&& value() &&;
948 
949   template <typename U>
950   constexpr T value_or(U&& v) const&;
951   template <typename U>
952   T value_or(U&& v) &&;
953 
954   template <typename... Args>
955   T& emplace(Args&&... args);
956 
957   template <typename U, typename... Args>
958   T& emplace(std::initializer_list<U> ilist, Args&&... args);
959 
960   void reset() noexcept;
961 
962   constexpr explicit operator bool() const noexcept;
963   constexpr bool has_value() const noexcept;
964 
965   void swap(optional& rhs) noexcept;
966 };
967 
968 template <typename T>
969 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
970 
971 template <typename T, typename... Args>
972 constexpr optional<T> make_optional(Args&&... args);
973 
974 template <typename T, typename U, typename... Args>
975 constexpr optional<T> make_optional(std::initializer_list<U> il,
976                                     Args&&... args);
977 
978 } // namespace absl
979 )";
980 
981 static constexpr char BaseOptionalHeader[] = R"(
982 #include "std_initializer_list.h"
983 #include "std_type_traits.h"
984 #include "std_utility.h"
985 
986 namespace base {
987 
988 struct in_place_t {};
989 constexpr in_place_t in_place;
990 
991 struct nullopt_t {
992   constexpr explicit nullopt_t() {}
993 };
994 constexpr nullopt_t nullopt;
995 
996 template <typename T>
997 class Optional;
998 
999 namespace internal {
1000 
1001 template <typename T>
1002 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
1003 
1004 template <typename T, typename U>
1005 struct IsConvertibleFromOptional
1006     : std::integral_constant<
1007           bool, std::is_constructible<T, Optional<U>&>::value ||
1008                     std::is_constructible<T, const Optional<U>&>::value ||
1009                     std::is_constructible<T, Optional<U>&&>::value ||
1010                     std::is_constructible<T, const Optional<U>&&>::value ||
1011                     std::is_convertible<Optional<U>&, T>::value ||
1012                     std::is_convertible<const Optional<U>&, T>::value ||
1013                     std::is_convertible<Optional<U>&&, T>::value ||
1014                     std::is_convertible<const Optional<U>&&, T>::value> {};
1015 
1016 template <typename T, typename U>
1017 struct IsAssignableFromOptional
1018     : std::integral_constant<
1019           bool, IsConvertibleFromOptional<T, U>::value ||
1020                     std::is_assignable<T&, Optional<U>&>::value ||
1021                     std::is_assignable<T&, const Optional<U>&>::value ||
1022                     std::is_assignable<T&, Optional<U>&&>::value ||
1023                     std::is_assignable<T&, const Optional<U>&&>::value> {};
1024 
1025 }  // namespace internal
1026 
1027 template <typename T>
1028 class Optional {
1029  public:
1030   using value_type = T;
1031 
1032   constexpr Optional() = default;
1033   constexpr Optional(const Optional& other) noexcept = default;
1034   constexpr Optional(Optional&& other) noexcept = default;
1035 
1036   constexpr Optional(nullopt_t);
1037 
1038   template <typename U,
1039             typename std::enable_if<
1040                 std::is_constructible<T, const U&>::value &&
1041                     !internal::IsConvertibleFromOptional<T, U>::value &&
1042                     std::is_convertible<const U&, T>::value,
1043                 bool>::type = false>
1044   Optional(const Optional<U>& other) noexcept;
1045 
1046   template <typename U,
1047             typename std::enable_if<
1048                 std::is_constructible<T, const U&>::value &&
1049                     !internal::IsConvertibleFromOptional<T, U>::value &&
1050                     !std::is_convertible<const U&, T>::value,
1051                 bool>::type = false>
1052   explicit Optional(const Optional<U>& other) noexcept;
1053 
1054   template <typename U,
1055             typename std::enable_if<
1056                 std::is_constructible<T, U&&>::value &&
1057                     !internal::IsConvertibleFromOptional<T, U>::value &&
1058                     std::is_convertible<U&&, T>::value,
1059                 bool>::type = false>
1060   Optional(Optional<U>&& other) noexcept;
1061 
1062   template <typename U,
1063             typename std::enable_if<
1064                 std::is_constructible<T, U&&>::value &&
1065                     !internal::IsConvertibleFromOptional<T, U>::value &&
1066                     !std::is_convertible<U&&, T>::value,
1067                 bool>::type = false>
1068   explicit Optional(Optional<U>&& other) noexcept;
1069 
1070   template <class... Args>
1071   constexpr explicit Optional(in_place_t, Args&&... args);
1072 
1073   template <class U, class... Args,
1074             class = typename std::enable_if<std::is_constructible<
1075                 value_type, std::initializer_list<U>&, Args...>::value>::type>
1076   constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
1077                               Args&&... args);
1078 
1079   template <
1080       typename U = value_type,
1081       typename std::enable_if<
1082           std::is_constructible<T, U&&>::value &&
1083               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1084               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1085               std::is_convertible<U&&, T>::value,
1086           bool>::type = false>
1087   constexpr Optional(U&& value);
1088 
1089   template <
1090       typename U = value_type,
1091       typename std::enable_if<
1092           std::is_constructible<T, U&&>::value &&
1093               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1094               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1095               !std::is_convertible<U&&, T>::value,
1096           bool>::type = false>
1097   constexpr explicit Optional(U&& value);
1098 
1099   Optional& operator=(const Optional& other) noexcept;
1100 
1101   Optional& operator=(Optional&& other) noexcept;
1102 
1103   Optional& operator=(nullopt_t);
1104 
1105   template <typename U>
1106   typename std::enable_if<
1107       !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1108           std::is_constructible<T, U>::value &&
1109           std::is_assignable<T&, U>::value &&
1110           (!std::is_scalar<T>::value ||
1111            !std::is_same<typename std::decay<U>::type, T>::value),
1112       Optional&>::type
1113   operator=(U&& value) noexcept;
1114 
1115   template <typename U>
1116   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1117                               std::is_constructible<T, const U&>::value &&
1118                               std::is_assignable<T&, const U&>::value,
1119                           Optional&>::type
1120   operator=(const Optional<U>& other) noexcept;
1121 
1122   template <typename U>
1123   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1124                               std::is_constructible<T, U>::value &&
1125                               std::is_assignable<T&, U>::value,
1126                           Optional&>::type
1127   operator=(Optional<U>&& other) noexcept;
1128 
1129   const T& operator*() const&;
1130   T& operator*() &;
1131   const T&& operator*() const&&;
1132   T&& operator*() &&;
1133 
1134   const T* operator->() const;
1135   T* operator->();
1136 
1137   const T& value() const&;
1138   T& value() &;
1139   const T&& value() const&&;
1140   T&& value() &&;
1141 
1142   template <typename U>
1143   constexpr T value_or(U&& v) const&;
1144   template <typename U>
1145   T value_or(U&& v) &&;
1146 
1147   template <typename... Args>
1148   T& emplace(Args&&... args);
1149 
1150   template <typename U, typename... Args>
1151   T& emplace(std::initializer_list<U> ilist, Args&&... args);
1152 
1153   void reset() noexcept;
1154 
1155   constexpr explicit operator bool() const noexcept;
1156   constexpr bool has_value() const noexcept;
1157 
1158   void swap(Optional& other);
1159 };
1160 
1161 template <typename T>
1162 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v);
1163 
1164 template <typename T, typename... Args>
1165 constexpr Optional<T> make_optional(Args&&... args);
1166 
1167 template <typename T, typename U, typename... Args>
1168 constexpr Optional<T> make_optional(std::initializer_list<U> il,
1169                                     Args&&... args);
1170 
1171 } // namespace base
1172 )";
1173 
1174 /// Converts `L` to string.
1175 static std::string ConvertToString(const SourceLocationsLattice &L,
1176                                    const ASTContext &Ctx) {
1177   return L.getSourceLocations().empty() ? "safe"
1178                                         : "unsafe: " + DebugString(L, Ctx);
1179 }
1180 
1181 /// Replaces all occurrences of `Pattern` in `S` with `Replacement`.
1182 static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern,
1183                                   const std::string &Replacement) {
1184   size_t Pos = 0;
1185   while (true) {
1186     Pos = S.find(Pattern, Pos);
1187     if (Pos == std::string::npos)
1188       break;
1189     S.replace(Pos, Pattern.size(), Replacement);
1190   }
1191 }
1192 
1193 struct OptionalTypeIdentifier {
1194   std::string NamespaceName;
1195   std::string TypeName;
1196 };
1197 
1198 class UncheckedOptionalAccessTest
1199     : public ::testing::TestWithParam<OptionalTypeIdentifier> {
1200 protected:
1201   template <typename LatticeChecksMatcher>
1202   void ExpectLatticeChecksFor(std::string SourceCode,
1203                               LatticeChecksMatcher MatchesLatticeChecks) {
1204     ExpectLatticeChecksFor(SourceCode, ast_matchers::hasName("target"),
1205                            MatchesLatticeChecks);
1206   }
1207 
1208 private:
1209   template <typename FuncDeclMatcher, typename LatticeChecksMatcher>
1210   void ExpectLatticeChecksFor(std::string SourceCode,
1211                               FuncDeclMatcher FuncMatcher,
1212                               LatticeChecksMatcher MatchesLatticeChecks) {
1213     ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName);
1214     ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName);
1215 
1216     std::vector<std::pair<std::string, std::string>> Headers;
1217     Headers.emplace_back("cstddef.h", CSDtdDefHeader);
1218     Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader);
1219     Headers.emplace_back("std_string.h", StdStringHeader);
1220     Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader);
1221     Headers.emplace_back("std_utility.h", StdUtilityHeader);
1222     Headers.emplace_back("std_optional.h", StdOptionalHeader);
1223     Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader);
1224     Headers.emplace_back("absl_optional.h", AbslOptionalHeader);
1225     Headers.emplace_back("base_optional.h", BaseOptionalHeader);
1226     Headers.emplace_back("unchecked_optional_access_test.h", R"(
1227       #include "absl_optional.h"
1228       #include "base_optional.h"
1229       #include "std_initializer_list.h"
1230       #include "std_optional.h"
1231       #include "std_string.h"
1232       #include "std_utility.h"
1233 
1234       template <typename T>
1235       T Make();
1236     )");
1237     const tooling::FileContentMappings FileContents(Headers.begin(),
1238                                                     Headers.end());
1239     llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
1240         SourceCode, FuncMatcher,
1241         [](ASTContext &Ctx, Environment &) {
1242           return UncheckedOptionalAccessModel(
1243               Ctx, UncheckedOptionalAccessModelOptions{
1244                        /*IgnoreSmartPointerDereference=*/true});
1245         },
1246         [&MatchesLatticeChecks](
1247             llvm::ArrayRef<std::pair<
1248                 std::string, DataflowAnalysisState<SourceLocationsLattice>>>
1249                 CheckToLatticeMap,
1250             ASTContext &Ctx) {
1251           // FIXME: Consider using a matcher instead of translating
1252           // `CheckToLatticeMap` to `CheckToStringifiedLatticeMap`.
1253           std::vector<std::pair<std::string, std::string>>
1254               CheckToStringifiedLatticeMap;
1255           for (const auto &E : CheckToLatticeMap) {
1256             CheckToStringifiedLatticeMap.emplace_back(
1257                 E.first, ConvertToString(E.second.Lattice, Ctx));
1258           }
1259           EXPECT_THAT(CheckToStringifiedLatticeMap, MatchesLatticeChecks);
1260         },
1261         {"-fsyntax-only", "-std=c++17", "-Wno-undefined-inline"}, FileContents);
1262     if (Error)
1263       FAIL() << llvm::toString(std::move(Error));
1264   }
1265 };
1266 
1267 INSTANTIATE_TEST_SUITE_P(
1268     UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
1269     ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
1270                       OptionalTypeIdentifier{"absl", "optional"},
1271                       OptionalTypeIdentifier{"base", "Optional"}),
1272     [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
1273       return Info.param.NamespaceName;
1274     });
1275 
1276 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
1277   ExpectLatticeChecksFor(R"(
1278     void target() {
1279       (void)0;
1280       /*[[check]]*/
1281     }
1282   )",
1283                          UnorderedElementsAre(Pair("check", "safe")));
1284 }
1285 
1286 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
1287   ExpectLatticeChecksFor(
1288       R"(
1289     #include "unchecked_optional_access_test.h"
1290 
1291     void target($ns::$optional<int> opt) {
1292       opt.value();
1293       /*[[check]]*/
1294     }
1295   )",
1296       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1297 
1298   ExpectLatticeChecksFor(
1299       R"(
1300     #include "unchecked_optional_access_test.h"
1301 
1302     void target($ns::$optional<int> opt) {
1303       std::move(opt).value();
1304       /*[[check]]*/
1305     }
1306   )",
1307       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1308 }
1309 
1310 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
1311   ExpectLatticeChecksFor(
1312       R"(
1313     #include "unchecked_optional_access_test.h"
1314 
1315     void target($ns::$optional<int> opt) {
1316       *opt;
1317       /*[[check]]*/
1318     }
1319   )",
1320       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8")));
1321 
1322   ExpectLatticeChecksFor(
1323       R"(
1324     #include "unchecked_optional_access_test.h"
1325 
1326     void target($ns::$optional<int> opt) {
1327       *std::move(opt);
1328       /*[[check]]*/
1329     }
1330   )",
1331       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8")));
1332 }
1333 
1334 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
1335   ExpectLatticeChecksFor(
1336       R"(
1337     #include "unchecked_optional_access_test.h"
1338 
1339     struct Foo {
1340       void foo();
1341     };
1342 
1343     void target($ns::$optional<Foo> opt) {
1344       opt->foo();
1345       /*[[check]]*/
1346     }
1347   )",
1348       UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7")));
1349 
1350   ExpectLatticeChecksFor(
1351       R"(
1352     #include "unchecked_optional_access_test.h"
1353 
1354     struct Foo {
1355       void foo();
1356     };
1357 
1358     void target($ns::$optional<Foo> opt) {
1359       std::move(opt)->foo();
1360       /*[[check]]*/
1361     }
1362   )",
1363       UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7")));
1364 }
1365 
1366 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
1367   ExpectLatticeChecksFor(R"(
1368     #include "unchecked_optional_access_test.h"
1369 
1370     void target($ns::$optional<int> opt) {
1371       if (opt.has_value()) {
1372         opt.value();
1373         /*[[check]]*/
1374       }
1375     }
1376   )",
1377                          UnorderedElementsAre(Pair("check", "safe")));
1378 }
1379 
1380 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
1381   ExpectLatticeChecksFor(R"(
1382     #include "unchecked_optional_access_test.h"
1383 
1384     void target($ns::$optional<int> opt) {
1385       if (opt) {
1386         opt.value();
1387         /*[[check]]*/
1388       }
1389     }
1390   )",
1391                          UnorderedElementsAre(Pair("check", "safe")));
1392 }
1393 
1394 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
1395   ExpectLatticeChecksFor(
1396       R"(
1397     #include "unchecked_optional_access_test.h"
1398 
1399     void target() {
1400       Make<$ns::$optional<int>>().value();
1401       (void)0;
1402       /*[[check]]*/
1403     }
1404   )",
1405       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1406 
1407   ExpectLatticeChecksFor(
1408       R"(
1409     #include "unchecked_optional_access_test.h"
1410 
1411     void target($ns::$optional<int> opt) {
1412       std::move(opt).value();
1413       /*[[check]]*/
1414     }
1415   )",
1416       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1417 }
1418 
1419 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
1420   ExpectLatticeChecksFor(
1421       R"(
1422     #include "unchecked_optional_access_test.h"
1423 
1424     void target() {
1425       $ns::$optional<int> opt;
1426       opt.value();
1427       /*[[check]]*/
1428     }
1429   )",
1430       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1431 }
1432 
1433 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
1434   ExpectLatticeChecksFor(
1435       R"(
1436     #include "unchecked_optional_access_test.h"
1437 
1438     void target() {
1439       $ns::$optional<int> opt($ns::nullopt);
1440       opt.value();
1441       /*[[check]]*/
1442     }
1443   )",
1444       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1445 }
1446 
1447 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
1448   ExpectLatticeChecksFor(R"(
1449     #include "unchecked_optional_access_test.h"
1450 
1451     void target() {
1452       $ns::$optional<int> opt($ns::in_place, 3);
1453       opt.value();
1454       /*[[check]]*/
1455     }
1456   )",
1457                          UnorderedElementsAre(Pair("check", "safe")));
1458 
1459   ExpectLatticeChecksFor(R"(
1460     #include "unchecked_optional_access_test.h"
1461 
1462     struct Foo {};
1463 
1464     void target() {
1465       $ns::$optional<Foo> opt($ns::in_place);
1466       opt.value();
1467       /*[[check]]*/
1468     }
1469   )",
1470                          UnorderedElementsAre(Pair("check", "safe")));
1471 
1472   ExpectLatticeChecksFor(R"(
1473     #include "unchecked_optional_access_test.h"
1474 
1475     struct Foo {
1476       explicit Foo(int, bool);
1477     };
1478 
1479     void target() {
1480       $ns::$optional<Foo> opt($ns::in_place, 3, false);
1481       opt.value();
1482       /*[[check]]*/
1483     }
1484   )",
1485                          UnorderedElementsAre(Pair("check", "safe")));
1486 
1487   ExpectLatticeChecksFor(R"(
1488     #include "unchecked_optional_access_test.h"
1489 
1490     struct Foo {
1491       explicit Foo(std::initializer_list<int>);
1492     };
1493 
1494     void target() {
1495       $ns::$optional<Foo> opt($ns::in_place, {3});
1496       opt.value();
1497       /*[[check]]*/
1498     }
1499   )",
1500                          UnorderedElementsAre(Pair("check", "safe")));
1501 }
1502 
1503 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
1504   ExpectLatticeChecksFor(R"(
1505     #include "unchecked_optional_access_test.h"
1506 
1507     void target() {
1508       $ns::$optional<int> opt(21);
1509       opt.value();
1510       /*[[check]]*/
1511     }
1512   )",
1513                          UnorderedElementsAre(Pair("check", "safe")));
1514 
1515   ExpectLatticeChecksFor(R"(
1516     #include "unchecked_optional_access_test.h"
1517 
1518     void target() {
1519       $ns::$optional<int> opt = $ns::$optional<int>(21);
1520       opt.value();
1521       /*[[check]]*/
1522     }
1523   )",
1524                          UnorderedElementsAre(Pair("check", "safe")));
1525   ExpectLatticeChecksFor(R"(
1526     #include "unchecked_optional_access_test.h"
1527 
1528     void target() {
1529       $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1530       opt.value();
1531       /*[[check]]*/
1532     }
1533   )",
1534                          UnorderedElementsAre(Pair("check", "safe")));
1535 
1536   ExpectLatticeChecksFor(R"(
1537     #include "unchecked_optional_access_test.h"
1538 
1539     struct MyString {
1540       MyString(const char*);
1541     };
1542 
1543     void target() {
1544       $ns::$optional<MyString> opt("foo");
1545       opt.value();
1546       /*[[check]]*/
1547     }
1548   )",
1549                          UnorderedElementsAre(Pair("check", "safe")));
1550 
1551   ExpectLatticeChecksFor(R"(
1552     #include "unchecked_optional_access_test.h"
1553 
1554     struct Foo {};
1555 
1556     struct Bar {
1557       Bar(const Foo&);
1558     };
1559 
1560     void target() {
1561       $ns::$optional<Bar> opt(Make<Foo>());
1562       opt.value();
1563       /*[[check]]*/
1564     }
1565   )",
1566                          UnorderedElementsAre(Pair("check", "safe")));
1567 
1568   ExpectLatticeChecksFor(R"(
1569     #include "unchecked_optional_access_test.h"
1570 
1571     struct Foo {
1572       explicit Foo(int);
1573     };
1574 
1575     void target() {
1576       $ns::$optional<Foo> opt(3);
1577       opt.value();
1578       /*[[check]]*/
1579     }
1580   )",
1581                          UnorderedElementsAre(Pair("check", "safe")));
1582 }
1583 
1584 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
1585   ExpectLatticeChecksFor(
1586       R"(
1587     #include "unchecked_optional_access_test.h"
1588 
1589     struct Foo {};
1590 
1591     struct Bar {
1592       Bar(const Foo&);
1593     };
1594 
1595     void target() {
1596       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1597       opt.value();
1598       /*[[check]]*/
1599     }
1600   )",
1601       UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7")));
1602 
1603   ExpectLatticeChecksFor(
1604       R"(
1605     #include "unchecked_optional_access_test.h"
1606 
1607     struct Foo {};
1608 
1609     struct Bar {
1610       explicit Bar(const Foo&);
1611     };
1612 
1613     void target() {
1614       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1615       opt.value();
1616       /*[[check]]*/
1617     }
1618   )",
1619       UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7")));
1620 
1621   ExpectLatticeChecksFor(
1622       R"(
1623     #include "unchecked_optional_access_test.h"
1624 
1625     struct Foo {};
1626 
1627     struct Bar {
1628       Bar(const Foo&);
1629     };
1630 
1631     void target() {
1632       $ns::$optional<Foo> opt1 = $ns::nullopt;
1633       $ns::$optional<Bar> opt2(opt1);
1634       opt2.value();
1635       /*[[check]]*/
1636     }
1637   )",
1638       UnorderedElementsAre(Pair("check", "unsafe: input.cc:13:7")));
1639 
1640   ExpectLatticeChecksFor(R"(
1641     #include "unchecked_optional_access_test.h"
1642 
1643     struct Foo {};
1644 
1645     struct Bar {
1646       Bar(const Foo&);
1647     };
1648 
1649     void target() {
1650       $ns::$optional<Foo> opt1(Make<Foo>());
1651       $ns::$optional<Bar> opt2(opt1);
1652       opt2.value();
1653       /*[[check]]*/
1654     }
1655   )",
1656                          UnorderedElementsAre(Pair("check", "safe")));
1657 
1658   ExpectLatticeChecksFor(R"(
1659     #include "unchecked_optional_access_test.h"
1660 
1661     struct Foo {};
1662 
1663     struct Bar {
1664       explicit Bar(const Foo&);
1665     };
1666 
1667     void target() {
1668       $ns::$optional<Foo> opt1(Make<Foo>());
1669       $ns::$optional<Bar> opt2(opt1);
1670       opt2.value();
1671       /*[[check]]*/
1672     }
1673   )",
1674                          UnorderedElementsAre(Pair("check", "safe")));
1675 }
1676 
1677 TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
1678   ExpectLatticeChecksFor(R"(
1679     #include "unchecked_optional_access_test.h"
1680 
1681     void target() {
1682       $ns::$optional<int> opt = $ns::make_optional(0);
1683       opt.value();
1684       /*[[check]]*/
1685     }
1686   )",
1687                          UnorderedElementsAre(Pair("check", "safe")));
1688 
1689   ExpectLatticeChecksFor(R"(
1690     #include "unchecked_optional_access_test.h"
1691 
1692     struct Foo {
1693       Foo(int, int);
1694     };
1695 
1696     void target() {
1697       $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1698       opt.value();
1699       /*[[check]]*/
1700     }
1701   )",
1702                          UnorderedElementsAre(Pair("check", "safe")));
1703 
1704   ExpectLatticeChecksFor(R"(
1705     #include "unchecked_optional_access_test.h"
1706 
1707     struct Foo {
1708       constexpr Foo(std::initializer_list<char>);
1709     };
1710 
1711     void target() {
1712       char a = 'a';
1713       $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1714       opt.value();
1715       /*[[check]]*/
1716     }
1717   )",
1718                          UnorderedElementsAre(Pair("check", "safe")));
1719 }
1720 
1721 TEST_P(UncheckedOptionalAccessTest, ValueOr) {
1722   ExpectLatticeChecksFor(R"(
1723     #include "unchecked_optional_access_test.h"
1724 
1725     void target() {
1726       $ns::$optional<int> opt;
1727       opt.value_or(0);
1728       (void)0;
1729       /*[[check]]*/
1730     }
1731   )",
1732                          UnorderedElementsAre(Pair("check", "safe")));
1733 }
1734 
1735 TEST_P(UncheckedOptionalAccessTest, ValueOrComparison) {
1736   // Pointers.
1737   ExpectLatticeChecksFor(
1738       R"code(
1739     #include "unchecked_optional_access_test.h"
1740 
1741     void target($ns::$optional<int*> opt) {
1742       if (opt.value_or(nullptr) != nullptr) {
1743         opt.value();
1744         /*[[check-ptrs-1]]*/
1745       } else {
1746         opt.value();
1747         /*[[check-ptrs-2]]*/
1748       }
1749     }
1750   )code",
1751       UnorderedElementsAre(Pair("check-ptrs-1", "safe"),
1752                            Pair("check-ptrs-2", "unsafe: input.cc:9:9")));
1753 
1754   // Integers.
1755   ExpectLatticeChecksFor(
1756       R"code(
1757     #include "unchecked_optional_access_test.h"
1758 
1759     void target($ns::$optional<int> opt) {
1760       if (opt.value_or(0) != 0) {
1761         opt.value();
1762         /*[[check-ints-1]]*/
1763       } else {
1764         opt.value();
1765         /*[[check-ints-2]]*/
1766       }
1767     }
1768   )code",
1769       UnorderedElementsAre(Pair("check-ints-1", "safe"),
1770                            Pair("check-ints-2", "unsafe: input.cc:9:9")));
1771 
1772   // Strings.
1773   ExpectLatticeChecksFor(
1774       R"code(
1775     #include "unchecked_optional_access_test.h"
1776 
1777     void target($ns::$optional<std::string> opt) {
1778       if (!opt.value_or("").empty()) {
1779         opt.value();
1780         /*[[check-strings-1]]*/
1781       } else {
1782         opt.value();
1783         /*[[check-strings-2]]*/
1784       }
1785     }
1786   )code",
1787       UnorderedElementsAre(Pair("check-strings-1", "safe"),
1788                            Pair("check-strings-2", "unsafe: input.cc:9:9")));
1789 
1790   ExpectLatticeChecksFor(
1791       R"code(
1792     #include "unchecked_optional_access_test.h"
1793 
1794     void target($ns::$optional<std::string> opt) {
1795       if (opt.value_or("") != "") {
1796         opt.value();
1797         /*[[check-strings-neq-1]]*/
1798       } else {
1799         opt.value();
1800         /*[[check-strings-neq-2]]*/
1801       }
1802     }
1803   )code",
1804       UnorderedElementsAre(
1805           Pair("check-strings-neq-1", "safe"),
1806           Pair("check-strings-neq-2", "unsafe: input.cc:9:9")));
1807 
1808   // Pointer-to-optional.
1809   //
1810   // FIXME: make `opt` a parameter directly, once we ensure that all `optional`
1811   // values have a `has_value` property.
1812   ExpectLatticeChecksFor(
1813       R"code(
1814     #include "unchecked_optional_access_test.h"
1815 
1816     void target($ns::$optional<int> p) {
1817       $ns::$optional<int> *opt = &p;
1818       if (opt->value_or(0) != 0) {
1819         opt->value();
1820         /*[[check-pto-1]]*/
1821       } else {
1822         opt->value();
1823         /*[[check-pto-2]]*/
1824       }
1825     }
1826   )code",
1827       UnorderedElementsAre(Pair("check-pto-1", "safe"),
1828                            Pair("check-pto-2", "unsafe: input.cc:10:9")));
1829 }
1830 
1831 TEST_P(UncheckedOptionalAccessTest, Emplace) {
1832   ExpectLatticeChecksFor(R"(
1833     #include "unchecked_optional_access_test.h"
1834 
1835     void target() {
1836       $ns::$optional<int> opt;
1837       opt.emplace(0);
1838       opt.value();
1839       /*[[check]]*/
1840     }
1841   )",
1842                          UnorderedElementsAre(Pair("check", "safe")));
1843 
1844   ExpectLatticeChecksFor(R"(
1845     #include "unchecked_optional_access_test.h"
1846 
1847     void target($ns::$optional<int> *opt) {
1848       opt->emplace(0);
1849       opt->value();
1850       /*[[check]]*/
1851     }
1852   )",
1853                          UnorderedElementsAre(Pair("check", "safe")));
1854 
1855   // FIXME: Add tests that call `emplace` in conditional branches.
1856 }
1857 
1858 TEST_P(UncheckedOptionalAccessTest, Reset) {
1859   ExpectLatticeChecksFor(
1860       R"(
1861     #include "unchecked_optional_access_test.h"
1862 
1863     void target() {
1864       $ns::$optional<int> opt = $ns::make_optional(0);
1865       opt.reset();
1866       opt.value();
1867       /*[[check]]*/
1868     }
1869   )",
1870       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7")));
1871 
1872   ExpectLatticeChecksFor(
1873       R"(
1874     #include "unchecked_optional_access_test.h"
1875 
1876     void target($ns::$optional<int> &opt) {
1877       if (opt.has_value()) {
1878         opt.reset();
1879         opt.value();
1880         /*[[check]]*/
1881       }
1882     }
1883   )",
1884       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:9")));
1885 
1886   // FIXME: Add tests that call `reset` in conditional branches.
1887 }
1888 
1889 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) {
1890   ExpectLatticeChecksFor(R"(
1891     #include "unchecked_optional_access_test.h"
1892 
1893     struct Foo {};
1894 
1895     void target() {
1896       $ns::$optional<Foo> opt;
1897       opt = Foo();
1898       opt.value();
1899       /*[[check]]*/
1900     }
1901   )",
1902                          UnorderedElementsAre(Pair("check", "safe")));
1903 
1904   ExpectLatticeChecksFor(R"(
1905     #include "unchecked_optional_access_test.h"
1906 
1907     struct Foo {};
1908 
1909     void target() {
1910       $ns::$optional<Foo> opt;
1911       (opt = Foo()).value();
1912       (void)0;
1913       /*[[check]]*/
1914     }
1915   )",
1916                          UnorderedElementsAre(Pair("check", "safe")));
1917 
1918   ExpectLatticeChecksFor(R"(
1919     #include "unchecked_optional_access_test.h"
1920 
1921     struct MyString {
1922       MyString(const char*);
1923     };
1924 
1925     void target() {
1926       $ns::$optional<MyString> opt;
1927       opt = "foo";
1928       opt.value();
1929       /*[[check]]*/
1930     }
1931   )",
1932                          UnorderedElementsAre(Pair("check", "safe")));
1933 
1934   ExpectLatticeChecksFor(R"(
1935     #include "unchecked_optional_access_test.h"
1936 
1937     struct MyString {
1938       MyString(const char*);
1939     };
1940 
1941     void target() {
1942       $ns::$optional<MyString> opt;
1943       (opt = "foo").value();
1944       /*[[check]]*/
1945     }
1946   )",
1947                          UnorderedElementsAre(Pair("check", "safe")));
1948 }
1949 
1950 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) {
1951   ExpectLatticeChecksFor(
1952       R"(
1953     #include "unchecked_optional_access_test.h"
1954 
1955     struct Foo {};
1956 
1957     struct Bar {
1958       Bar(const Foo&);
1959     };
1960 
1961     void target() {
1962       $ns::$optional<Foo> opt1 = Foo();
1963       $ns::$optional<Bar> opt2;
1964       opt2 = opt1;
1965       opt2.value();
1966       /*[[check]]*/
1967     }
1968   )",
1969       UnorderedElementsAre(Pair("check", "safe")));
1970 
1971   ExpectLatticeChecksFor(
1972       R"(
1973     #include "unchecked_optional_access_test.h"
1974 
1975     struct Foo {};
1976 
1977     struct Bar {
1978       Bar(const Foo&);
1979     };
1980 
1981     void target() {
1982       $ns::$optional<Foo> opt1;
1983       $ns::$optional<Bar> opt2;
1984       if (opt2.has_value()) {
1985         opt2 = opt1;
1986         opt2.value();
1987         /*[[check]]*/
1988       }
1989     }
1990   )",
1991       UnorderedElementsAre(Pair("check", "unsafe: input.cc:15:9")));
1992 
1993   ExpectLatticeChecksFor(
1994       R"(
1995     #include "unchecked_optional_access_test.h"
1996 
1997     struct Foo {};
1998 
1999     struct Bar {
2000       Bar(const Foo&);
2001     };
2002 
2003     void target() {
2004       $ns::$optional<Foo> opt1 = Foo();
2005       $ns::$optional<Bar> opt2;
2006       (opt2 = opt1).value();
2007       (void)0;
2008       /*[[check]]*/
2009     }
2010   )",
2011       UnorderedElementsAre(Pair("check", "safe")));
2012 }
2013 
2014 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) {
2015   ExpectLatticeChecksFor(
2016       R"(
2017     #include "unchecked_optional_access_test.h"
2018 
2019     void target() {
2020       $ns::$optional<int> opt = 3;
2021       opt = $ns::nullopt;
2022       opt.value();
2023       /*[[check]]*/
2024     }
2025   )",
2026       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7")));
2027 
2028   ExpectLatticeChecksFor(
2029       R"(
2030     #include "unchecked_optional_access_test.h"
2031 
2032     void target() {
2033       $ns::$optional<int> opt = 3;
2034       (opt = $ns::nullopt).value();
2035       /*[[check]]*/
2036     }
2037   )",
2038       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
2039 }
2040 
2041 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) {
2042   ExpectLatticeChecksFor(
2043       R"(
2044     #include "unchecked_optional_access_test.h"
2045 
2046     void target() {
2047       $ns::$optional<int> opt1 = $ns::nullopt;
2048       $ns::$optional<int> opt2 = 3;
2049 
2050       opt1.swap(opt2);
2051 
2052       opt1.value();
2053       /*[[check-1]]*/
2054 
2055       opt2.value();
2056       /*[[check-2]]*/
2057     }
2058   )",
2059       UnorderedElementsAre(Pair("check-1", "safe"),
2060                            Pair("check-2", "unsafe: input.cc:13:7")));
2061 
2062   ExpectLatticeChecksFor(
2063       R"(
2064     #include "unchecked_optional_access_test.h"
2065 
2066     void target() {
2067       $ns::$optional<int> opt1 = $ns::nullopt;
2068       $ns::$optional<int> opt2 = 3;
2069 
2070       opt2.swap(opt1);
2071 
2072       opt1.value();
2073       /*[[check-3]]*/
2074 
2075       opt2.value();
2076       /*[[check-4]]*/
2077     }
2078   )",
2079       UnorderedElementsAre(Pair("check-3", "safe"),
2080                            Pair("check-4", "unsafe: input.cc:13:7")));
2081 }
2082 
2083 TEST_P(UncheckedOptionalAccessTest, StdSwap) {
2084   ExpectLatticeChecksFor(
2085       R"(
2086     #include "unchecked_optional_access_test.h"
2087 
2088     void target() {
2089       $ns::$optional<int> opt1 = $ns::nullopt;
2090       $ns::$optional<int> opt2 = 3;
2091 
2092       std::swap(opt1, opt2);
2093 
2094       opt1.value();
2095       /*[[check-1]]*/
2096 
2097       opt2.value();
2098       /*[[check-2]]*/
2099     }
2100   )",
2101       UnorderedElementsAre(Pair("check-1", "safe"),
2102                            Pair("check-2", "unsafe: input.cc:13:7")));
2103 
2104   ExpectLatticeChecksFor(
2105       R"(
2106     #include "unchecked_optional_access_test.h"
2107 
2108     void target() {
2109       $ns::$optional<int> opt1 = $ns::nullopt;
2110       $ns::$optional<int> opt2 = 3;
2111 
2112       std::swap(opt2, opt1);
2113 
2114       opt1.value();
2115       /*[[check-3]]*/
2116 
2117       opt2.value();
2118       /*[[check-4]]*/
2119     }
2120   )",
2121       UnorderedElementsAre(Pair("check-3", "safe"),
2122                            Pair("check-4", "unsafe: input.cc:13:7")));
2123 }
2124 
2125 TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) {
2126   // We suppress diagnostics for values reachable from smart pointers (other
2127   // than `optional` itself).
2128   ExpectLatticeChecksFor(
2129       R"(
2130     #include "unchecked_optional_access_test.h"
2131 
2132     template <typename T>
2133     struct smart_ptr {
2134       T& operator*() &;
2135       T* operator->();
2136     };
2137 
2138     struct Foo {
2139       $ns::$optional<int> opt;
2140     };
2141 
2142     void target() {
2143       smart_ptr<Foo> foo;
2144       *foo->opt;
2145       /*[[check-1]]*/
2146       *(*foo).opt;
2147       /*[[check-2]]*/
2148     }
2149   )",
2150       UnorderedElementsAre(Pair("check-1", "safe"), Pair("check-2", "safe")));
2151 }
2152 
2153 TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) {
2154   ExpectLatticeChecksFor(
2155       R"(
2156     #include "unchecked_optional_access_test.h"
2157 
2158     $ns::$optional<int> MakeOpt();
2159 
2160     void target() {
2161       $ns::$optional<int> opt = 0;
2162       opt = MakeOpt();
2163       opt.value();
2164       /*[[check-1]]*/
2165     }
2166   )",
2167       UnorderedElementsAre(Pair("check-1", "unsafe: input.cc:9:7")));
2168 
2169   ExpectLatticeChecksFor(
2170       R"(
2171     #include "unchecked_optional_access_test.h"
2172 
2173     const $ns::$optional<int>& MakeOpt();
2174 
2175     void target() {
2176       $ns::$optional<int> opt = 0;
2177       opt = MakeOpt();
2178       opt.value();
2179       /*[[check-2]]*/
2180     }
2181   )",
2182       UnorderedElementsAre(Pair("check-2", "unsafe: input.cc:9:7")));
2183 
2184   ExpectLatticeChecksFor(
2185       R"(
2186     #include "unchecked_optional_access_test.h"
2187 
2188     using IntOpt = $ns::$optional<int>;
2189     IntOpt MakeOpt();
2190 
2191     void target() {
2192       IntOpt opt = 0;
2193       opt = MakeOpt();
2194       opt.value();
2195       /*[[check-3]]*/
2196     }
2197   )",
2198       UnorderedElementsAre(Pair("check-3", "unsafe: input.cc:10:7")));
2199 
2200   ExpectLatticeChecksFor(
2201       R"(
2202     #include "unchecked_optional_access_test.h"
2203 
2204     using IntOpt = $ns::$optional<int>;
2205     const IntOpt& MakeOpt();
2206 
2207     void target() {
2208       IntOpt opt = 0;
2209       opt = MakeOpt();
2210       opt.value();
2211       /*[[check-4]]*/
2212     }
2213   )",
2214       UnorderedElementsAre(Pair("check-4", "unsafe: input.cc:10:7")));
2215 }
2216 
2217 // FIXME: Add support for:
2218 // - constructors (copy, move)
2219 // - assignment operators (default, copy, move)
2220 // - invalidation (passing optional by non-const reference/pointer)
2221 // - nested `optional` values
2222