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 StdUtilityHeader[] = R"(
500 #ifndef UTILITY_H
501 #define UTILITY_H
502 
503 #include "std_type_traits.h"
504 
505 namespace std {
506 
507 template <typename T>
508 constexpr remove_reference_t<T>&& move(T&& x);
509 
510 } // namespace std
511 
512 #endif // UTILITY_H
513 )";
514 
515 static constexpr char StdInitializerListHeader[] = R"(
516 #ifndef INITIALIZER_LIST_H
517 #define INITIALIZER_LIST_H
518 
519 namespace std {
520 
521 template <typename T>
522 class initializer_list {
523  public:
524   initializer_list() noexcept;
525 };
526 
527 } // namespace std
528 
529 #endif // INITIALIZER_LIST_H
530 )";
531 
532 static constexpr char StdOptionalHeader[] = R"(
533 #include "std_initializer_list.h"
534 #include "std_type_traits.h"
535 #include "std_utility.h"
536 
537 namespace std {
538 
539 struct in_place_t {};
540 constexpr in_place_t in_place;
541 
542 struct nullopt_t {
543   constexpr explicit nullopt_t() {}
544 };
545 constexpr nullopt_t nullopt;
546 
547 template <class _Tp>
548 struct __optional_destruct_base {
549   constexpr void reset() noexcept;
550 };
551 
552 template <class _Tp>
553 struct __optional_storage_base : __optional_destruct_base<_Tp> {
554   constexpr bool has_value() const noexcept;
555 };
556 
557 template <typename _Tp>
558 class optional : private __optional_storage_base<_Tp> {
559   using __base = __optional_storage_base<_Tp>;
560 
561  public:
562   using value_type = _Tp;
563 
564  private:
565   struct _CheckOptionalArgsConstructor {
566     template <class _Up>
567     static constexpr bool __enable_implicit() {
568       return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
569     }
570 
571     template <class _Up>
572     static constexpr bool __enable_explicit() {
573       return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
574     }
575   };
576   template <class _Up>
577   using _CheckOptionalArgsCtor =
578       _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value &&
579               _IsNotSame<__uncvref_t<_Up>, optional>::value,
580           _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>;
581   template <class _QualUp>
582   struct _CheckOptionalLikeConstructor {
583     template <class _Up, class _Opt = optional<_Up>>
584     using __check_constructible_from_opt =
585         _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>,
586             is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>,
587             is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>,
588             is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>;
589     template <class _Up, class _QUp = _QualUp>
590     static constexpr bool __enable_implicit() {
591       return is_convertible<_QUp, _Tp>::value &&
592              !__check_constructible_from_opt<_Up>::value;
593     }
594     template <class _Up, class _QUp = _QualUp>
595     static constexpr bool __enable_explicit() {
596       return !is_convertible<_QUp, _Tp>::value &&
597              !__check_constructible_from_opt<_Up>::value;
598     }
599   };
600 
601   template <class _Up, class _QualUp>
602   using _CheckOptionalLikeCtor =
603       _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value,
604           _CheckOptionalLikeConstructor<_QualUp>,
605           __check_tuple_constructor_fail>;
606 
607 
608   template <class _Up, class _QualUp>
609   using _CheckOptionalLikeAssign = _If<
610       _And<
611           _IsNotSame<_Up, _Tp>,
612           is_constructible<_Tp, _QualUp>,
613           is_assignable<_Tp&, _QualUp>
614       >::value,
615       _CheckOptionalLikeConstructor<_QualUp>,
616       __check_tuple_constructor_fail
617     >;
618 
619  public:
620   constexpr optional() noexcept {}
621   constexpr optional(const optional&) = default;
622   constexpr optional(optional&&) = default;
623   constexpr optional(nullopt_t) noexcept {}
624 
625   template <
626       class _InPlaceT, class... _Args,
627       class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>,
628                              is_constructible<value_type, _Args...>>::value>>
629   constexpr explicit optional(_InPlaceT, _Args&&... __args);
630 
631   template <class _Up, class... _Args,
632             class = enable_if_t<is_constructible_v<
633                 value_type, initializer_list<_Up>&, _Args...>>>
634   constexpr explicit optional(in_place_t, initializer_list<_Up> __il,
635                               _Args&&... __args);
636 
637   template <
638       class _Up = value_type,
639       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(),
640                 int> = 0>
641   constexpr optional(_Up&& __v);
642 
643   template <
644       class _Up,
645       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(),
646                 int> = 0>
647   constexpr explicit optional(_Up&& __v);
648 
649   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
650                                      template __enable_implicit<_Up>(),
651                                  int> = 0>
652   constexpr optional(const optional<_Up>& __v);
653 
654   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
655                                      template __enable_explicit<_Up>(),
656                                  int> = 0>
657   constexpr explicit optional(const optional<_Up>& __v);
658 
659   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
660                                      template __enable_implicit<_Up>(),
661                                  int> = 0>
662   constexpr optional(optional<_Up>&& __v);
663 
664   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
665                                      template __enable_explicit<_Up>(),
666                                  int> = 0>
667   constexpr explicit optional(optional<_Up>&& __v);
668 
669   constexpr optional& operator=(nullopt_t) noexcept;
670 
671   optional& operator=(const optional&);
672 
673   optional& operator=(optional&&);
674 
675   template <class _Up = value_type,
676             class = enable_if_t<_And<_IsNotSame<__uncvref_t<_Up>, optional>,
677                                    _Or<_IsNotSame<__uncvref_t<_Up>, value_type>,
678                                        _Not<is_scalar<value_type>>>,
679                                    is_constructible<value_type, _Up>,
680                                    is_assignable<value_type&, _Up>>::value>>
681   constexpr optional& operator=(_Up&& __v);
682 
683   template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>::
684                                      template __enable_assign<_Up>(),
685                                  int> = 0>
686   constexpr optional& operator=(const optional<_Up>& __v);
687 
688   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
689                                      template __enable_assign<_Up>(),
690                                  int> = 0>
691   constexpr optional& operator=(optional<_Up>&& __v);
692 
693   const _Tp& operator*() const&;
694   _Tp& operator*() &;
695   const _Tp&& operator*() const&&;
696   _Tp&& operator*() &&;
697 
698   const _Tp* operator->() const;
699   _Tp* operator->();
700 
701   const _Tp& value() const&;
702   _Tp& value() &;
703   const _Tp&& value() const&&;
704   _Tp&& value() &&;
705 
706   template <typename U>
707   constexpr _Tp value_or(U&& v) const&;
708   template <typename U>
709   _Tp value_or(U&& v) &&;
710 
711   template <typename... Args>
712   _Tp& emplace(Args&&... args);
713 
714   template <typename U, typename... Args>
715   _Tp& emplace(std::initializer_list<U> ilist, Args&&... args);
716 
717   using __base::reset;
718 
719   constexpr explicit operator bool() const noexcept;
720   using __base::has_value;
721 };
722 
723 template <typename T>
724 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
725 
726 template <typename T, typename... Args>
727 constexpr optional<T> make_optional(Args&&... args);
728 
729 template <typename T, typename U, typename... Args>
730 constexpr optional<T> make_optional(std::initializer_list<U> il,
731                                     Args&&... args);
732 
733 } // namespace std
734 )";
735 
736 static constexpr char AbslOptionalHeader[] = R"(
737 #include "absl_type_traits.h"
738 #include "std_initializer_list.h"
739 #include "std_type_traits.h"
740 #include "std_utility.h"
741 
742 namespace absl {
743 
744 struct nullopt_t {
745   constexpr explicit nullopt_t() {}
746 };
747 constexpr nullopt_t nullopt;
748 
749 struct in_place_t {};
750 constexpr in_place_t in_place;
751 
752 template <typename T>
753 class optional;
754 
755 namespace optional_internal {
756 
757 template <typename T, typename U>
758 struct is_constructible_convertible_from_optional
759     : std::integral_constant<
760           bool, std::is_constructible<T, optional<U>&>::value ||
761                     std::is_constructible<T, optional<U>&&>::value ||
762                     std::is_constructible<T, const optional<U>&>::value ||
763                     std::is_constructible<T, const optional<U>&&>::value ||
764                     std::is_convertible<optional<U>&, T>::value ||
765                     std::is_convertible<optional<U>&&, T>::value ||
766                     std::is_convertible<const optional<U>&, T>::value ||
767                     std::is_convertible<const optional<U>&&, T>::value> {};
768 
769 template <typename T, typename U>
770 struct is_constructible_convertible_assignable_from_optional
771     : std::integral_constant<
772           bool, is_constructible_convertible_from_optional<T, U>::value ||
773                     std::is_assignable<T&, optional<U>&>::value ||
774                     std::is_assignable<T&, optional<U>&&>::value ||
775                     std::is_assignable<T&, const optional<U>&>::value ||
776                     std::is_assignable<T&, const optional<U>&&>::value> {};
777 
778 }  // namespace optional_internal
779 
780 template <typename T>
781 class optional {
782  public:
783   constexpr optional() noexcept;
784 
785   constexpr optional(nullopt_t) noexcept;
786 
787   optional(const optional&) = default;
788 
789   optional(optional&&) = default;
790 
791   template <typename InPlaceT, typename... Args,
792             absl::enable_if_t<absl::conjunction<
793                 std::is_same<InPlaceT, in_place_t>,
794                 std::is_constructible<T, Args&&...>>::value>* = nullptr>
795   constexpr explicit optional(InPlaceT, Args&&... args);
796 
797   template <typename U, typename... Args,
798             typename = typename std::enable_if<std::is_constructible<
799                 T, std::initializer_list<U>&, Args&&...>::value>::type>
800   constexpr explicit optional(in_place_t, std::initializer_list<U> il,
801                               Args&&... args);
802 
803   template <
804       typename U = T,
805       typename std::enable_if<
806           absl::conjunction<absl::negation<std::is_same<
807                                 in_place_t, typename std::decay<U>::type>>,
808                             absl::negation<std::is_same<
809                                 optional<T>, typename std::decay<U>::type>>,
810                             std::is_convertible<U&&, T>,
811                             std::is_constructible<T, U&&>>::value,
812           bool>::type = false>
813   constexpr optional(U&& v);
814 
815   template <
816       typename U = T,
817       typename std::enable_if<
818           absl::conjunction<absl::negation<std::is_same<
819                                 in_place_t, typename std::decay<U>::type>>,
820                             absl::negation<std::is_same<
821                                 optional<T>, typename std::decay<U>::type>>,
822                             absl::negation<std::is_convertible<U&&, T>>,
823                             std::is_constructible<T, U&&>>::value,
824           bool>::type = false>
825   explicit constexpr optional(U&& v);
826 
827   template <typename U,
828             typename std::enable_if<
829                 absl::conjunction<
830                     absl::negation<std::is_same<T, U>>,
831                     std::is_constructible<T, const U&>,
832                     absl::negation<
833                         optional_internal::
834                             is_constructible_convertible_from_optional<T, U>>,
835                     std::is_convertible<const U&, T>>::value,
836                 bool>::type = false>
837   optional(const optional<U>& rhs);
838 
839   template <typename U,
840             typename std::enable_if<
841                 absl::conjunction<
842                     absl::negation<std::is_same<T, U>>,
843                     std::is_constructible<T, const U&>,
844                     absl::negation<
845                         optional_internal::
846                             is_constructible_convertible_from_optional<T, U>>,
847                     absl::negation<std::is_convertible<const U&, T>>>::value,
848                 bool>::type = false>
849   explicit optional(const optional<U>& rhs);
850 
851   template <
852       typename U,
853       typename std::enable_if<
854           absl::conjunction<
855               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
856               absl::negation<
857                   optional_internal::is_constructible_convertible_from_optional<
858                       T, U>>,
859               std::is_convertible<U&&, T>>::value,
860           bool>::type = false>
861   optional(optional<U>&& rhs);
862 
863   template <
864       typename U,
865       typename std::enable_if<
866           absl::conjunction<
867               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
868               absl::negation<
869                   optional_internal::is_constructible_convertible_from_optional<
870                       T, U>>,
871               absl::negation<std::is_convertible<U&&, T>>>::value,
872           bool>::type = false>
873   explicit optional(optional<U>&& rhs);
874 
875   optional& operator=(nullopt_t) noexcept;
876 
877   optional& operator=(const optional& src);
878 
879   optional& operator=(optional&& src);
880 
881   template <
882       typename U = T,
883       typename = typename std::enable_if<absl::conjunction<
884           absl::negation<
885               std::is_same<optional<T>, typename std::decay<U>::type>>,
886           absl::negation<
887               absl::conjunction<std::is_scalar<T>,
888                                 std::is_same<T, typename std::decay<U>::type>>>,
889           std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
890   optional& operator=(U&& v);
891 
892   template <
893       typename U,
894       typename = typename std::enable_if<absl::conjunction<
895           absl::negation<std::is_same<T, U>>,
896           std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
897           absl::negation<
898               optional_internal::
899                   is_constructible_convertible_assignable_from_optional<
900                       T, U>>>::value>::type>
901   optional& operator=(const optional<U>& rhs);
902 
903   template <typename U,
904             typename = typename std::enable_if<absl::conjunction<
905                 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
906                 std::is_assignable<T&, U>,
907                 absl::negation<
908                     optional_internal::
909                         is_constructible_convertible_assignable_from_optional<
910                             T, U>>>::value>::type>
911   optional& operator=(optional<U>&& rhs);
912 
913   const T& operator*() const&;
914   T& operator*() &;
915   const T&& operator*() const&&;
916   T&& operator*() &&;
917 
918   const T* operator->() const;
919   T* operator->();
920 
921   const T& value() const&;
922   T& value() &;
923   const T&& value() const&&;
924   T&& value() &&;
925 
926   template <typename U>
927   constexpr T value_or(U&& v) const&;
928   template <typename U>
929   T value_or(U&& v) &&;
930 
931   template <typename... Args>
932   T& emplace(Args&&... args);
933 
934   template <typename U, typename... Args>
935   T& emplace(std::initializer_list<U> ilist, Args&&... args);
936 
937   void reset() noexcept;
938 
939   constexpr explicit operator bool() const noexcept;
940   constexpr bool has_value() const noexcept;
941 };
942 
943 template <typename T>
944 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
945 
946 template <typename T, typename... Args>
947 constexpr optional<T> make_optional(Args&&... args);
948 
949 template <typename T, typename U, typename... Args>
950 constexpr optional<T> make_optional(std::initializer_list<U> il,
951                                     Args&&... args);
952 
953 } // namespace absl
954 )";
955 
956 static constexpr char BaseOptionalHeader[] = R"(
957 #include "std_initializer_list.h"
958 #include "std_type_traits.h"
959 #include "std_utility.h"
960 
961 namespace base {
962 
963 struct in_place_t {};
964 constexpr in_place_t in_place;
965 
966 struct nullopt_t {
967   constexpr explicit nullopt_t() {}
968 };
969 constexpr nullopt_t nullopt;
970 
971 template <typename T>
972 class Optional;
973 
974 namespace internal {
975 
976 template <typename T>
977 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
978 
979 template <typename T, typename U>
980 struct IsConvertibleFromOptional
981     : std::integral_constant<
982           bool, std::is_constructible<T, Optional<U>&>::value ||
983                     std::is_constructible<T, const Optional<U>&>::value ||
984                     std::is_constructible<T, Optional<U>&&>::value ||
985                     std::is_constructible<T, const Optional<U>&&>::value ||
986                     std::is_convertible<Optional<U>&, T>::value ||
987                     std::is_convertible<const Optional<U>&, T>::value ||
988                     std::is_convertible<Optional<U>&&, T>::value ||
989                     std::is_convertible<const Optional<U>&&, T>::value> {};
990 
991 template <typename T, typename U>
992 struct IsAssignableFromOptional
993     : std::integral_constant<
994           bool, IsConvertibleFromOptional<T, U>::value ||
995                     std::is_assignable<T&, Optional<U>&>::value ||
996                     std::is_assignable<T&, const Optional<U>&>::value ||
997                     std::is_assignable<T&, Optional<U>&&>::value ||
998                     std::is_assignable<T&, const Optional<U>&&>::value> {};
999 
1000 }  // namespace internal
1001 
1002 template <typename T>
1003 class Optional {
1004  public:
1005   using value_type = T;
1006 
1007   constexpr Optional() = default;
1008   constexpr Optional(const Optional& other) noexcept = default;
1009   constexpr Optional(Optional&& other) noexcept = default;
1010 
1011   constexpr Optional(nullopt_t);
1012 
1013   template <typename U,
1014             typename std::enable_if<
1015                 std::is_constructible<T, const U&>::value &&
1016                     !internal::IsConvertibleFromOptional<T, U>::value &&
1017                     std::is_convertible<const U&, T>::value,
1018                 bool>::type = false>
1019   Optional(const Optional<U>& other) noexcept;
1020 
1021   template <typename U,
1022             typename std::enable_if<
1023                 std::is_constructible<T, const U&>::value &&
1024                     !internal::IsConvertibleFromOptional<T, U>::value &&
1025                     !std::is_convertible<const U&, T>::value,
1026                 bool>::type = false>
1027   explicit Optional(const Optional<U>& other) noexcept;
1028 
1029   template <typename U,
1030             typename std::enable_if<
1031                 std::is_constructible<T, U&&>::value &&
1032                     !internal::IsConvertibleFromOptional<T, U>::value &&
1033                     std::is_convertible<U&&, T>::value,
1034                 bool>::type = false>
1035   Optional(Optional<U>&& other) noexcept;
1036 
1037   template <typename U,
1038             typename std::enable_if<
1039                 std::is_constructible<T, U&&>::value &&
1040                     !internal::IsConvertibleFromOptional<T, U>::value &&
1041                     !std::is_convertible<U&&, T>::value,
1042                 bool>::type = false>
1043   explicit Optional(Optional<U>&& other) noexcept;
1044 
1045   template <class... Args>
1046   constexpr explicit Optional(in_place_t, Args&&... args);
1047 
1048   template <class U, class... Args,
1049             class = typename std::enable_if<std::is_constructible<
1050                 value_type, std::initializer_list<U>&, Args...>::value>::type>
1051   constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
1052                               Args&&... args);
1053 
1054   template <
1055       typename U = value_type,
1056       typename std::enable_if<
1057           std::is_constructible<T, U&&>::value &&
1058               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1059               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1060               std::is_convertible<U&&, T>::value,
1061           bool>::type = false>
1062   constexpr Optional(U&& value);
1063 
1064   template <
1065       typename U = value_type,
1066       typename std::enable_if<
1067           std::is_constructible<T, U&&>::value &&
1068               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1069               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1070               !std::is_convertible<U&&, T>::value,
1071           bool>::type = false>
1072   constexpr explicit Optional(U&& value);
1073 
1074   Optional& operator=(const Optional& other) noexcept;
1075 
1076   Optional& operator=(Optional&& other) noexcept;
1077 
1078   Optional& operator=(nullopt_t);
1079 
1080   template <typename U>
1081   typename std::enable_if<
1082       !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1083           std::is_constructible<T, U>::value &&
1084           std::is_assignable<T&, U>::value &&
1085           (!std::is_scalar<T>::value ||
1086            !std::is_same<typename std::decay<U>::type, T>::value),
1087       Optional&>::type
1088   operator=(U&& value) noexcept;
1089 
1090   template <typename U>
1091   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1092                               std::is_constructible<T, const U&>::value &&
1093                               std::is_assignable<T&, const U&>::value,
1094                           Optional&>::type
1095   operator=(const Optional<U>& other) noexcept;
1096 
1097   template <typename U>
1098   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1099                               std::is_constructible<T, U>::value &&
1100                               std::is_assignable<T&, U>::value,
1101                           Optional&>::type
1102   operator=(Optional<U>&& other) noexcept;
1103 
1104   const T& operator*() const&;
1105   T& operator*() &;
1106   const T&& operator*() const&&;
1107   T&& operator*() &&;
1108 
1109   const T* operator->() const;
1110   T* operator->();
1111 
1112   const T& value() const&;
1113   T& value() &;
1114   const T&& value() const&&;
1115   T&& value() &&;
1116 
1117   template <typename U>
1118   constexpr T value_or(U&& v) const&;
1119   template <typename U>
1120   T value_or(U&& v) &&;
1121 
1122   template <typename... Args>
1123   T& emplace(Args&&... args);
1124 
1125   template <typename U, typename... Args>
1126   T& emplace(std::initializer_list<U> ilist, Args&&... args);
1127 
1128   void reset() noexcept;
1129 
1130   constexpr explicit operator bool() const noexcept;
1131   constexpr bool has_value() const noexcept;
1132 };
1133 
1134 template <typename T>
1135 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v);
1136 
1137 template <typename T, typename... Args>
1138 constexpr Optional<T> make_optional(Args&&... args);
1139 
1140 template <typename T, typename U, typename... Args>
1141 constexpr Optional<T> make_optional(std::initializer_list<U> il,
1142                                     Args&&... args);
1143 
1144 } // namespace base
1145 )";
1146 
1147 /// Converts `L` to string.
1148 static std::string ConvertToString(const SourceLocationsLattice &L,
1149                                    const ASTContext &Ctx) {
1150   return L.getSourceLocations().empty() ? "safe"
1151                                         : "unsafe: " + DebugString(L, Ctx);
1152 }
1153 
1154 /// Replaces all occurrences of `Pattern` in `S` with `Replacement`.
1155 static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern,
1156                                   const std::string &Replacement) {
1157   size_t Pos = 0;
1158   while (true) {
1159     Pos = S.find(Pattern, Pos);
1160     if (Pos == std::string::npos)
1161       break;
1162     S.replace(Pos, Pattern.size(), Replacement);
1163   }
1164 }
1165 
1166 struct OptionalTypeIdentifier {
1167   std::string NamespaceName;
1168   std::string TypeName;
1169 };
1170 
1171 class UncheckedOptionalAccessTest
1172     : public ::testing::TestWithParam<OptionalTypeIdentifier> {
1173 protected:
1174   template <typename LatticeChecksMatcher>
1175   void ExpectLatticeChecksFor(std::string SourceCode,
1176                               LatticeChecksMatcher MatchesLatticeChecks) {
1177     ExpectLatticeChecksFor(SourceCode, ast_matchers::hasName("target"),
1178                            MatchesLatticeChecks);
1179   }
1180 
1181 private:
1182   template <typename FuncDeclMatcher, typename LatticeChecksMatcher>
1183   void ExpectLatticeChecksFor(std::string SourceCode,
1184                               FuncDeclMatcher FuncMatcher,
1185                               LatticeChecksMatcher MatchesLatticeChecks) {
1186     ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName);
1187     ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName);
1188 
1189     std::vector<std::pair<std::string, std::string>> Headers;
1190     Headers.emplace_back("cstddef.h", CSDtdDefHeader);
1191     Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader);
1192     Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader);
1193     Headers.emplace_back("std_utility.h", StdUtilityHeader);
1194     Headers.emplace_back("std_optional.h", StdOptionalHeader);
1195     Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader);
1196     Headers.emplace_back("absl_optional.h", AbslOptionalHeader);
1197     Headers.emplace_back("base_optional.h", BaseOptionalHeader);
1198     Headers.emplace_back("unchecked_optional_access_test.h", R"(
1199       #include "absl_optional.h"
1200       #include "base_optional.h"
1201       #include "std_initializer_list.h"
1202       #include "std_optional.h"
1203       #include "std_utility.h"
1204 
1205       template <typename T>
1206       T Make();
1207     )");
1208     const tooling::FileContentMappings FileContents(Headers.begin(),
1209                                                     Headers.end());
1210     llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
1211         SourceCode, FuncMatcher,
1212         [](ASTContext &Ctx, Environment &) {
1213           return UncheckedOptionalAccessModel(Ctx);
1214         },
1215         [&MatchesLatticeChecks](
1216             llvm::ArrayRef<std::pair<
1217                 std::string, DataflowAnalysisState<SourceLocationsLattice>>>
1218                 CheckToLatticeMap,
1219             ASTContext &Ctx) {
1220           // FIXME: Consider using a matcher instead of translating
1221           // `CheckToLatticeMap` to `CheckToStringifiedLatticeMap`.
1222           std::vector<std::pair<std::string, std::string>>
1223               CheckToStringifiedLatticeMap;
1224           for (const auto &E : CheckToLatticeMap) {
1225             CheckToStringifiedLatticeMap.emplace_back(
1226                 E.first, ConvertToString(E.second.Lattice, Ctx));
1227           }
1228           EXPECT_THAT(CheckToStringifiedLatticeMap, MatchesLatticeChecks);
1229         },
1230         {"-fsyntax-only", "-std=c++17", "-Wno-undefined-inline"}, FileContents);
1231     if (Error)
1232       FAIL() << llvm::toString(std::move(Error));
1233   }
1234 };
1235 
1236 INSTANTIATE_TEST_SUITE_P(
1237     UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
1238     ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
1239                       OptionalTypeIdentifier{"absl", "optional"},
1240                       OptionalTypeIdentifier{"base", "Optional"}),
1241     [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
1242       return Info.param.NamespaceName;
1243     });
1244 
1245 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
1246   ExpectLatticeChecksFor(R"(
1247     void target() {
1248       (void)0;
1249       /*[[check]]*/
1250     }
1251   )",
1252                          UnorderedElementsAre(Pair("check", "safe")));
1253 }
1254 
1255 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
1256   ExpectLatticeChecksFor(
1257       R"(
1258     #include "unchecked_optional_access_test.h"
1259 
1260     void target($ns::$optional<int> opt) {
1261       opt.value();
1262       /*[[check]]*/
1263     }
1264   )",
1265       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1266 
1267   ExpectLatticeChecksFor(
1268       R"(
1269     #include "unchecked_optional_access_test.h"
1270 
1271     void target($ns::$optional<int> opt) {
1272       std::move(opt).value();
1273       /*[[check]]*/
1274     }
1275   )",
1276       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1277 }
1278 
1279 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
1280   ExpectLatticeChecksFor(
1281       R"(
1282     #include "unchecked_optional_access_test.h"
1283 
1284     void target($ns::$optional<int> opt) {
1285       *opt;
1286       /*[[check]]*/
1287     }
1288   )",
1289       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8")));
1290 
1291   ExpectLatticeChecksFor(
1292       R"(
1293     #include "unchecked_optional_access_test.h"
1294 
1295     void target($ns::$optional<int> opt) {
1296       *std::move(opt);
1297       /*[[check]]*/
1298     }
1299   )",
1300       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8")));
1301 }
1302 
1303 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
1304   ExpectLatticeChecksFor(
1305       R"(
1306     #include "unchecked_optional_access_test.h"
1307 
1308     struct Foo {
1309       void foo();
1310     };
1311 
1312     void target($ns::$optional<Foo> opt) {
1313       opt->foo();
1314       /*[[check]]*/
1315     }
1316   )",
1317       UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7")));
1318 
1319   ExpectLatticeChecksFor(
1320       R"(
1321     #include "unchecked_optional_access_test.h"
1322 
1323     struct Foo {
1324       void foo();
1325     };
1326 
1327     void target($ns::$optional<Foo> opt) {
1328       std::move(opt)->foo();
1329       /*[[check]]*/
1330     }
1331   )",
1332       UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7")));
1333 }
1334 
1335 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
1336   ExpectLatticeChecksFor(R"(
1337     #include "unchecked_optional_access_test.h"
1338 
1339     void target($ns::$optional<int> opt) {
1340       if (opt.has_value()) {
1341         opt.value();
1342         /*[[check]]*/
1343       }
1344     }
1345   )",
1346                          UnorderedElementsAre(Pair("check", "safe")));
1347 }
1348 
1349 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
1350   ExpectLatticeChecksFor(R"(
1351     #include "unchecked_optional_access_test.h"
1352 
1353     void target($ns::$optional<int> opt) {
1354       if (opt) {
1355         opt.value();
1356         /*[[check]]*/
1357       }
1358     }
1359   )",
1360                          UnorderedElementsAre(Pair("check", "safe")));
1361 }
1362 
1363 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
1364   ExpectLatticeChecksFor(
1365       R"(
1366     #include "unchecked_optional_access_test.h"
1367 
1368     void target() {
1369       Make<$ns::$optional<int>>().value();
1370       (void)0;
1371       /*[[check]]*/
1372     }
1373   )",
1374       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1375 
1376   ExpectLatticeChecksFor(
1377       R"(
1378     #include "unchecked_optional_access_test.h"
1379 
1380     void target($ns::$optional<int> opt) {
1381       std::move(opt).value();
1382       /*[[check]]*/
1383     }
1384   )",
1385       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1386 }
1387 
1388 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
1389   ExpectLatticeChecksFor(
1390       R"(
1391     #include "unchecked_optional_access_test.h"
1392 
1393     void target() {
1394       $ns::$optional<int> opt;
1395       opt.value();
1396       /*[[check]]*/
1397     }
1398   )",
1399       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1400 }
1401 
1402 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
1403   ExpectLatticeChecksFor(
1404       R"(
1405     #include "unchecked_optional_access_test.h"
1406 
1407     void target() {
1408       $ns::$optional<int> opt($ns::nullopt);
1409       opt.value();
1410       /*[[check]]*/
1411     }
1412   )",
1413       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1414 }
1415 
1416 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
1417   ExpectLatticeChecksFor(R"(
1418     #include "unchecked_optional_access_test.h"
1419 
1420     void target() {
1421       $ns::$optional<int> opt($ns::in_place, 3);
1422       opt.value();
1423       /*[[check]]*/
1424     }
1425   )",
1426                          UnorderedElementsAre(Pair("check", "safe")));
1427 
1428   ExpectLatticeChecksFor(R"(
1429     #include "unchecked_optional_access_test.h"
1430 
1431     struct Foo {};
1432 
1433     void target() {
1434       $ns::$optional<Foo> opt($ns::in_place);
1435       opt.value();
1436       /*[[check]]*/
1437     }
1438   )",
1439                          UnorderedElementsAre(Pair("check", "safe")));
1440 
1441   ExpectLatticeChecksFor(R"(
1442     #include "unchecked_optional_access_test.h"
1443 
1444     struct Foo {
1445       explicit Foo(int, bool);
1446     };
1447 
1448     void target() {
1449       $ns::$optional<Foo> opt($ns::in_place, 3, false);
1450       opt.value();
1451       /*[[check]]*/
1452     }
1453   )",
1454                          UnorderedElementsAre(Pair("check", "safe")));
1455 
1456   ExpectLatticeChecksFor(R"(
1457     #include "unchecked_optional_access_test.h"
1458 
1459     struct Foo {
1460       explicit Foo(std::initializer_list<int>);
1461     };
1462 
1463     void target() {
1464       $ns::$optional<Foo> opt($ns::in_place, {3});
1465       opt.value();
1466       /*[[check]]*/
1467     }
1468   )",
1469                          UnorderedElementsAre(Pair("check", "safe")));
1470 }
1471 
1472 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
1473   ExpectLatticeChecksFor(R"(
1474     #include "unchecked_optional_access_test.h"
1475 
1476     void target() {
1477       $ns::$optional<int> opt(21);
1478       opt.value();
1479       /*[[check]]*/
1480     }
1481   )",
1482                          UnorderedElementsAre(Pair("check", "safe")));
1483 
1484   ExpectLatticeChecksFor(R"(
1485     #include "unchecked_optional_access_test.h"
1486 
1487     void target() {
1488       $ns::$optional<int> opt = $ns::$optional<int>(21);
1489       opt.value();
1490       /*[[check]]*/
1491     }
1492   )",
1493                          UnorderedElementsAre(Pair("check", "safe")));
1494   ExpectLatticeChecksFor(R"(
1495     #include "unchecked_optional_access_test.h"
1496 
1497     void target() {
1498       $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1499       opt.value();
1500       /*[[check]]*/
1501     }
1502   )",
1503                          UnorderedElementsAre(Pair("check", "safe")));
1504 
1505   ExpectLatticeChecksFor(R"(
1506     #include "unchecked_optional_access_test.h"
1507 
1508     struct MyString {
1509       MyString(const char*);
1510     };
1511 
1512     void target() {
1513       $ns::$optional<MyString> opt("foo");
1514       opt.value();
1515       /*[[check]]*/
1516     }
1517   )",
1518                          UnorderedElementsAre(Pair("check", "safe")));
1519 
1520   ExpectLatticeChecksFor(R"(
1521     #include "unchecked_optional_access_test.h"
1522 
1523     struct Foo {};
1524 
1525     struct Bar {
1526       Bar(const Foo&);
1527     };
1528 
1529     void target() {
1530       $ns::$optional<Bar> opt(Make<Foo>());
1531       opt.value();
1532       /*[[check]]*/
1533     }
1534   )",
1535                          UnorderedElementsAre(Pair("check", "safe")));
1536 
1537   ExpectLatticeChecksFor(R"(
1538     #include "unchecked_optional_access_test.h"
1539 
1540     struct Foo {
1541       explicit Foo(int);
1542     };
1543 
1544     void target() {
1545       $ns::$optional<Foo> opt(3);
1546       opt.value();
1547       /*[[check]]*/
1548     }
1549   )",
1550                          UnorderedElementsAre(Pair("check", "safe")));
1551 }
1552 
1553 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
1554   ExpectLatticeChecksFor(
1555       R"(
1556     #include "unchecked_optional_access_test.h"
1557 
1558     struct Foo {};
1559 
1560     struct Bar {
1561       Bar(const Foo&);
1562     };
1563 
1564     void target() {
1565       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1566       opt.value();
1567       /*[[check]]*/
1568     }
1569   )",
1570       UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7")));
1571 
1572   ExpectLatticeChecksFor(
1573       R"(
1574     #include "unchecked_optional_access_test.h"
1575 
1576     struct Foo {};
1577 
1578     struct Bar {
1579       explicit Bar(const Foo&);
1580     };
1581 
1582     void target() {
1583       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1584       opt.value();
1585       /*[[check]]*/
1586     }
1587   )",
1588       UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7")));
1589 
1590   ExpectLatticeChecksFor(
1591       R"(
1592     #include "unchecked_optional_access_test.h"
1593 
1594     struct Foo {};
1595 
1596     struct Bar {
1597       Bar(const Foo&);
1598     };
1599 
1600     void target() {
1601       $ns::$optional<Foo> opt1 = $ns::nullopt;
1602       $ns::$optional<Bar> opt2(opt1);
1603       opt2.value();
1604       /*[[check]]*/
1605     }
1606   )",
1607       UnorderedElementsAre(Pair("check", "unsafe: input.cc:13:7")));
1608 
1609   ExpectLatticeChecksFor(R"(
1610     #include "unchecked_optional_access_test.h"
1611 
1612     struct Foo {};
1613 
1614     struct Bar {
1615       Bar(const Foo&);
1616     };
1617 
1618     void target() {
1619       $ns::$optional<Foo> opt1(Make<Foo>());
1620       $ns::$optional<Bar> opt2(opt1);
1621       opt2.value();
1622       /*[[check]]*/
1623     }
1624   )",
1625                          UnorderedElementsAre(Pair("check", "safe")));
1626 
1627   ExpectLatticeChecksFor(R"(
1628     #include "unchecked_optional_access_test.h"
1629 
1630     struct Foo {};
1631 
1632     struct Bar {
1633       explicit Bar(const Foo&);
1634     };
1635 
1636     void target() {
1637       $ns::$optional<Foo> opt1(Make<Foo>());
1638       $ns::$optional<Bar> opt2(opt1);
1639       opt2.value();
1640       /*[[check]]*/
1641     }
1642   )",
1643                          UnorderedElementsAre(Pair("check", "safe")));
1644 }
1645 
1646 TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
1647   ExpectLatticeChecksFor(R"(
1648     #include "unchecked_optional_access_test.h"
1649 
1650     void target() {
1651       $ns::$optional<int> opt = $ns::make_optional(0);
1652       opt.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       Foo(int, int);
1663     };
1664 
1665     void target() {
1666       $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1667       opt.value();
1668       /*[[check]]*/
1669     }
1670   )",
1671                          UnorderedElementsAre(Pair("check", "safe")));
1672 
1673   ExpectLatticeChecksFor(R"(
1674     #include "unchecked_optional_access_test.h"
1675 
1676     struct Foo {
1677       constexpr Foo(std::initializer_list<char>);
1678     };
1679 
1680     void target() {
1681       char a = 'a';
1682       $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1683       opt.value();
1684       /*[[check]]*/
1685     }
1686   )",
1687                          UnorderedElementsAre(Pair("check", "safe")));
1688 }
1689 
1690 TEST_P(UncheckedOptionalAccessTest, ValueOr) {
1691   ExpectLatticeChecksFor(R"(
1692     #include "unchecked_optional_access_test.h"
1693 
1694     void target() {
1695       $ns::$optional<int> opt;
1696       opt.value_or(0);
1697       (void)0;
1698       /*[[check]]*/
1699     }
1700   )",
1701                          UnorderedElementsAre(Pair("check", "safe")));
1702 }
1703 
1704 TEST_P(UncheckedOptionalAccessTest, Emplace) {
1705   ExpectLatticeChecksFor(R"(
1706     #include "unchecked_optional_access_test.h"
1707 
1708     void target() {
1709       $ns::$optional<int> opt;
1710       opt.emplace(0);
1711       opt.value();
1712       /*[[check]]*/
1713     }
1714   )",
1715                          UnorderedElementsAre(Pair("check", "safe")));
1716 
1717   ExpectLatticeChecksFor(R"(
1718     #include "unchecked_optional_access_test.h"
1719 
1720     void target($ns::$optional<int> *opt) {
1721       opt->emplace(0);
1722       opt->value();
1723       /*[[check]]*/
1724     }
1725   )",
1726                          UnorderedElementsAre(Pair("check", "safe")));
1727 
1728   // FIXME: Add tests that call `emplace` in conditional branches.
1729 }
1730 
1731 TEST_P(UncheckedOptionalAccessTest, Reset) {
1732   ExpectLatticeChecksFor(
1733       R"(
1734     #include "unchecked_optional_access_test.h"
1735 
1736     void target() {
1737       $ns::$optional<int> opt = $ns::make_optional(0);
1738       opt.reset();
1739       opt.value();
1740       /*[[check]]*/
1741     }
1742   )",
1743       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7")));
1744 
1745   ExpectLatticeChecksFor(
1746       R"(
1747     #include "unchecked_optional_access_test.h"
1748 
1749     void target($ns::$optional<int> &opt) {
1750       if (opt.has_value()) {
1751         opt.reset();
1752         opt.value();
1753         /*[[check]]*/
1754       }
1755     }
1756   )",
1757       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:9")));
1758 
1759   // FIXME: Add tests that call `reset` in conditional branches.
1760 }
1761 
1762 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) {
1763   ExpectLatticeChecksFor(R"(
1764     #include "unchecked_optional_access_test.h"
1765 
1766     struct Foo {};
1767 
1768     void target() {
1769       $ns::$optional<Foo> opt;
1770       opt = Foo();
1771       opt.value();
1772       /*[[check]]*/
1773     }
1774   )",
1775                          UnorderedElementsAre(Pair("check", "safe")));
1776 
1777   ExpectLatticeChecksFor(R"(
1778     #include "unchecked_optional_access_test.h"
1779 
1780     struct Foo {};
1781 
1782     void target() {
1783       $ns::$optional<Foo> opt;
1784       (opt = Foo()).value();
1785       (void)0;
1786       /*[[check]]*/
1787     }
1788   )",
1789                          UnorderedElementsAre(Pair("check", "safe")));
1790 
1791   ExpectLatticeChecksFor(R"(
1792     #include "unchecked_optional_access_test.h"
1793 
1794     struct MyString {
1795       MyString(const char*);
1796     };
1797 
1798     void target() {
1799       $ns::$optional<MyString> opt;
1800       opt = "foo";
1801       opt.value();
1802       /*[[check]]*/
1803     }
1804   )",
1805                          UnorderedElementsAre(Pair("check", "safe")));
1806 
1807   ExpectLatticeChecksFor(R"(
1808     #include "unchecked_optional_access_test.h"
1809 
1810     struct MyString {
1811       MyString(const char*);
1812     };
1813 
1814     void target() {
1815       $ns::$optional<MyString> opt;
1816       (opt = "foo").value();
1817       /*[[check]]*/
1818     }
1819   )",
1820                          UnorderedElementsAre(Pair("check", "safe")));
1821 }
1822 
1823 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) {
1824   ExpectLatticeChecksFor(
1825       R"(
1826     #include "unchecked_optional_access_test.h"
1827 
1828     struct Foo {};
1829 
1830     struct Bar {
1831       Bar(const Foo&);
1832     };
1833 
1834     void target() {
1835       $ns::$optional<Foo> opt1 = Foo();
1836       $ns::$optional<Bar> opt2;
1837       opt2 = opt1;
1838       opt2.value();
1839       /*[[check]]*/
1840     }
1841   )",
1842       UnorderedElementsAre(Pair("check", "safe")));
1843 
1844   ExpectLatticeChecksFor(
1845       R"(
1846     #include "unchecked_optional_access_test.h"
1847 
1848     struct Foo {};
1849 
1850     struct Bar {
1851       Bar(const Foo&);
1852     };
1853 
1854     void target() {
1855       $ns::$optional<Foo> opt1;
1856       $ns::$optional<Bar> opt2;
1857       if (opt2.has_value()) {
1858         opt2 = opt1;
1859         opt2.value();
1860         /*[[check]]*/
1861       }
1862     }
1863   )",
1864       UnorderedElementsAre(Pair("check", "unsafe: input.cc:15:9")));
1865 
1866   ExpectLatticeChecksFor(
1867       R"(
1868     #include "unchecked_optional_access_test.h"
1869 
1870     struct Foo {};
1871 
1872     struct Bar {
1873       Bar(const Foo&);
1874     };
1875 
1876     void target() {
1877       $ns::$optional<Foo> opt1 = Foo();
1878       $ns::$optional<Bar> opt2;
1879       (opt2 = opt1).value();
1880       (void)0;
1881       /*[[check]]*/
1882     }
1883   )",
1884       UnorderedElementsAre(Pair("check", "safe")));
1885 }
1886 
1887 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) {
1888   ExpectLatticeChecksFor(
1889       R"(
1890     #include "unchecked_optional_access_test.h"
1891 
1892     void target() {
1893       $ns::$optional<int> opt = 3;
1894       opt = $ns::nullopt;
1895       opt.value();
1896       /*[[check]]*/
1897     }
1898   )",
1899       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7")));
1900 
1901   ExpectLatticeChecksFor(
1902       R"(
1903     #include "unchecked_optional_access_test.h"
1904 
1905     void target() {
1906       $ns::$optional<int> opt = 3;
1907       (opt = $ns::nullopt).value();
1908       /*[[check]]*/
1909     }
1910   )",
1911       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1912 }
1913 
1914 // FIXME: Add support for:
1915 // - constructors (copy, move)
1916 // - assignment operators (default, copy, move)
1917 // - swap
1918 // - invalidation (passing optional by non-const reference/pointer)
1919 // - `value_or(nullptr) != nullptr`, `value_or(0) != 0`, `value_or("").empty()`
1920 // - nested `optional` values
1921