xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (revision 2ddd57ae1ec42c4aad8e70645cff82c877a94e3f)
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(Ctx);
1223         },
1224         [&MatchesLatticeChecks](
1225             llvm::ArrayRef<std::pair<
1226                 std::string, DataflowAnalysisState<SourceLocationsLattice>>>
1227                 CheckToLatticeMap,
1228             ASTContext &Ctx) {
1229           // FIXME: Consider using a matcher instead of translating
1230           // `CheckToLatticeMap` to `CheckToStringifiedLatticeMap`.
1231           std::vector<std::pair<std::string, std::string>>
1232               CheckToStringifiedLatticeMap;
1233           for (const auto &E : CheckToLatticeMap) {
1234             CheckToStringifiedLatticeMap.emplace_back(
1235                 E.first, ConvertToString(E.second.Lattice, Ctx));
1236           }
1237           EXPECT_THAT(CheckToStringifiedLatticeMap, MatchesLatticeChecks);
1238         },
1239         {"-fsyntax-only", "-std=c++17", "-Wno-undefined-inline"}, FileContents);
1240     if (Error)
1241       FAIL() << llvm::toString(std::move(Error));
1242   }
1243 };
1244 
1245 INSTANTIATE_TEST_SUITE_P(
1246     UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
1247     ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
1248                       OptionalTypeIdentifier{"absl", "optional"},
1249                       OptionalTypeIdentifier{"base", "Optional"}),
1250     [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
1251       return Info.param.NamespaceName;
1252     });
1253 
1254 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
1255   ExpectLatticeChecksFor(R"(
1256     void target() {
1257       (void)0;
1258       /*[[check]]*/
1259     }
1260   )",
1261                          UnorderedElementsAre(Pair("check", "safe")));
1262 }
1263 
1264 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
1265   ExpectLatticeChecksFor(
1266       R"(
1267     #include "unchecked_optional_access_test.h"
1268 
1269     void target($ns::$optional<int> opt) {
1270       opt.value();
1271       /*[[check]]*/
1272     }
1273   )",
1274       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1275 
1276   ExpectLatticeChecksFor(
1277       R"(
1278     #include "unchecked_optional_access_test.h"
1279 
1280     void target($ns::$optional<int> opt) {
1281       std::move(opt).value();
1282       /*[[check]]*/
1283     }
1284   )",
1285       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1286 }
1287 
1288 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
1289   ExpectLatticeChecksFor(
1290       R"(
1291     #include "unchecked_optional_access_test.h"
1292 
1293     void target($ns::$optional<int> opt) {
1294       *opt;
1295       /*[[check]]*/
1296     }
1297   )",
1298       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8")));
1299 
1300   ExpectLatticeChecksFor(
1301       R"(
1302     #include "unchecked_optional_access_test.h"
1303 
1304     void target($ns::$optional<int> opt) {
1305       *std::move(opt);
1306       /*[[check]]*/
1307     }
1308   )",
1309       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8")));
1310 }
1311 
1312 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
1313   ExpectLatticeChecksFor(
1314       R"(
1315     #include "unchecked_optional_access_test.h"
1316 
1317     struct Foo {
1318       void foo();
1319     };
1320 
1321     void target($ns::$optional<Foo> opt) {
1322       opt->foo();
1323       /*[[check]]*/
1324     }
1325   )",
1326       UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7")));
1327 
1328   ExpectLatticeChecksFor(
1329       R"(
1330     #include "unchecked_optional_access_test.h"
1331 
1332     struct Foo {
1333       void foo();
1334     };
1335 
1336     void target($ns::$optional<Foo> opt) {
1337       std::move(opt)->foo();
1338       /*[[check]]*/
1339     }
1340   )",
1341       UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7")));
1342 }
1343 
1344 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
1345   ExpectLatticeChecksFor(R"(
1346     #include "unchecked_optional_access_test.h"
1347 
1348     void target($ns::$optional<int> opt) {
1349       if (opt.has_value()) {
1350         opt.value();
1351         /*[[check]]*/
1352       }
1353     }
1354   )",
1355                          UnorderedElementsAre(Pair("check", "safe")));
1356 }
1357 
1358 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
1359   ExpectLatticeChecksFor(R"(
1360     #include "unchecked_optional_access_test.h"
1361 
1362     void target($ns::$optional<int> opt) {
1363       if (opt) {
1364         opt.value();
1365         /*[[check]]*/
1366       }
1367     }
1368   )",
1369                          UnorderedElementsAre(Pair("check", "safe")));
1370 }
1371 
1372 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
1373   ExpectLatticeChecksFor(
1374       R"(
1375     #include "unchecked_optional_access_test.h"
1376 
1377     void target() {
1378       Make<$ns::$optional<int>>().value();
1379       (void)0;
1380       /*[[check]]*/
1381     }
1382   )",
1383       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1384 
1385   ExpectLatticeChecksFor(
1386       R"(
1387     #include "unchecked_optional_access_test.h"
1388 
1389     void target($ns::$optional<int> opt) {
1390       std::move(opt).value();
1391       /*[[check]]*/
1392     }
1393   )",
1394       UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7")));
1395 }
1396 
1397 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
1398   ExpectLatticeChecksFor(
1399       R"(
1400     #include "unchecked_optional_access_test.h"
1401 
1402     void target() {
1403       $ns::$optional<int> opt;
1404       opt.value();
1405       /*[[check]]*/
1406     }
1407   )",
1408       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1409 }
1410 
1411 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
1412   ExpectLatticeChecksFor(
1413       R"(
1414     #include "unchecked_optional_access_test.h"
1415 
1416     void target() {
1417       $ns::$optional<int> opt($ns::nullopt);
1418       opt.value();
1419       /*[[check]]*/
1420     }
1421   )",
1422       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1423 }
1424 
1425 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
1426   ExpectLatticeChecksFor(R"(
1427     #include "unchecked_optional_access_test.h"
1428 
1429     void target() {
1430       $ns::$optional<int> opt($ns::in_place, 3);
1431       opt.value();
1432       /*[[check]]*/
1433     }
1434   )",
1435                          UnorderedElementsAre(Pair("check", "safe")));
1436 
1437   ExpectLatticeChecksFor(R"(
1438     #include "unchecked_optional_access_test.h"
1439 
1440     struct Foo {};
1441 
1442     void target() {
1443       $ns::$optional<Foo> opt($ns::in_place);
1444       opt.value();
1445       /*[[check]]*/
1446     }
1447   )",
1448                          UnorderedElementsAre(Pair("check", "safe")));
1449 
1450   ExpectLatticeChecksFor(R"(
1451     #include "unchecked_optional_access_test.h"
1452 
1453     struct Foo {
1454       explicit Foo(int, bool);
1455     };
1456 
1457     void target() {
1458       $ns::$optional<Foo> opt($ns::in_place, 3, false);
1459       opt.value();
1460       /*[[check]]*/
1461     }
1462   )",
1463                          UnorderedElementsAre(Pair("check", "safe")));
1464 
1465   ExpectLatticeChecksFor(R"(
1466     #include "unchecked_optional_access_test.h"
1467 
1468     struct Foo {
1469       explicit Foo(std::initializer_list<int>);
1470     };
1471 
1472     void target() {
1473       $ns::$optional<Foo> opt($ns::in_place, {3});
1474       opt.value();
1475       /*[[check]]*/
1476     }
1477   )",
1478                          UnorderedElementsAre(Pair("check", "safe")));
1479 }
1480 
1481 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
1482   ExpectLatticeChecksFor(R"(
1483     #include "unchecked_optional_access_test.h"
1484 
1485     void target() {
1486       $ns::$optional<int> opt(21);
1487       opt.value();
1488       /*[[check]]*/
1489     }
1490   )",
1491                          UnorderedElementsAre(Pair("check", "safe")));
1492 
1493   ExpectLatticeChecksFor(R"(
1494     #include "unchecked_optional_access_test.h"
1495 
1496     void target() {
1497       $ns::$optional<int> opt = $ns::$optional<int>(21);
1498       opt.value();
1499       /*[[check]]*/
1500     }
1501   )",
1502                          UnorderedElementsAre(Pair("check", "safe")));
1503   ExpectLatticeChecksFor(R"(
1504     #include "unchecked_optional_access_test.h"
1505 
1506     void target() {
1507       $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1508       opt.value();
1509       /*[[check]]*/
1510     }
1511   )",
1512                          UnorderedElementsAre(Pair("check", "safe")));
1513 
1514   ExpectLatticeChecksFor(R"(
1515     #include "unchecked_optional_access_test.h"
1516 
1517     struct MyString {
1518       MyString(const char*);
1519     };
1520 
1521     void target() {
1522       $ns::$optional<MyString> opt("foo");
1523       opt.value();
1524       /*[[check]]*/
1525     }
1526   )",
1527                          UnorderedElementsAre(Pair("check", "safe")));
1528 
1529   ExpectLatticeChecksFor(R"(
1530     #include "unchecked_optional_access_test.h"
1531 
1532     struct Foo {};
1533 
1534     struct Bar {
1535       Bar(const Foo&);
1536     };
1537 
1538     void target() {
1539       $ns::$optional<Bar> opt(Make<Foo>());
1540       opt.value();
1541       /*[[check]]*/
1542     }
1543   )",
1544                          UnorderedElementsAre(Pair("check", "safe")));
1545 
1546   ExpectLatticeChecksFor(R"(
1547     #include "unchecked_optional_access_test.h"
1548 
1549     struct Foo {
1550       explicit Foo(int);
1551     };
1552 
1553     void target() {
1554       $ns::$optional<Foo> opt(3);
1555       opt.value();
1556       /*[[check]]*/
1557     }
1558   )",
1559                          UnorderedElementsAre(Pair("check", "safe")));
1560 }
1561 
1562 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
1563   ExpectLatticeChecksFor(
1564       R"(
1565     #include "unchecked_optional_access_test.h"
1566 
1567     struct Foo {};
1568 
1569     struct Bar {
1570       Bar(const Foo&);
1571     };
1572 
1573     void target() {
1574       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1575       opt.value();
1576       /*[[check]]*/
1577     }
1578   )",
1579       UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7")));
1580 
1581   ExpectLatticeChecksFor(
1582       R"(
1583     #include "unchecked_optional_access_test.h"
1584 
1585     struct Foo {};
1586 
1587     struct Bar {
1588       explicit Bar(const Foo&);
1589     };
1590 
1591     void target() {
1592       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1593       opt.value();
1594       /*[[check]]*/
1595     }
1596   )",
1597       UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7")));
1598 
1599   ExpectLatticeChecksFor(
1600       R"(
1601     #include "unchecked_optional_access_test.h"
1602 
1603     struct Foo {};
1604 
1605     struct Bar {
1606       Bar(const Foo&);
1607     };
1608 
1609     void target() {
1610       $ns::$optional<Foo> opt1 = $ns::nullopt;
1611       $ns::$optional<Bar> opt2(opt1);
1612       opt2.value();
1613       /*[[check]]*/
1614     }
1615   )",
1616       UnorderedElementsAre(Pair("check", "unsafe: input.cc:13:7")));
1617 
1618   ExpectLatticeChecksFor(R"(
1619     #include "unchecked_optional_access_test.h"
1620 
1621     struct Foo {};
1622 
1623     struct Bar {
1624       Bar(const Foo&);
1625     };
1626 
1627     void target() {
1628       $ns::$optional<Foo> opt1(Make<Foo>());
1629       $ns::$optional<Bar> opt2(opt1);
1630       opt2.value();
1631       /*[[check]]*/
1632     }
1633   )",
1634                          UnorderedElementsAre(Pair("check", "safe")));
1635 
1636   ExpectLatticeChecksFor(R"(
1637     #include "unchecked_optional_access_test.h"
1638 
1639     struct Foo {};
1640 
1641     struct Bar {
1642       explicit Bar(const Foo&);
1643     };
1644 
1645     void target() {
1646       $ns::$optional<Foo> opt1(Make<Foo>());
1647       $ns::$optional<Bar> opt2(opt1);
1648       opt2.value();
1649       /*[[check]]*/
1650     }
1651   )",
1652                          UnorderedElementsAre(Pair("check", "safe")));
1653 }
1654 
1655 TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
1656   ExpectLatticeChecksFor(R"(
1657     #include "unchecked_optional_access_test.h"
1658 
1659     void target() {
1660       $ns::$optional<int> opt = $ns::make_optional(0);
1661       opt.value();
1662       /*[[check]]*/
1663     }
1664   )",
1665                          UnorderedElementsAre(Pair("check", "safe")));
1666 
1667   ExpectLatticeChecksFor(R"(
1668     #include "unchecked_optional_access_test.h"
1669 
1670     struct Foo {
1671       Foo(int, int);
1672     };
1673 
1674     void target() {
1675       $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1676       opt.value();
1677       /*[[check]]*/
1678     }
1679   )",
1680                          UnorderedElementsAre(Pair("check", "safe")));
1681 
1682   ExpectLatticeChecksFor(R"(
1683     #include "unchecked_optional_access_test.h"
1684 
1685     struct Foo {
1686       constexpr Foo(std::initializer_list<char>);
1687     };
1688 
1689     void target() {
1690       char a = 'a';
1691       $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1692       opt.value();
1693       /*[[check]]*/
1694     }
1695   )",
1696                          UnorderedElementsAre(Pair("check", "safe")));
1697 }
1698 
1699 TEST_P(UncheckedOptionalAccessTest, ValueOr) {
1700   ExpectLatticeChecksFor(R"(
1701     #include "unchecked_optional_access_test.h"
1702 
1703     void target() {
1704       $ns::$optional<int> opt;
1705       opt.value_or(0);
1706       (void)0;
1707       /*[[check]]*/
1708     }
1709   )",
1710                          UnorderedElementsAre(Pair("check", "safe")));
1711 }
1712 
1713 TEST_P(UncheckedOptionalAccessTest, Emplace) {
1714   ExpectLatticeChecksFor(R"(
1715     #include "unchecked_optional_access_test.h"
1716 
1717     void target() {
1718       $ns::$optional<int> opt;
1719       opt.emplace(0);
1720       opt.value();
1721       /*[[check]]*/
1722     }
1723   )",
1724                          UnorderedElementsAre(Pair("check", "safe")));
1725 
1726   ExpectLatticeChecksFor(R"(
1727     #include "unchecked_optional_access_test.h"
1728 
1729     void target($ns::$optional<int> *opt) {
1730       opt->emplace(0);
1731       opt->value();
1732       /*[[check]]*/
1733     }
1734   )",
1735                          UnorderedElementsAre(Pair("check", "safe")));
1736 
1737   // FIXME: Add tests that call `emplace` in conditional branches.
1738 }
1739 
1740 TEST_P(UncheckedOptionalAccessTest, Reset) {
1741   ExpectLatticeChecksFor(
1742       R"(
1743     #include "unchecked_optional_access_test.h"
1744 
1745     void target() {
1746       $ns::$optional<int> opt = $ns::make_optional(0);
1747       opt.reset();
1748       opt.value();
1749       /*[[check]]*/
1750     }
1751   )",
1752       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7")));
1753 
1754   ExpectLatticeChecksFor(
1755       R"(
1756     #include "unchecked_optional_access_test.h"
1757 
1758     void target($ns::$optional<int> &opt) {
1759       if (opt.has_value()) {
1760         opt.reset();
1761         opt.value();
1762         /*[[check]]*/
1763       }
1764     }
1765   )",
1766       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:9")));
1767 
1768   // FIXME: Add tests that call `reset` in conditional branches.
1769 }
1770 
1771 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) {
1772   ExpectLatticeChecksFor(R"(
1773     #include "unchecked_optional_access_test.h"
1774 
1775     struct Foo {};
1776 
1777     void target() {
1778       $ns::$optional<Foo> opt;
1779       opt = Foo();
1780       opt.value();
1781       /*[[check]]*/
1782     }
1783   )",
1784                          UnorderedElementsAre(Pair("check", "safe")));
1785 
1786   ExpectLatticeChecksFor(R"(
1787     #include "unchecked_optional_access_test.h"
1788 
1789     struct Foo {};
1790 
1791     void target() {
1792       $ns::$optional<Foo> opt;
1793       (opt = Foo()).value();
1794       (void)0;
1795       /*[[check]]*/
1796     }
1797   )",
1798                          UnorderedElementsAre(Pair("check", "safe")));
1799 
1800   ExpectLatticeChecksFor(R"(
1801     #include "unchecked_optional_access_test.h"
1802 
1803     struct MyString {
1804       MyString(const char*);
1805     };
1806 
1807     void target() {
1808       $ns::$optional<MyString> opt;
1809       opt = "foo";
1810       opt.value();
1811       /*[[check]]*/
1812     }
1813   )",
1814                          UnorderedElementsAre(Pair("check", "safe")));
1815 
1816   ExpectLatticeChecksFor(R"(
1817     #include "unchecked_optional_access_test.h"
1818 
1819     struct MyString {
1820       MyString(const char*);
1821     };
1822 
1823     void target() {
1824       $ns::$optional<MyString> opt;
1825       (opt = "foo").value();
1826       /*[[check]]*/
1827     }
1828   )",
1829                          UnorderedElementsAre(Pair("check", "safe")));
1830 }
1831 
1832 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) {
1833   ExpectLatticeChecksFor(
1834       R"(
1835     #include "unchecked_optional_access_test.h"
1836 
1837     struct Foo {};
1838 
1839     struct Bar {
1840       Bar(const Foo&);
1841     };
1842 
1843     void target() {
1844       $ns::$optional<Foo> opt1 = Foo();
1845       $ns::$optional<Bar> opt2;
1846       opt2 = opt1;
1847       opt2.value();
1848       /*[[check]]*/
1849     }
1850   )",
1851       UnorderedElementsAre(Pair("check", "safe")));
1852 
1853   ExpectLatticeChecksFor(
1854       R"(
1855     #include "unchecked_optional_access_test.h"
1856 
1857     struct Foo {};
1858 
1859     struct Bar {
1860       Bar(const Foo&);
1861     };
1862 
1863     void target() {
1864       $ns::$optional<Foo> opt1;
1865       $ns::$optional<Bar> opt2;
1866       if (opt2.has_value()) {
1867         opt2 = opt1;
1868         opt2.value();
1869         /*[[check]]*/
1870       }
1871     }
1872   )",
1873       UnorderedElementsAre(Pair("check", "unsafe: input.cc:15:9")));
1874 
1875   ExpectLatticeChecksFor(
1876       R"(
1877     #include "unchecked_optional_access_test.h"
1878 
1879     struct Foo {};
1880 
1881     struct Bar {
1882       Bar(const Foo&);
1883     };
1884 
1885     void target() {
1886       $ns::$optional<Foo> opt1 = Foo();
1887       $ns::$optional<Bar> opt2;
1888       (opt2 = opt1).value();
1889       (void)0;
1890       /*[[check]]*/
1891     }
1892   )",
1893       UnorderedElementsAre(Pair("check", "safe")));
1894 }
1895 
1896 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) {
1897   ExpectLatticeChecksFor(
1898       R"(
1899     #include "unchecked_optional_access_test.h"
1900 
1901     void target() {
1902       $ns::$optional<int> opt = 3;
1903       opt = $ns::nullopt;
1904       opt.value();
1905       /*[[check]]*/
1906     }
1907   )",
1908       UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7")));
1909 
1910   ExpectLatticeChecksFor(
1911       R"(
1912     #include "unchecked_optional_access_test.h"
1913 
1914     void target() {
1915       $ns::$optional<int> opt = 3;
1916       (opt = $ns::nullopt).value();
1917       /*[[check]]*/
1918     }
1919   )",
1920       UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7")));
1921 }
1922 
1923 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) {
1924   ExpectLatticeChecksFor(
1925       R"(
1926     #include "unchecked_optional_access_test.h"
1927 
1928     void target() {
1929       $ns::$optional<int> opt1 = $ns::nullopt;
1930       $ns::$optional<int> opt2 = 3;
1931 
1932       opt1.swap(opt2);
1933 
1934       opt1.value();
1935       /*[[check-1]]*/
1936 
1937       opt2.value();
1938       /*[[check-2]]*/
1939     }
1940   )",
1941       UnorderedElementsAre(Pair("check-1", "safe"),
1942                            Pair("check-2", "unsafe: input.cc:13:7")));
1943 
1944   ExpectLatticeChecksFor(
1945       R"(
1946     #include "unchecked_optional_access_test.h"
1947 
1948     void target() {
1949       $ns::$optional<int> opt1 = $ns::nullopt;
1950       $ns::$optional<int> opt2 = 3;
1951 
1952       opt2.swap(opt1);
1953 
1954       opt1.value();
1955       /*[[check-3]]*/
1956 
1957       opt2.value();
1958       /*[[check-4]]*/
1959     }
1960   )",
1961       UnorderedElementsAre(Pair("check-3", "safe"),
1962                            Pair("check-4", "unsafe: input.cc:13:7")));
1963 }
1964 
1965 TEST_P(UncheckedOptionalAccessTest, StdSwap) {
1966   ExpectLatticeChecksFor(
1967       R"(
1968     #include "unchecked_optional_access_test.h"
1969 
1970     void target() {
1971       $ns::$optional<int> opt1 = $ns::nullopt;
1972       $ns::$optional<int> opt2 = 3;
1973 
1974       std::swap(opt1, opt2);
1975 
1976       opt1.value();
1977       /*[[check-1]]*/
1978 
1979       opt2.value();
1980       /*[[check-2]]*/
1981     }
1982   )",
1983       UnorderedElementsAre(Pair("check-1", "safe"),
1984                            Pair("check-2", "unsafe: input.cc:13:7")));
1985 
1986   ExpectLatticeChecksFor(
1987       R"(
1988     #include "unchecked_optional_access_test.h"
1989 
1990     void target() {
1991       $ns::$optional<int> opt1 = $ns::nullopt;
1992       $ns::$optional<int> opt2 = 3;
1993 
1994       std::swap(opt2, opt1);
1995 
1996       opt1.value();
1997       /*[[check-3]]*/
1998 
1999       opt2.value();
2000       /*[[check-4]]*/
2001     }
2002   )",
2003       UnorderedElementsAre(Pair("check-3", "safe"),
2004                            Pair("check-4", "unsafe: input.cc:13:7")));
2005 }
2006 
2007 // FIXME: Add support for:
2008 // - constructors (copy, move)
2009 // - assignment operators (default, copy, move)
2010 // - invalidation (passing optional by non-const reference/pointer)
2011 // - `value_or(nullptr) != nullptr`, `value_or(0) != 0`, `value_or("").empty()`
2012 // - nested `optional` values
2013