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