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