xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (revision 72a28a3bf0b539bcdfd8f41905675ce6a890c0ac)
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/Basic/SourceLocation.h"
15 #include "clang/Frontend/TextDiagnostic.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "llvm/ADT/DenseSet.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/Support/Error.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include <optional>
23 #include <string>
24 #include <utility>
25 #include <vector>
26 
27 using namespace clang;
28 using namespace dataflow;
29 using namespace test;
30 
31 using ::testing::ContainerEq;
32 
33 // FIXME: Move header definitions in separate file(s).
34 static constexpr char CSDtdDefHeader[] = R"(
35 #ifndef CSTDDEF_H
36 #define CSTDDEF_H
37 
38 namespace std {
39 
40 typedef decltype(sizeof(char)) size_t;
41 
42 using nullptr_t = decltype(nullptr);
43 
44 } // namespace std
45 
46 #endif // CSTDDEF_H
47 )";
48 
49 static constexpr char StdTypeTraitsHeader[] = R"(
50 #ifndef STD_TYPE_TRAITS_H
51 #define STD_TYPE_TRAITS_H
52 
53 #include "cstddef.h"
54 
55 namespace std {
56 
57 template <typename T, T V>
58 struct integral_constant {
59   static constexpr T value = V;
60 };
61 
62 using true_type = integral_constant<bool, true>;
63 using false_type = integral_constant<bool, false>;
64 
65 template< class T > struct remove_reference      {typedef T type;};
66 template< class T > struct remove_reference<T&>  {typedef T type;};
67 template< class T > struct remove_reference<T&&> {typedef T type;};
68 
69 template <class T>
70   using remove_reference_t = typename remove_reference<T>::type;
71 
72 template <class T>
73 struct remove_extent {
74   typedef T type;
75 };
76 
77 template <class T>
78 struct remove_extent<T[]> {
79   typedef T type;
80 };
81 
82 template <class T, size_t N>
83 struct remove_extent<T[N]> {
84   typedef T type;
85 };
86 
87 template <class T>
88 struct is_array : false_type {};
89 
90 template <class T>
91 struct is_array<T[]> : true_type {};
92 
93 template <class T, size_t N>
94 struct is_array<T[N]> : true_type {};
95 
96 template <class>
97 struct is_function : false_type {};
98 
99 template <class Ret, class... Args>
100 struct is_function<Ret(Args...)> : true_type {};
101 
102 namespace detail {
103 
104 template <class T>
105 struct type_identity {
106   using type = T;
107 };  // or use type_identity (since C++20)
108 
109 template <class T>
110 auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>;
111 template <class T>
112 auto try_add_pointer(...) -> type_identity<T>;
113 
114 }  // namespace detail
115 
116 template <class T>
117 struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
118 
119 template <bool B, class T, class F>
120 struct conditional {
121   typedef T type;
122 };
123 
124 template <class T, class F>
125 struct conditional<false, T, F> {
126   typedef F type;
127 };
128 
129 template <class T>
130 struct remove_cv {
131   typedef T type;
132 };
133 template <class T>
134 struct remove_cv<const T> {
135   typedef T type;
136 };
137 template <class T>
138 struct remove_cv<volatile T> {
139   typedef T type;
140 };
141 template <class T>
142 struct remove_cv<const volatile T> {
143   typedef T type;
144 };
145 
146 template <class T>
147 using remove_cv_t = typename remove_cv<T>::type;
148 
149 template <class T>
150 struct decay {
151  private:
152   typedef typename remove_reference<T>::type U;
153 
154  public:
155   typedef typename conditional<
156       is_array<U>::value, typename remove_extent<U>::type*,
157       typename conditional<is_function<U>::value, typename add_pointer<U>::type,
158                            typename remove_cv<U>::type>::type>::type type;
159 };
160 
161 template <bool B, class T = void>
162 struct enable_if {};
163 
164 template <class T>
165 struct enable_if<true, T> {
166   typedef T type;
167 };
168 
169 template <bool B, class T = void>
170 using enable_if_t = typename enable_if<B, T>::type;
171 
172 template <class T, class U>
173 struct is_same : false_type {};
174 
175 template <class T>
176 struct is_same<T, T> : true_type {};
177 
178 template <class T>
179 struct is_void : is_same<void, typename remove_cv<T>::type> {};
180 
181 namespace detail {
182 
183 template <class T>
184 auto try_add_lvalue_reference(int) -> type_identity<T&>;
185 template <class T>
186 auto try_add_lvalue_reference(...) -> type_identity<T>;
187 
188 template <class T>
189 auto try_add_rvalue_reference(int) -> type_identity<T&&>;
190 template <class T>
191 auto try_add_rvalue_reference(...) -> type_identity<T>;
192 
193 }  // namespace detail
194 
195 template <class T>
196 struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {
197 };
198 
199 template <class T>
200 struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {
201 };
202 
203 template <class T>
204 typename add_rvalue_reference<T>::type declval() noexcept;
205 
206 namespace detail {
207 
208 template <class T>
209 auto test_returnable(int)
210     -> decltype(void(static_cast<T (*)()>(nullptr)), true_type{});
211 template <class>
212 auto test_returnable(...) -> false_type;
213 
214 template <class From, class To>
215 auto test_implicitly_convertible(int)
216     -> decltype(void(declval<void (&)(To)>()(declval<From>())), true_type{});
217 template <class, class>
218 auto test_implicitly_convertible(...) -> false_type;
219 
220 }  // namespace detail
221 
222 template <class From, class To>
223 struct is_convertible
224     : integral_constant<bool,
225                         (decltype(detail::test_returnable<To>(0))::value &&
226                          decltype(detail::test_implicitly_convertible<From, To>(
227                              0))::value) ||
228                             (is_void<From>::value && is_void<To>::value)> {};
229 
230 template <class From, class To>
231 inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
232 
233 template <class...>
234 using void_t = void;
235 
236 template <class, class T, class... Args>
237 struct is_constructible_ : false_type {};
238 
239 template <class T, class... Args>
240 struct is_constructible_<void_t<decltype(T(declval<Args>()...))>, T, Args...>
241     : true_type {};
242 
243 template <class T, class... Args>
244 using is_constructible = is_constructible_<void_t<>, T, Args...>;
245 
246 template <class T, class... Args>
247 inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
248 
249 template <class _Tp>
250 struct __uncvref {
251   typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type;
252 };
253 
254 template <class _Tp>
255 using __uncvref_t = typename __uncvref<_Tp>::type;
256 
257 template <bool _Val>
258 using _BoolConstant = integral_constant<bool, _Val>;
259 
260 template <class _Tp, class _Up>
261 using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>;
262 
263 template <class _Tp, class _Up>
264 using _IsNotSame = _BoolConstant<!__is_same(_Tp, _Up)>;
265 
266 template <bool>
267 struct _MetaBase;
268 template <>
269 struct _MetaBase<true> {
270   template <class _Tp, class _Up>
271   using _SelectImpl = _Tp;
272   template <template <class...> class _FirstFn, template <class...> class,
273             class... _Args>
274   using _SelectApplyImpl = _FirstFn<_Args...>;
275   template <class _First, class...>
276   using _FirstImpl = _First;
277   template <class, class _Second, class...>
278   using _SecondImpl = _Second;
279   template <class _Result, class _First, class... _Rest>
280   using _OrImpl =
281       typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>::
282           template _OrImpl<_First, _Rest...>;
283 };
284 
285 template <>
286 struct _MetaBase<false> {
287   template <class _Tp, class _Up>
288   using _SelectImpl = _Up;
289   template <template <class...> class, template <class...> class _SecondFn,
290             class... _Args>
291   using _SelectApplyImpl = _SecondFn<_Args...>;
292   template <class _Result, class...>
293   using _OrImpl = _Result;
294 };
295 
296 template <bool _Cond, class _IfRes, class _ElseRes>
297 using _If = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;
298 
299 template <class... _Rest>
300 using _Or = typename _MetaBase<sizeof...(_Rest) !=
301                                0>::template _OrImpl<false_type, _Rest...>;
302 
303 template <bool _Bp, class _Tp = void>
304 using __enable_if_t = typename enable_if<_Bp, _Tp>::type;
305 
306 template <class...>
307 using __expand_to_true = true_type;
308 template <class... _Pred>
309 __expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int);
310 template <class...>
311 false_type __and_helper(...);
312 template <class... _Pred>
313 using _And = decltype(__and_helper<_Pred...>(0));
314 
315 template <class _Pred>
316 struct _Not : _BoolConstant<!_Pred::value> {};
317 
318 struct __check_tuple_constructor_fail {
319   static constexpr bool __enable_explicit_default() { return false; }
320   static constexpr bool __enable_implicit_default() { return false; }
321   template <class...>
322   static constexpr bool __enable_explicit() {
323     return false;
324   }
325   template <class...>
326   static constexpr bool __enable_implicit() {
327     return false;
328   }
329 };
330 
331 template <typename, typename _Tp>
332 struct __select_2nd {
333   typedef _Tp type;
334 };
335 template <class _Tp, class _Arg>
336 typename __select_2nd<decltype((declval<_Tp>() = declval<_Arg>())),
337                       true_type>::type
338 __is_assignable_test(int);
339 template <class, class>
340 false_type __is_assignable_test(...);
341 template <class _Tp, class _Arg,
342           bool = is_void<_Tp>::value || is_void<_Arg>::value>
343 struct __is_assignable_imp
344     : public decltype((__is_assignable_test<_Tp, _Arg>(0))) {};
345 template <class _Tp, class _Arg>
346 struct __is_assignable_imp<_Tp, _Arg, true> : public false_type {};
347 template <class _Tp, class _Arg>
348 struct is_assignable : public __is_assignable_imp<_Tp, _Arg> {};
349 
350 template <class _Tp>
351 struct __libcpp_is_integral : public false_type {};
352 template <>
353 struct __libcpp_is_integral<bool> : public true_type {};
354 template <>
355 struct __libcpp_is_integral<char> : public true_type {};
356 template <>
357 struct __libcpp_is_integral<signed char> : public true_type {};
358 template <>
359 struct __libcpp_is_integral<unsigned char> : public true_type {};
360 template <>
361 struct __libcpp_is_integral<wchar_t> : public true_type {};
362 template <>
363 struct __libcpp_is_integral<short> : public true_type {};  // NOLINT
364 template <>
365 struct __libcpp_is_integral<unsigned short> : public true_type {};  // NOLINT
366 template <>
367 struct __libcpp_is_integral<int> : public true_type {};
368 template <>
369 struct __libcpp_is_integral<unsigned int> : public true_type {};
370 template <>
371 struct __libcpp_is_integral<long> : public true_type {};  // NOLINT
372 template <>
373 struct __libcpp_is_integral<unsigned long> : public true_type {};  // NOLINT
374 template <>
375 struct __libcpp_is_integral<long long> : public true_type {};  // NOLINT
376 template <>                                                    // NOLINTNEXTLINE
377 struct __libcpp_is_integral<unsigned long long> : public true_type {};
378 template <class _Tp>
379 struct is_integral
380     : public __libcpp_is_integral<typename remove_cv<_Tp>::type> {};
381 
382 template <class _Tp>
383 struct __libcpp_is_floating_point : public false_type {};
384 template <>
385 struct __libcpp_is_floating_point<float> : public true_type {};
386 template <>
387 struct __libcpp_is_floating_point<double> : public true_type {};
388 template <>
389 struct __libcpp_is_floating_point<long double> : public true_type {};
390 template <class _Tp>
391 struct is_floating_point
392     : public __libcpp_is_floating_point<typename remove_cv<_Tp>::type> {};
393 
394 template <class _Tp>
395 struct is_arithmetic
396     : public integral_constant<bool, is_integral<_Tp>::value ||
397                                          is_floating_point<_Tp>::value> {};
398 
399 template <class _Tp>
400 struct __libcpp_is_pointer : public false_type {};
401 template <class _Tp>
402 struct __libcpp_is_pointer<_Tp*> : public true_type {};
403 template <class _Tp>
404 struct is_pointer : public __libcpp_is_pointer<typename remove_cv<_Tp>::type> {
405 };
406 
407 template <class _Tp>
408 struct __libcpp_is_member_pointer : public false_type {};
409 template <class _Tp, class _Up>
410 struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type {};
411 template <class _Tp>
412 struct is_member_pointer
413     : public __libcpp_is_member_pointer<typename remove_cv<_Tp>::type> {};
414 
415 template <class _Tp>
416 struct __libcpp_union : public false_type {};
417 template <class _Tp>
418 struct is_union : public __libcpp_union<typename remove_cv<_Tp>::type> {};
419 
420 template <class T>
421 struct is_reference : false_type {};
422 template <class T>
423 struct is_reference<T&> : true_type {};
424 template <class T>
425 struct is_reference<T&&> : true_type {};
426 
427 template <class T>
428 inline constexpr bool is_reference_v = is_reference<T>::value;
429 
430 struct __two {
431   char __lx[2];
432 };
433 
434 namespace __is_class_imp {
435 template <class _Tp>
436 char __test(int _Tp::*);
437 template <class _Tp>
438 __two __test(...);
439 }  // namespace __is_class_imp
440 template <class _Tp>
441 struct is_class
442     : public integral_constant<bool,
443                                sizeof(__is_class_imp::__test<_Tp>(0)) == 1 &&
444                                    !is_union<_Tp>::value> {};
445 
446 template <class _Tp>
447 struct __is_nullptr_t_impl : public false_type {};
448 template <>
449 struct __is_nullptr_t_impl<nullptr_t> : public true_type {};
450 template <class _Tp>
451 struct __is_nullptr_t
452     : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
453 template <class _Tp>
454 struct is_null_pointer
455     : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
456 
457 template <class _Tp>
458 struct is_enum
459     : public integral_constant<
460           bool, !is_void<_Tp>::value && !is_integral<_Tp>::value &&
461                     !is_floating_point<_Tp>::value && !is_array<_Tp>::value &&
462                     !is_pointer<_Tp>::value && !is_reference<_Tp>::value &&
463                     !is_member_pointer<_Tp>::value && !is_union<_Tp>::value &&
464                     !is_class<_Tp>::value && !is_function<_Tp>::value> {};
465 
466 template <class _Tp>
467 struct is_scalar
468     : public integral_constant<
469           bool, is_arithmetic<_Tp>::value || is_member_pointer<_Tp>::value ||
470                     is_pointer<_Tp>::value || __is_nullptr_t<_Tp>::value ||
471                     is_enum<_Tp>::value> {};
472 template <>
473 struct is_scalar<nullptr_t> : public true_type {};
474 
475 } // namespace std
476 
477 #endif // STD_TYPE_TRAITS_H
478 )";
479 
480 static constexpr char AbslTypeTraitsHeader[] = R"(
481 #ifndef ABSL_TYPE_TRAITS_H
482 #define ABSL_TYPE_TRAITS_H
483 
484 #include "std_type_traits.h"
485 
486 namespace absl {
487 
488 template <typename... Ts>
489 struct conjunction : std::true_type {};
490 
491 template <typename T, typename... Ts>
492 struct conjunction<T, Ts...>
493     : std::conditional<T::value, conjunction<Ts...>, T>::type {};
494 
495 template <typename T>
496 struct conjunction<T> : T {};
497 
498 template <typename T>
499 struct negation : std::integral_constant<bool, !T::value> {};
500 
501 template <bool B, typename T = void>
502 using enable_if_t = typename std::enable_if<B, T>::type;
503 
504 } // namespace absl
505 
506 #endif // ABSL_TYPE_TRAITS_H
507 )";
508 
509 static constexpr char StdStringHeader[] = R"(
510 #ifndef STRING_H
511 #define STRING_H
512 
513 namespace std {
514 
515 struct string {
516   string(const char*);
517   ~string();
518   bool empty();
519 };
520 bool operator!=(const string &LHS, const char *RHS);
521 
522 } // namespace std
523 
524 #endif // STRING_H
525 )";
526 
527 static constexpr char StdUtilityHeader[] = R"(
528 #ifndef UTILITY_H
529 #define UTILITY_H
530 
531 #include "std_type_traits.h"
532 
533 namespace std {
534 
535 template <typename T>
536 constexpr remove_reference_t<T>&& move(T&& x);
537 
538 template <typename T>
539 void swap(T& a, T& b) noexcept;
540 
541 } // namespace std
542 
543 #endif // UTILITY_H
544 )";
545 
546 static constexpr char StdInitializerListHeader[] = R"(
547 #ifndef INITIALIZER_LIST_H
548 #define INITIALIZER_LIST_H
549 
550 namespace std {
551 
552 template <typename T>
553 class initializer_list {
554  public:
555   const T *a, *b;
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 template <typename T, typename U>
768 constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs);
769 template <typename T, typename U>
770 constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs);
771 
772 template <typename T>
773 constexpr bool operator==(const optional<T> &opt, nullopt_t);
774 
775 // C++20 and later do not define the following overloads because they are
776 // provided by rewritten candidates instead.
777 #if __cplusplus < 202002L
778 template <typename T>
779 constexpr bool operator==(nullopt_t, const optional<T> &opt);
780 template <typename T>
781 constexpr bool operator!=(const optional<T> &opt, nullopt_t);
782 template <typename T>
783 constexpr bool operator!=(nullopt_t, const optional<T> &opt);
784 #endif  // __cplusplus < 202002L
785 
786 template <typename T, typename U>
787 constexpr bool operator==(const optional<T> &opt, const U &value);
788 template <typename T, typename U>
789 constexpr bool operator==(const T &value, const optional<U> &opt);
790 template <typename T, typename U>
791 constexpr bool operator!=(const optional<T> &opt, const U &value);
792 template <typename T, typename U>
793 constexpr bool operator!=(const T &value, const optional<U> &opt);
794 
795 } // namespace std
796 )";
797 
798 static constexpr char AbslOptionalHeader[] = R"(
799 #include "absl_type_traits.h"
800 #include "std_initializer_list.h"
801 #include "std_type_traits.h"
802 #include "std_utility.h"
803 
804 namespace absl {
805 
806 struct nullopt_t {
807   constexpr explicit nullopt_t() {}
808 };
809 constexpr nullopt_t nullopt;
810 
811 struct in_place_t {};
812 constexpr in_place_t in_place;
813 
814 template <typename T>
815 class optional;
816 
817 namespace optional_internal {
818 
819 template <typename T, typename U>
820 struct is_constructible_convertible_from_optional
821     : std::integral_constant<
822           bool, std::is_constructible<T, optional<U>&>::value ||
823                     std::is_constructible<T, optional<U>&&>::value ||
824                     std::is_constructible<T, const optional<U>&>::value ||
825                     std::is_constructible<T, const optional<U>&&>::value ||
826                     std::is_convertible<optional<U>&, T>::value ||
827                     std::is_convertible<optional<U>&&, T>::value ||
828                     std::is_convertible<const optional<U>&, T>::value ||
829                     std::is_convertible<const optional<U>&&, T>::value> {};
830 
831 template <typename T, typename U>
832 struct is_constructible_convertible_assignable_from_optional
833     : std::integral_constant<
834           bool, is_constructible_convertible_from_optional<T, U>::value ||
835                     std::is_assignable<T&, optional<U>&>::value ||
836                     std::is_assignable<T&, optional<U>&&>::value ||
837                     std::is_assignable<T&, const optional<U>&>::value ||
838                     std::is_assignable<T&, const optional<U>&&>::value> {};
839 
840 }  // namespace optional_internal
841 
842 template <typename T>
843 class optional {
844  public:
845   constexpr optional() noexcept;
846 
847   constexpr optional(nullopt_t) noexcept;
848 
849   optional(const optional&) = default;
850 
851   optional(optional&&) = default;
852 
853   template <typename InPlaceT, typename... Args,
854             absl::enable_if_t<absl::conjunction<
855                 std::is_same<InPlaceT, in_place_t>,
856                 std::is_constructible<T, Args&&...>>::value>* = nullptr>
857   constexpr explicit optional(InPlaceT, Args&&... args);
858 
859   template <typename U, typename... Args,
860             typename = typename std::enable_if<std::is_constructible<
861                 T, std::initializer_list<U>&, Args&&...>::value>::type>
862   constexpr explicit optional(in_place_t, std::initializer_list<U> il,
863                               Args&&... args);
864 
865   template <
866       typename U = T,
867       typename std::enable_if<
868           absl::conjunction<absl::negation<std::is_same<
869                                 in_place_t, typename std::decay<U>::type>>,
870                             absl::negation<std::is_same<
871                                 optional<T>, typename std::decay<U>::type>>,
872                             std::is_convertible<U&&, T>,
873                             std::is_constructible<T, U&&>>::value,
874           bool>::type = false>
875   constexpr optional(U&& v);
876 
877   template <
878       typename U = T,
879       typename std::enable_if<
880           absl::conjunction<absl::negation<std::is_same<
881                                 in_place_t, typename std::decay<U>::type>>,
882                             absl::negation<std::is_same<
883                                 optional<T>, typename std::decay<U>::type>>,
884                             absl::negation<std::is_convertible<U&&, T>>,
885                             std::is_constructible<T, U&&>>::value,
886           bool>::type = false>
887   explicit constexpr optional(U&& v);
888 
889   template <typename U,
890             typename std::enable_if<
891                 absl::conjunction<
892                     absl::negation<std::is_same<T, U>>,
893                     std::is_constructible<T, const U&>,
894                     absl::negation<
895                         optional_internal::
896                             is_constructible_convertible_from_optional<T, U>>,
897                     std::is_convertible<const U&, T>>::value,
898                 bool>::type = false>
899   optional(const optional<U>& rhs);
900 
901   template <typename U,
902             typename std::enable_if<
903                 absl::conjunction<
904                     absl::negation<std::is_same<T, U>>,
905                     std::is_constructible<T, const U&>,
906                     absl::negation<
907                         optional_internal::
908                             is_constructible_convertible_from_optional<T, U>>,
909                     absl::negation<std::is_convertible<const U&, T>>>::value,
910                 bool>::type = false>
911   explicit optional(const optional<U>& rhs);
912 
913   template <
914       typename U,
915       typename std::enable_if<
916           absl::conjunction<
917               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
918               absl::negation<
919                   optional_internal::is_constructible_convertible_from_optional<
920                       T, U>>,
921               std::is_convertible<U&&, T>>::value,
922           bool>::type = false>
923   optional(optional<U>&& rhs);
924 
925   template <
926       typename U,
927       typename std::enable_if<
928           absl::conjunction<
929               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
930               absl::negation<
931                   optional_internal::is_constructible_convertible_from_optional<
932                       T, U>>,
933               absl::negation<std::is_convertible<U&&, T>>>::value,
934           bool>::type = false>
935   explicit optional(optional<U>&& rhs);
936 
937   optional& operator=(nullopt_t) noexcept;
938 
939   optional& operator=(const optional& src);
940 
941   optional& operator=(optional&& src);
942 
943   template <
944       typename U = T,
945       typename = typename std::enable_if<absl::conjunction<
946           absl::negation<
947               std::is_same<optional<T>, typename std::decay<U>::type>>,
948           absl::negation<
949               absl::conjunction<std::is_scalar<T>,
950                                 std::is_same<T, typename std::decay<U>::type>>>,
951           std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
952   optional& operator=(U&& v);
953 
954   template <
955       typename U,
956       typename = typename std::enable_if<absl::conjunction<
957           absl::negation<std::is_same<T, U>>,
958           std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
959           absl::negation<
960               optional_internal::
961                   is_constructible_convertible_assignable_from_optional<
962                       T, U>>>::value>::type>
963   optional& operator=(const optional<U>& rhs);
964 
965   template <typename U,
966             typename = typename std::enable_if<absl::conjunction<
967                 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
968                 std::is_assignable<T&, U>,
969                 absl::negation<
970                     optional_internal::
971                         is_constructible_convertible_assignable_from_optional<
972                             T, U>>>::value>::type>
973   optional& operator=(optional<U>&& rhs);
974 
975   const T& operator*() const&;
976   T& operator*() &;
977   const T&& operator*() const&&;
978   T&& operator*() &&;
979 
980   const T* operator->() const;
981   T* operator->();
982 
983   const T& value() const&;
984   T& value() &;
985   const T&& value() const&&;
986   T&& value() &&;
987 
988   template <typename U>
989   constexpr T value_or(U&& v) const&;
990   template <typename U>
991   T value_or(U&& v) &&;
992 
993   template <typename... Args>
994   T& emplace(Args&&... args);
995 
996   template <typename U, typename... Args>
997   T& emplace(std::initializer_list<U> ilist, Args&&... args);
998 
999   void reset() noexcept;
1000 
1001   constexpr explicit operator bool() const noexcept;
1002   constexpr bool has_value() const noexcept;
1003 
1004   void swap(optional& rhs) noexcept;
1005 };
1006 
1007 template <typename T>
1008 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
1009 
1010 template <typename T, typename... Args>
1011 constexpr optional<T> make_optional(Args&&... args);
1012 
1013 template <typename T, typename U, typename... Args>
1014 constexpr optional<T> make_optional(std::initializer_list<U> il,
1015                                     Args&&... args);
1016 
1017 template <typename T, typename U>
1018 constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs);
1019 template <typename T, typename U>
1020 constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs);
1021 
1022 template <typename T>
1023 constexpr bool operator==(const optional<T> &opt, nullopt_t);
1024 template <typename T>
1025 constexpr bool operator==(nullopt_t, const optional<T> &opt);
1026 template <typename T>
1027 constexpr bool operator!=(const optional<T> &opt, nullopt_t);
1028 template <typename T>
1029 constexpr bool operator!=(nullopt_t, const optional<T> &opt);
1030 
1031 template <typename T, typename U>
1032 constexpr bool operator==(const optional<T> &opt, const U &value);
1033 template <typename T, typename U>
1034 constexpr bool operator==(const T &value, const optional<U> &opt);
1035 template <typename T, typename U>
1036 constexpr bool operator!=(const optional<T> &opt, const U &value);
1037 template <typename T, typename U>
1038 constexpr bool operator!=(const T &value, const optional<U> &opt);
1039 
1040 } // namespace absl
1041 )";
1042 
1043 static constexpr char BaseOptionalHeader[] = R"(
1044 #include "std_initializer_list.h"
1045 #include "std_type_traits.h"
1046 #include "std_utility.h"
1047 
1048 namespace base {
1049 
1050 struct in_place_t {};
1051 constexpr in_place_t in_place;
1052 
1053 struct nullopt_t {
1054   constexpr explicit nullopt_t() {}
1055 };
1056 constexpr nullopt_t nullopt;
1057 
1058 template <typename T>
1059 class Optional;
1060 
1061 namespace internal {
1062 
1063 template <typename T>
1064 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
1065 
1066 template <typename T, typename U>
1067 struct IsConvertibleFromOptional
1068     : std::integral_constant<
1069           bool, std::is_constructible<T, Optional<U>&>::value ||
1070                     std::is_constructible<T, const Optional<U>&>::value ||
1071                     std::is_constructible<T, Optional<U>&&>::value ||
1072                     std::is_constructible<T, const Optional<U>&&>::value ||
1073                     std::is_convertible<Optional<U>&, T>::value ||
1074                     std::is_convertible<const Optional<U>&, T>::value ||
1075                     std::is_convertible<Optional<U>&&, T>::value ||
1076                     std::is_convertible<const Optional<U>&&, T>::value> {};
1077 
1078 template <typename T, typename U>
1079 struct IsAssignableFromOptional
1080     : std::integral_constant<
1081           bool, IsConvertibleFromOptional<T, U>::value ||
1082                     std::is_assignable<T&, Optional<U>&>::value ||
1083                     std::is_assignable<T&, const Optional<U>&>::value ||
1084                     std::is_assignable<T&, Optional<U>&&>::value ||
1085                     std::is_assignable<T&, const Optional<U>&&>::value> {};
1086 
1087 }  // namespace internal
1088 
1089 template <typename T>
1090 class Optional {
1091  public:
1092   using value_type = T;
1093 
1094   constexpr Optional() = default;
1095   constexpr Optional(const Optional& other) noexcept = default;
1096   constexpr Optional(Optional&& other) noexcept = default;
1097 
1098   constexpr Optional(nullopt_t);
1099 
1100   template <typename U,
1101             typename std::enable_if<
1102                 std::is_constructible<T, const U&>::value &&
1103                     !internal::IsConvertibleFromOptional<T, U>::value &&
1104                     std::is_convertible<const U&, T>::value,
1105                 bool>::type = false>
1106   Optional(const Optional<U>& other) noexcept;
1107 
1108   template <typename U,
1109             typename std::enable_if<
1110                 std::is_constructible<T, const U&>::value &&
1111                     !internal::IsConvertibleFromOptional<T, U>::value &&
1112                     !std::is_convertible<const U&, T>::value,
1113                 bool>::type = false>
1114   explicit Optional(const Optional<U>& other) noexcept;
1115 
1116   template <typename U,
1117             typename std::enable_if<
1118                 std::is_constructible<T, U&&>::value &&
1119                     !internal::IsConvertibleFromOptional<T, U>::value &&
1120                     std::is_convertible<U&&, T>::value,
1121                 bool>::type = false>
1122   Optional(Optional<U>&& other) noexcept;
1123 
1124   template <typename U,
1125             typename std::enable_if<
1126                 std::is_constructible<T, U&&>::value &&
1127                     !internal::IsConvertibleFromOptional<T, U>::value &&
1128                     !std::is_convertible<U&&, T>::value,
1129                 bool>::type = false>
1130   explicit Optional(Optional<U>&& other) noexcept;
1131 
1132   template <class... Args>
1133   constexpr explicit Optional(in_place_t, Args&&... args);
1134 
1135   template <class U, class... Args,
1136             class = typename std::enable_if<std::is_constructible<
1137                 value_type, std::initializer_list<U>&, Args...>::value>::type>
1138   constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
1139                               Args&&... args);
1140 
1141   template <
1142       typename U = value_type,
1143       typename std::enable_if<
1144           std::is_constructible<T, U&&>::value &&
1145               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1146               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1147               std::is_convertible<U&&, T>::value,
1148           bool>::type = false>
1149   constexpr Optional(U&& value);
1150 
1151   template <
1152       typename U = value_type,
1153       typename std::enable_if<
1154           std::is_constructible<T, U&&>::value &&
1155               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1156               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1157               !std::is_convertible<U&&, T>::value,
1158           bool>::type = false>
1159   constexpr explicit Optional(U&& value);
1160 
1161   Optional& operator=(const Optional& other) noexcept;
1162 
1163   Optional& operator=(Optional&& other) noexcept;
1164 
1165   Optional& operator=(nullopt_t);
1166 
1167   template <typename U>
1168   typename std::enable_if<
1169       !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1170           std::is_constructible<T, U>::value &&
1171           std::is_assignable<T&, U>::value &&
1172           (!std::is_scalar<T>::value ||
1173            !std::is_same<typename std::decay<U>::type, T>::value),
1174       Optional&>::type
1175   operator=(U&& value) noexcept;
1176 
1177   template <typename U>
1178   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1179                               std::is_constructible<T, const U&>::value &&
1180                               std::is_assignable<T&, const U&>::value,
1181                           Optional&>::type
1182   operator=(const Optional<U>& other) noexcept;
1183 
1184   template <typename U>
1185   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1186                               std::is_constructible<T, U>::value &&
1187                               std::is_assignable<T&, U>::value,
1188                           Optional&>::type
1189   operator=(Optional<U>&& other) noexcept;
1190 
1191   const T& operator*() const&;
1192   T& operator*() &;
1193   const T&& operator*() const&&;
1194   T&& operator*() &&;
1195 
1196   const T* operator->() const;
1197   T* operator->();
1198 
1199   const T& value() const&;
1200   T& value() &;
1201   const T&& value() const&&;
1202   T&& value() &&;
1203 
1204   template <typename U>
1205   constexpr T value_or(U&& v) const&;
1206   template <typename U>
1207   T value_or(U&& v) &&;
1208 
1209   template <typename... Args>
1210   T& emplace(Args&&... args);
1211 
1212   template <typename U, typename... Args>
1213   T& emplace(std::initializer_list<U> ilist, Args&&... args);
1214 
1215   void reset() noexcept;
1216 
1217   constexpr explicit operator bool() const noexcept;
1218   constexpr bool has_value() const noexcept;
1219 
1220   void swap(Optional& other);
1221 };
1222 
1223 template <typename T>
1224 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v);
1225 
1226 template <typename T, typename... Args>
1227 constexpr Optional<T> make_optional(Args&&... args);
1228 
1229 template <typename T, typename U, typename... Args>
1230 constexpr Optional<T> make_optional(std::initializer_list<U> il,
1231                                     Args&&... args);
1232 
1233 template <typename T, typename U>
1234 constexpr bool operator==(const Optional<T> &lhs, const Optional<U> &rhs);
1235 template <typename T, typename U>
1236 constexpr bool operator!=(const Optional<T> &lhs, const Optional<U> &rhs);
1237 
1238 template <typename T>
1239 constexpr bool operator==(const Optional<T> &opt, nullopt_t);
1240 template <typename T>
1241 constexpr bool operator==(nullopt_t, const Optional<T> &opt);
1242 template <typename T>
1243 constexpr bool operator!=(const Optional<T> &opt, nullopt_t);
1244 template <typename T>
1245 constexpr bool operator!=(nullopt_t, const Optional<T> &opt);
1246 
1247 template <typename T, typename U>
1248 constexpr bool operator==(const Optional<T> &opt, const U &value);
1249 template <typename T, typename U>
1250 constexpr bool operator==(const T &value, const Optional<U> &opt);
1251 template <typename T, typename U>
1252 constexpr bool operator!=(const Optional<T> &opt, const U &value);
1253 template <typename T, typename U>
1254 constexpr bool operator!=(const T &value, const Optional<U> &opt);
1255 
1256 } // namespace base
1257 )";
1258 
1259 /// Replaces all occurrences of `Pattern` in `S` with `Replacement`.
1260 static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern,
1261                                   const std::string &Replacement) {
1262   size_t Pos = 0;
1263   while (true) {
1264     Pos = S.find(Pattern, Pos);
1265     if (Pos == std::string::npos)
1266       break;
1267     S.replace(Pos, Pattern.size(), Replacement);
1268   }
1269 }
1270 
1271 struct OptionalTypeIdentifier {
1272   std::string NamespaceName;
1273   std::string TypeName;
1274 };
1275 
1276 static raw_ostream &operator<<(raw_ostream &OS,
1277                                const OptionalTypeIdentifier &TypeId) {
1278   OS << TypeId.NamespaceName << "::" << TypeId.TypeName;
1279   return OS;
1280 }
1281 
1282 class UncheckedOptionalAccessTest
1283     : public ::testing::TestWithParam<OptionalTypeIdentifier> {
1284 protected:
1285   void ExpectDiagnosticsFor(std::string SourceCode,
1286                             bool IgnoreSmartPointerDereference = true) {
1287     ExpectDiagnosticsFor(SourceCode, ast_matchers::hasName("target"),
1288                          IgnoreSmartPointerDereference);
1289   }
1290 
1291   void ExpectDiagnosticsForLambda(std::string SourceCode,
1292                                   bool IgnoreSmartPointerDereference = true) {
1293     ExpectDiagnosticsFor(
1294         SourceCode,
1295         ast_matchers::hasDeclContext(
1296             ast_matchers::cxxRecordDecl(ast_matchers::isLambda())),
1297         IgnoreSmartPointerDereference);
1298   }
1299 
1300   template <typename FuncDeclMatcher>
1301   void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher,
1302                             bool IgnoreSmartPointerDereference = true) {
1303     // Run in C++17 and C++20 mode to cover differences in the AST between modes
1304     // (e.g. C++20 can contain `CXXRewrittenBinaryOperator`).
1305     for (const char *CxxMode : {"-std=c++17", "-std=c++20"})
1306       ExpectDiagnosticsFor(SourceCode, FuncMatcher, CxxMode,
1307                            IgnoreSmartPointerDereference);
1308   }
1309 
1310   template <typename FuncDeclMatcher>
1311   void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher,
1312                             const char *CxxMode,
1313                             bool IgnoreSmartPointerDereference) {
1314     ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName);
1315     ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName);
1316 
1317     std::vector<std::pair<std::string, std::string>> Headers;
1318     Headers.emplace_back("cstddef.h", CSDtdDefHeader);
1319     Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader);
1320     Headers.emplace_back("std_string.h", StdStringHeader);
1321     Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader);
1322     Headers.emplace_back("std_utility.h", StdUtilityHeader);
1323     Headers.emplace_back("std_optional.h", StdOptionalHeader);
1324     Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader);
1325     Headers.emplace_back("absl_optional.h", AbslOptionalHeader);
1326     Headers.emplace_back("base_optional.h", BaseOptionalHeader);
1327     Headers.emplace_back("unchecked_optional_access_test.h", R"(
1328       #include "absl_optional.h"
1329       #include "base_optional.h"
1330       #include "std_initializer_list.h"
1331       #include "std_optional.h"
1332       #include "std_string.h"
1333       #include "std_utility.h"
1334 
1335       template <typename T>
1336       T Make();
1337     )");
1338     UncheckedOptionalAccessModelOptions Options{IgnoreSmartPointerDereference};
1339     std::vector<SourceLocation> Diagnostics;
1340     llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
1341         AnalysisInputs<UncheckedOptionalAccessModel>(
1342             SourceCode, std::move(FuncMatcher),
1343             [](ASTContext &Ctx, Environment &Env) {
1344               return UncheckedOptionalAccessModel(Ctx, Env);
1345             })
1346             .withDiagnosisCallbacks(
1347                 {/*Before=*/[&Diagnostics,
1348                              Diagnoser =
1349                                  UncheckedOptionalAccessDiagnoser(Options)](
1350                                 ASTContext &Ctx, const CFGElement &Elt,
1351                                 const TransferStateForDiagnostics<
1352                                     UncheckedOptionalAccessLattice>
1353                                     &State) mutable {
1354                    auto EltDiagnostics = Diagnoser(Elt, Ctx, State);
1355                    llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
1356                  },
1357                  /*After=*/nullptr})
1358             .withASTBuildArgs(
1359                 {"-fsyntax-only", CxxMode, "-Wno-undefined-inline"})
1360             .withASTBuildVirtualMappedFiles(
1361                 tooling::FileContentMappings(Headers.begin(), Headers.end())),
1362         /*VerifyResults=*/[&Diagnostics](
1363                               const llvm::DenseMap<unsigned, std::string>
1364                                   &Annotations,
1365                               const AnalysisOutputs &AO) {
1366           llvm::DenseSet<unsigned> AnnotationLines;
1367           for (const auto &[Line, _] : Annotations) {
1368             AnnotationLines.insert(Line);
1369           }
1370           auto &SrcMgr = AO.ASTCtx.getSourceManager();
1371           llvm::DenseSet<unsigned> DiagnosticLines;
1372           for (SourceLocation &Loc : Diagnostics) {
1373             unsigned Line = SrcMgr.getPresumedLineNumber(Loc);
1374             DiagnosticLines.insert(Line);
1375             if (!AnnotationLines.contains(Line)) {
1376               IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
1377                   new DiagnosticOptions());
1378               TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
1379                                 DiagOpts.get());
1380               TD.emitDiagnostic(FullSourceLoc(Loc, SrcMgr),
1381                                 DiagnosticsEngine::Error,
1382                                 "unexpected diagnostic", {}, {});
1383             }
1384           }
1385 
1386           EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines));
1387         });
1388     if (Error)
1389       FAIL() << llvm::toString(std::move(Error));
1390   }
1391 };
1392 
1393 INSTANTIATE_TEST_SUITE_P(
1394     UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
1395     ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
1396                       OptionalTypeIdentifier{"absl", "optional"},
1397                       OptionalTypeIdentifier{"base", "Optional"}),
1398     [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
1399       return Info.param.NamespaceName;
1400     });
1401 
1402 // Verifies that similarly-named types are ignored.
1403 TEST_P(UncheckedOptionalAccessTest, NonTrackedOptionalType) {
1404   ExpectDiagnosticsFor(
1405       R"(
1406     namespace other {
1407     namespace $ns {
1408     template <typename T>
1409     struct $optional {
1410       T value();
1411     };
1412     }
1413 
1414     void target($ns::$optional<int> opt) {
1415       opt.value();
1416     }
1417     }
1418   )");
1419 }
1420 
1421 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
1422   ExpectDiagnosticsFor(R"(
1423     void target() {
1424       (void)0;
1425     }
1426   )");
1427 }
1428 
1429 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
1430   ExpectDiagnosticsFor(
1431       R"(
1432     #include "unchecked_optional_access_test.h"
1433 
1434     void target($ns::$optional<int> opt) {
1435       opt.value(); // [[unsafe]]
1436     }
1437   )");
1438 
1439   ExpectDiagnosticsFor(
1440       R"(
1441     #include "unchecked_optional_access_test.h"
1442 
1443     void target($ns::$optional<int> opt) {
1444       std::move(opt).value(); // [[unsafe]]
1445     }
1446   )");
1447 }
1448 
1449 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
1450   ExpectDiagnosticsFor(
1451       R"(
1452     #include "unchecked_optional_access_test.h"
1453 
1454     void target($ns::$optional<int> opt) {
1455       *opt; // [[unsafe]]
1456     }
1457   )");
1458 
1459   ExpectDiagnosticsFor(
1460       R"(
1461     #include "unchecked_optional_access_test.h"
1462 
1463     void target($ns::$optional<int> opt) {
1464       *std::move(opt); // [[unsafe]]
1465     }
1466   )");
1467 }
1468 
1469 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
1470   ExpectDiagnosticsFor(
1471       R"(
1472     #include "unchecked_optional_access_test.h"
1473 
1474     struct Foo {
1475       void foo();
1476     };
1477 
1478     void target($ns::$optional<Foo> opt) {
1479       opt->foo(); // [[unsafe]]
1480     }
1481   )");
1482 
1483   ExpectDiagnosticsFor(
1484       R"(
1485     #include "unchecked_optional_access_test.h"
1486 
1487     struct Foo {
1488       void foo();
1489     };
1490 
1491     void target($ns::$optional<Foo> opt) {
1492       std::move(opt)->foo(); // [[unsafe]]
1493     }
1494   )");
1495 }
1496 
1497 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
1498   ExpectDiagnosticsFor(R"(
1499     #include "unchecked_optional_access_test.h"
1500 
1501     void target($ns::$optional<int> opt) {
1502       if (opt.has_value()) {
1503         opt.value();
1504       }
1505     }
1506   )");
1507 }
1508 
1509 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
1510   ExpectDiagnosticsFor(R"(
1511     #include "unchecked_optional_access_test.h"
1512 
1513     void target($ns::$optional<int> opt) {
1514       if (opt) {
1515         opt.value();
1516       }
1517     }
1518   )");
1519 }
1520 
1521 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
1522   ExpectDiagnosticsFor(
1523       R"(
1524     #include "unchecked_optional_access_test.h"
1525 
1526     void target() {
1527       Make<$ns::$optional<int>>().value(); // [[unsafe]]
1528       (void)0;
1529     }
1530   )");
1531 
1532   ExpectDiagnosticsFor(
1533       R"(
1534     #include "unchecked_optional_access_test.h"
1535 
1536     void target($ns::$optional<int> opt) {
1537       std::move(opt).value(); // [[unsafe]]
1538     }
1539   )");
1540 }
1541 
1542 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
1543   ExpectDiagnosticsFor(
1544       R"(
1545     #include "unchecked_optional_access_test.h"
1546 
1547     void target() {
1548       $ns::$optional<int> opt;
1549       opt.value(); // [[unsafe]]
1550     }
1551   )");
1552 }
1553 
1554 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
1555   ExpectDiagnosticsFor(
1556       R"(
1557     #include "unchecked_optional_access_test.h"
1558 
1559     void target() {
1560       $ns::$optional<int> opt($ns::nullopt);
1561       opt.value(); // [[unsafe]]
1562     }
1563   )");
1564 }
1565 
1566 TEST_P(UncheckedOptionalAccessTest, NulloptConstructorWithSugaredType) {
1567   ExpectDiagnosticsFor(
1568       R"(
1569     #include "unchecked_optional_access_test.h"
1570     template <typename T>
1571     using wrapper = T;
1572 
1573     template <typename T>
1574     wrapper<T> wrap(T);
1575 
1576     void target() {
1577       $ns::$optional<int> opt(wrap($ns::nullopt));
1578       opt.value(); // [[unsafe]]
1579     }
1580   )");
1581 }
1582 
1583 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
1584   ExpectDiagnosticsFor(R"(
1585     #include "unchecked_optional_access_test.h"
1586 
1587     void target() {
1588       $ns::$optional<int> opt($ns::in_place, 3);
1589       opt.value();
1590     }
1591   )");
1592 
1593   ExpectDiagnosticsFor(R"(
1594     #include "unchecked_optional_access_test.h"
1595 
1596     struct Foo {};
1597 
1598     void target() {
1599       $ns::$optional<Foo> opt($ns::in_place);
1600       opt.value();
1601     }
1602   )");
1603 
1604   ExpectDiagnosticsFor(R"(
1605     #include "unchecked_optional_access_test.h"
1606 
1607     struct Foo {
1608       explicit Foo(int, bool);
1609     };
1610 
1611     void target() {
1612       $ns::$optional<Foo> opt($ns::in_place, 3, false);
1613       opt.value();
1614     }
1615   )");
1616 
1617   ExpectDiagnosticsFor(R"(
1618     #include "unchecked_optional_access_test.h"
1619 
1620     struct Foo {
1621       explicit Foo(std::initializer_list<int>);
1622     };
1623 
1624     void target() {
1625       $ns::$optional<Foo> opt($ns::in_place, {3});
1626       opt.value();
1627     }
1628   )");
1629 }
1630 
1631 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
1632   ExpectDiagnosticsFor(R"(
1633     #include "unchecked_optional_access_test.h"
1634 
1635     void target() {
1636       $ns::$optional<int> opt(21);
1637       opt.value();
1638     }
1639   )");
1640 
1641   ExpectDiagnosticsFor(R"(
1642     #include "unchecked_optional_access_test.h"
1643 
1644     void target() {
1645       $ns::$optional<int> opt = $ns::$optional<int>(21);
1646       opt.value();
1647     }
1648   )");
1649   ExpectDiagnosticsFor(R"(
1650     #include "unchecked_optional_access_test.h"
1651 
1652     void target() {
1653       $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1654       opt.value();
1655     }
1656   )");
1657 
1658   ExpectDiagnosticsFor(R"(
1659     #include "unchecked_optional_access_test.h"
1660 
1661     struct MyString {
1662       MyString(const char*);
1663     };
1664 
1665     void target() {
1666       $ns::$optional<MyString> opt("foo");
1667       opt.value();
1668     }
1669   )");
1670 
1671   ExpectDiagnosticsFor(R"(
1672     #include "unchecked_optional_access_test.h"
1673 
1674     struct Foo {};
1675 
1676     struct Bar {
1677       Bar(const Foo&);
1678     };
1679 
1680     void target() {
1681       $ns::$optional<Bar> opt(Make<Foo>());
1682       opt.value();
1683     }
1684   )");
1685 
1686   ExpectDiagnosticsFor(R"(
1687     #include "unchecked_optional_access_test.h"
1688 
1689     struct Foo {
1690       explicit Foo(int);
1691     };
1692 
1693     void target() {
1694       $ns::$optional<Foo> opt(3);
1695       opt.value();
1696     }
1697   )");
1698 }
1699 
1700 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
1701   ExpectDiagnosticsFor(
1702       R"(
1703     #include "unchecked_optional_access_test.h"
1704 
1705     struct Foo {};
1706 
1707     struct Bar {
1708       Bar(const Foo&);
1709     };
1710 
1711     void target() {
1712       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1713       opt.value(); // [[unsafe]]
1714     }
1715   )");
1716 
1717   ExpectDiagnosticsFor(
1718       R"(
1719     #include "unchecked_optional_access_test.h"
1720 
1721     struct Foo {};
1722 
1723     struct Bar {
1724       explicit Bar(const Foo&);
1725     };
1726 
1727     void target() {
1728       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1729       opt.value(); // [[unsafe]]
1730     }
1731   )");
1732 
1733   ExpectDiagnosticsFor(
1734       R"(
1735     #include "unchecked_optional_access_test.h"
1736 
1737     struct Foo {};
1738 
1739     struct Bar {
1740       Bar(const Foo&);
1741     };
1742 
1743     void target() {
1744       $ns::$optional<Foo> opt1 = $ns::nullopt;
1745       $ns::$optional<Bar> opt2(opt1);
1746       opt2.value(); // [[unsafe]]
1747     }
1748   )");
1749 
1750   ExpectDiagnosticsFor(R"(
1751     #include "unchecked_optional_access_test.h"
1752 
1753     struct Foo {};
1754 
1755     struct Bar {
1756       Bar(const Foo&);
1757     };
1758 
1759     void target() {
1760       $ns::$optional<Foo> opt1(Make<Foo>());
1761       $ns::$optional<Bar> opt2(opt1);
1762       opt2.value();
1763     }
1764   )");
1765 
1766   ExpectDiagnosticsFor(R"(
1767     #include "unchecked_optional_access_test.h"
1768 
1769     struct Foo {};
1770 
1771     struct Bar {
1772       explicit Bar(const Foo&);
1773     };
1774 
1775     void target() {
1776       $ns::$optional<Foo> opt1(Make<Foo>());
1777       $ns::$optional<Bar> opt2(opt1);
1778       opt2.value();
1779     }
1780   )");
1781 }
1782 
1783 TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
1784   ExpectDiagnosticsFor(R"(
1785     #include "unchecked_optional_access_test.h"
1786 
1787     void target() {
1788       $ns::$optional<int> opt = $ns::make_optional(0);
1789       opt.value();
1790     }
1791   )");
1792 
1793   ExpectDiagnosticsFor(R"(
1794     #include "unchecked_optional_access_test.h"
1795 
1796     struct Foo {
1797       Foo(int, int);
1798     };
1799 
1800     void target() {
1801       $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1802       opt.value();
1803     }
1804   )");
1805 
1806   ExpectDiagnosticsFor(R"(
1807     #include "unchecked_optional_access_test.h"
1808 
1809     struct Foo {
1810       constexpr Foo(std::initializer_list<char>);
1811     };
1812 
1813     void target() {
1814       char a = 'a';
1815       $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1816       opt.value();
1817     }
1818   )");
1819 }
1820 
1821 TEST_P(UncheckedOptionalAccessTest, ValueOr) {
1822   ExpectDiagnosticsFor(R"(
1823     #include "unchecked_optional_access_test.h"
1824 
1825     void target() {
1826       $ns::$optional<int> opt;
1827       opt.value_or(0);
1828       (void)0;
1829     }
1830   )");
1831 }
1832 
1833 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointers) {
1834   ExpectDiagnosticsFor(
1835       R"code(
1836     #include "unchecked_optional_access_test.h"
1837 
1838     void target($ns::$optional<int*> opt) {
1839       if (opt.value_or(nullptr) != nullptr) {
1840         opt.value();
1841       } else {
1842         opt.value(); // [[unsafe]]
1843       }
1844     }
1845   )code");
1846 }
1847 
1848 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonIntegers) {
1849   ExpectDiagnosticsFor(
1850       R"code(
1851     #include "unchecked_optional_access_test.h"
1852 
1853     void target($ns::$optional<int> opt) {
1854       if (opt.value_or(0) != 0) {
1855         opt.value();
1856       } else {
1857         opt.value(); // [[unsafe]]
1858       }
1859     }
1860   )code");
1861 }
1862 
1863 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonStrings) {
1864   ExpectDiagnosticsFor(
1865       R"code(
1866     #include "unchecked_optional_access_test.h"
1867 
1868     void target($ns::$optional<std::string> opt) {
1869       if (!opt.value_or("").empty()) {
1870         opt.value();
1871       } else {
1872         opt.value(); // [[unsafe]]
1873       }
1874     }
1875   )code");
1876 
1877   ExpectDiagnosticsFor(
1878       R"code(
1879     #include "unchecked_optional_access_test.h"
1880 
1881     void target($ns::$optional<std::string> opt) {
1882       if (opt.value_or("") != "") {
1883         opt.value();
1884       } else {
1885         opt.value(); // [[unsafe]]
1886       }
1887     }
1888   )code");
1889 }
1890 
1891 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointerToOptional) {
1892   // FIXME: make `opt` a parameter directly, once we ensure that all `optional`
1893   // values have a `has_value` property.
1894   ExpectDiagnosticsFor(
1895       R"code(
1896     #include "unchecked_optional_access_test.h"
1897 
1898     void target($ns::$optional<int> p) {
1899       $ns::$optional<int> *opt = &p;
1900       if (opt->value_or(0) != 0) {
1901         opt->value();
1902       } else {
1903         opt->value(); // [[unsafe]]
1904       }
1905     }
1906   )code");
1907 }
1908 
1909 TEST_P(UncheckedOptionalAccessTest, Emplace) {
1910   ExpectDiagnosticsFor(R"(
1911     #include "unchecked_optional_access_test.h"
1912 
1913     void target() {
1914       $ns::$optional<int> opt;
1915       opt.emplace(0);
1916       opt.value();
1917     }
1918   )");
1919 
1920   ExpectDiagnosticsFor(R"(
1921     #include "unchecked_optional_access_test.h"
1922 
1923     void target($ns::$optional<int> *opt) {
1924       opt->emplace(0);
1925       opt->value();
1926     }
1927   )");
1928 
1929   // FIXME: Add tests that call `emplace` in conditional branches:
1930   //  ExpectDiagnosticsFor(
1931   //      R"(
1932   //    #include "unchecked_optional_access_test.h"
1933   //
1934   //    void target($ns::$optional<int> opt, bool b) {
1935   //      if (b) {
1936   //        opt.emplace(0);
1937   //      }
1938   //      if (b) {
1939   //        opt.value();
1940   //      } else {
1941   //        opt.value(); // [[unsafe]]
1942   //      }
1943   //    }
1944   //  )");
1945 }
1946 
1947 TEST_P(UncheckedOptionalAccessTest, Reset) {
1948   ExpectDiagnosticsFor(
1949       R"(
1950     #include "unchecked_optional_access_test.h"
1951 
1952     void target() {
1953       $ns::$optional<int> opt = $ns::make_optional(0);
1954       opt.reset();
1955       opt.value(); // [[unsafe]]
1956     }
1957   )");
1958 
1959   ExpectDiagnosticsFor(
1960       R"(
1961     #include "unchecked_optional_access_test.h"
1962 
1963     void target($ns::$optional<int> &opt) {
1964       if (opt.has_value()) {
1965         opt.reset();
1966         opt.value(); // [[unsafe]]
1967       }
1968     }
1969   )");
1970 
1971   // FIXME: Add tests that call `reset` in conditional branches:
1972   //  ExpectDiagnosticsFor(
1973   //      R"(
1974   //    #include "unchecked_optional_access_test.h"
1975   //
1976   //    void target(bool b) {
1977   //      $ns::$optional<int> opt = $ns::make_optional(0);
1978   //      if (b) {
1979   //        opt.reset();
1980   //      }
1981   //      if (b) {
1982   //        opt.value(); // [[unsafe]]
1983   //      } else {
1984   //        opt.value();
1985   //      }
1986   //    }
1987   //  )");
1988 }
1989 
1990 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) {
1991   ExpectDiagnosticsFor(R"(
1992     #include "unchecked_optional_access_test.h"
1993 
1994     struct Foo {};
1995 
1996     void target() {
1997       $ns::$optional<Foo> opt;
1998       opt = Foo();
1999       opt.value();
2000     }
2001   )");
2002 
2003   ExpectDiagnosticsFor(R"(
2004     #include "unchecked_optional_access_test.h"
2005 
2006     struct Foo {};
2007 
2008     void target() {
2009       $ns::$optional<Foo> opt;
2010       (opt = Foo()).value();
2011       (void)0;
2012     }
2013   )");
2014 
2015   ExpectDiagnosticsFor(R"(
2016     #include "unchecked_optional_access_test.h"
2017 
2018     struct MyString {
2019       MyString(const char*);
2020     };
2021 
2022     void target() {
2023       $ns::$optional<MyString> opt;
2024       opt = "foo";
2025       opt.value();
2026     }
2027   )");
2028 
2029   ExpectDiagnosticsFor(R"(
2030     #include "unchecked_optional_access_test.h"
2031 
2032     struct MyString {
2033       MyString(const char*);
2034     };
2035 
2036     void target() {
2037       $ns::$optional<MyString> opt;
2038       (opt = "foo").value();
2039     }
2040   )");
2041 }
2042 
2043 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) {
2044   ExpectDiagnosticsFor(
2045       R"(
2046     #include "unchecked_optional_access_test.h"
2047 
2048     struct Foo {};
2049 
2050     struct Bar {
2051       Bar(const Foo&);
2052     };
2053 
2054     void target() {
2055       $ns::$optional<Foo> opt1 = Foo();
2056       $ns::$optional<Bar> opt2;
2057       opt2 = opt1;
2058       opt2.value();
2059     }
2060   )");
2061 
2062   ExpectDiagnosticsFor(
2063       R"(
2064     #include "unchecked_optional_access_test.h"
2065 
2066     struct Foo {};
2067 
2068     struct Bar {
2069       Bar(const Foo&);
2070     };
2071 
2072     void target() {
2073       $ns::$optional<Foo> opt1;
2074       $ns::$optional<Bar> opt2;
2075       if (opt2.has_value()) {
2076         opt2 = opt1;
2077         opt2.value(); // [[unsafe]]
2078       }
2079     }
2080   )");
2081 
2082   ExpectDiagnosticsFor(
2083       R"(
2084     #include "unchecked_optional_access_test.h"
2085 
2086     struct Foo {};
2087 
2088     struct Bar {
2089       Bar(const Foo&);
2090     };
2091 
2092     void target() {
2093       $ns::$optional<Foo> opt1 = Foo();
2094       $ns::$optional<Bar> opt2;
2095       (opt2 = opt1).value();
2096       (void)0;
2097     }
2098   )");
2099 }
2100 
2101 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) {
2102   ExpectDiagnosticsFor(
2103       R"(
2104     #include "unchecked_optional_access_test.h"
2105 
2106     void target() {
2107       $ns::$optional<int> opt = 3;
2108       opt = $ns::nullopt;
2109       opt.value(); // [[unsafe]]
2110     }
2111   )");
2112 
2113   ExpectDiagnosticsFor(
2114       R"(
2115     #include "unchecked_optional_access_test.h"
2116 
2117     void target() {
2118       $ns::$optional<int> opt = 3;
2119       (opt = $ns::nullopt).value(); // [[unsafe]]
2120     }
2121   )");
2122 }
2123 
2124 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) {
2125   ExpectDiagnosticsFor(
2126       R"(
2127     #include "unchecked_optional_access_test.h"
2128 
2129     void target() {
2130       $ns::$optional<int> opt1 = $ns::nullopt;
2131       $ns::$optional<int> opt2 = 3;
2132 
2133       opt1.swap(opt2);
2134 
2135       opt1.value();
2136 
2137       opt2.value(); // [[unsafe]]
2138     }
2139   )");
2140 
2141   ExpectDiagnosticsFor(
2142       R"(
2143     #include "unchecked_optional_access_test.h"
2144 
2145     void target() {
2146       $ns::$optional<int> opt1 = $ns::nullopt;
2147       $ns::$optional<int> opt2 = 3;
2148 
2149       opt2.swap(opt1);
2150 
2151       opt1.value();
2152 
2153       opt2.value(); // [[unsafe]]
2154     }
2155   )");
2156 }
2157 
2158 TEST_P(UncheckedOptionalAccessTest, OptionalReturnedFromFuntionCall) {
2159   ExpectDiagnosticsFor(
2160       R"(
2161     #include "unchecked_optional_access_test.h"
2162 
2163     struct S {
2164       $ns::$optional<float> x;
2165     } s;
2166     S getOptional() {
2167       return s;
2168     }
2169 
2170     void target() {
2171       getOptional().x = 0;
2172     }
2173   )");
2174 }
2175 
2176 TEST_P(UncheckedOptionalAccessTest, NonConstMethodMayClearOptionalField) {
2177   ExpectDiagnosticsFor(
2178       R"(
2179     #include "unchecked_optional_access_test.h"
2180 
2181     struct Foo {
2182       $ns::$optional<std::string> opt;
2183       void clear();  // assume this may modify the opt field's state
2184     };
2185 
2186     void target(Foo& foo) {
2187       if (foo.opt) {
2188         foo.opt.value();
2189         foo.clear();
2190         foo.opt.value();  // [[unsafe]]
2191       }
2192     }
2193   )");
2194 }
2195 
2196 TEST_P(UncheckedOptionalAccessTest,
2197        NonConstMethodMayNotClearConstOptionalField) {
2198   ExpectDiagnosticsFor(
2199       R"(
2200     #include "unchecked_optional_access_test.h"
2201 
2202     struct Foo {
2203       const $ns::$optional<std::string> opt;
2204       void clear();
2205     };
2206 
2207     void target(Foo& foo) {
2208       if (foo.opt) {
2209         foo.opt.value();
2210         foo.clear();
2211         foo.opt.value();
2212       }
2213     }
2214   )");
2215 }
2216 
2217 TEST_P(UncheckedOptionalAccessTest, StdSwap) {
2218   ExpectDiagnosticsFor(
2219       R"(
2220     #include "unchecked_optional_access_test.h"
2221 
2222     void target() {
2223       $ns::$optional<int> opt1 = $ns::nullopt;
2224       $ns::$optional<int> opt2 = 3;
2225 
2226       std::swap(opt1, opt2);
2227 
2228       opt1.value();
2229 
2230       opt2.value(); // [[unsafe]]
2231     }
2232   )");
2233 
2234   ExpectDiagnosticsFor(
2235       R"(
2236     #include "unchecked_optional_access_test.h"
2237 
2238     void target() {
2239       $ns::$optional<int> opt1 = $ns::nullopt;
2240       $ns::$optional<int> opt2 = 3;
2241 
2242       std::swap(opt2, opt1);
2243 
2244       opt1.value();
2245 
2246       opt2.value(); // [[unsafe]]
2247     }
2248   )");
2249 }
2250 
2251 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocLeft) {
2252   ExpectDiagnosticsFor(
2253       R"(
2254     #include "unchecked_optional_access_test.h"
2255 
2256     struct L { $ns::$optional<int> hd; L* tl; };
2257 
2258     void target() {
2259       $ns::$optional<int> foo = 3;
2260       L bar;
2261 
2262       // Any `tl` beyond the first is not modeled.
2263       bar.tl->tl->hd.swap(foo);
2264 
2265       bar.tl->tl->hd.value(); // [[unsafe]]
2266       foo.value(); // [[unsafe]]
2267     }
2268   )");
2269 }
2270 
2271 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocRight) {
2272   ExpectDiagnosticsFor(
2273       R"(
2274     #include "unchecked_optional_access_test.h"
2275 
2276     struct L { $ns::$optional<int> hd; L* tl; };
2277 
2278     void target() {
2279       $ns::$optional<int> foo = 3;
2280       L bar;
2281 
2282       // Any `tl` beyond the first is not modeled.
2283       foo.swap(bar.tl->tl->hd);
2284 
2285       bar.tl->tl->hd.value(); // [[unsafe]]
2286       foo.value(); // [[unsafe]]
2287     }
2288   )");
2289 }
2290 
2291 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftSet) {
2292   ExpectDiagnosticsFor(
2293       R"(
2294     #include "unchecked_optional_access_test.h"
2295 
2296     struct S { int x; };
2297     struct A { $ns::$optional<S> late; };
2298     struct B { A f3; };
2299     struct C { B f2; };
2300     struct D { C f1; };
2301 
2302     void target() {
2303       $ns::$optional<S> foo = S{3};
2304       D bar;
2305 
2306       bar.f1.f2.f3.late.swap(foo);
2307 
2308       bar.f1.f2.f3.late.value();
2309       foo.value(); // [[unsafe]]
2310     }
2311   )");
2312 }
2313 
2314 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftUnset) {
2315   ExpectDiagnosticsFor(
2316       R"(
2317     #include "unchecked_optional_access_test.h"
2318 
2319     struct S { int x; };
2320     struct A { $ns::$optional<S> late; };
2321     struct B { A f3; };
2322     struct C { B f2; };
2323     struct D { C f1; };
2324 
2325     void target() {
2326       $ns::$optional<S> foo;
2327       D bar;
2328 
2329       bar.f1.f2.f3.late.swap(foo);
2330 
2331       bar.f1.f2.f3.late.value(); // [[unsafe]]
2332       foo.value(); // [[unsafe]]
2333     }
2334   )");
2335 }
2336 
2337 // fixme: use recursion instead of depth.
2338 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightSet) {
2339   ExpectDiagnosticsFor(
2340       R"(
2341     #include "unchecked_optional_access_test.h"
2342 
2343     struct S { int x; };
2344     struct A { $ns::$optional<S> late; };
2345     struct B { A f3; };
2346     struct C { B f2; };
2347     struct D { C f1; };
2348 
2349     void target() {
2350       $ns::$optional<S> foo = S{3};
2351       D bar;
2352 
2353       foo.swap(bar.f1.f2.f3.late);
2354 
2355       bar.f1.f2.f3.late.value();
2356       foo.value(); // [[unsafe]]
2357     }
2358   )");
2359 }
2360 
2361 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightUnset) {
2362   ExpectDiagnosticsFor(
2363       R"(
2364     #include "unchecked_optional_access_test.h"
2365 
2366     struct S { int x; };
2367     struct A { $ns::$optional<S> late; };
2368     struct B { A f3; };
2369     struct C { B f2; };
2370     struct D { C f1; };
2371 
2372     void target() {
2373       $ns::$optional<S> foo;
2374       D bar;
2375 
2376       foo.swap(bar.f1.f2.f3.late);
2377 
2378       bar.f1.f2.f3.late.value(); // [[unsafe]]
2379       foo.value(); // [[unsafe]]
2380     }
2381   )");
2382 }
2383 
2384 TEST_P(UncheckedOptionalAccessTest, UniquePtrToOptional) {
2385   // We suppress diagnostics for optionals in smart pointers (other than
2386   // `optional` itself).
2387   ExpectDiagnosticsFor(
2388       R"(
2389     #include "unchecked_optional_access_test.h"
2390 
2391     template <typename T>
2392     struct smart_ptr {
2393       T& operator*() &;
2394       T* operator->();
2395     };
2396 
2397     void target() {
2398       smart_ptr<$ns::$optional<bool>> foo;
2399       foo->value();
2400       (*foo).value();
2401     }
2402   )");
2403 }
2404 
2405 TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) {
2406   // We suppress diagnostics for optional fields reachable from smart pointers
2407   // (other than `optional` itself) through (exactly) one member access.
2408   ExpectDiagnosticsFor(
2409       R"(
2410     #include "unchecked_optional_access_test.h"
2411 
2412     template <typename T>
2413     struct smart_ptr {
2414       T& operator*() &;
2415       T* operator->();
2416     };
2417 
2418     struct Foo {
2419       $ns::$optional<int> opt;
2420     };
2421 
2422     void target() {
2423       smart_ptr<Foo> foo;
2424       *foo->opt;
2425       *(*foo).opt;
2426     }
2427   )");
2428 }
2429 
2430 TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) {
2431   ExpectDiagnosticsFor(
2432       R"(
2433     #include "unchecked_optional_access_test.h"
2434 
2435     $ns::$optional<int> MakeOpt();
2436 
2437     void target() {
2438       $ns::$optional<int> opt = 0;
2439       opt = MakeOpt();
2440       opt.value(); // [[unsafe]]
2441     }
2442   )");
2443   ExpectDiagnosticsFor(
2444       R"(
2445     #include "unchecked_optional_access_test.h"
2446 
2447     const $ns::$optional<int>& MakeOpt();
2448 
2449     void target() {
2450       $ns::$optional<int> opt = 0;
2451       opt = MakeOpt();
2452       opt.value(); // [[unsafe]]
2453     }
2454   )");
2455 
2456   ExpectDiagnosticsFor(
2457       R"(
2458     #include "unchecked_optional_access_test.h"
2459 
2460     using IntOpt = $ns::$optional<int>;
2461     IntOpt MakeOpt();
2462 
2463     void target() {
2464       IntOpt opt = 0;
2465       opt = MakeOpt();
2466       opt.value(); // [[unsafe]]
2467     }
2468   )");
2469 
2470   ExpectDiagnosticsFor(
2471       R"(
2472     #include "unchecked_optional_access_test.h"
2473 
2474     using IntOpt = $ns::$optional<int>;
2475     const IntOpt& MakeOpt();
2476 
2477     void target() {
2478       IntOpt opt = 0;
2479       opt = MakeOpt();
2480       opt.value(); // [[unsafe]]
2481     }
2482   )");
2483 }
2484 
2485 
2486 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftSet) {
2487   ExpectDiagnosticsFor(
2488       R"(
2489     #include "unchecked_optional_access_test.h"
2490 
2491     void target() {
2492       $ns::$optional<int> opt1 = 3;
2493       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2494 
2495       if (opt1 == opt2) {
2496         opt2.value();
2497       } else {
2498         opt2.value(); // [[unsafe]]
2499       }
2500     }
2501   )");
2502 }
2503 
2504 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightSet) {
2505   ExpectDiagnosticsFor(
2506       R"(
2507     #include "unchecked_optional_access_test.h"
2508 
2509     void target() {
2510       $ns::$optional<int> opt1 = 3;
2511       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2512 
2513       if (opt2 == opt1) {
2514         opt2.value();
2515       } else {
2516         opt2.value(); // [[unsafe]]
2517       }
2518     }
2519   )");
2520 }
2521 
2522 TEST_P(UncheckedOptionalAccessTest, EqualityCheckVerifySetAfterEq) {
2523   ExpectDiagnosticsFor(
2524       R"(
2525     #include "unchecked_optional_access_test.h"
2526 
2527     void target() {
2528       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2529       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2530 
2531       if (opt1 == opt2) {
2532         if (opt1.has_value())
2533           opt2.value();
2534         if (opt2.has_value())
2535           opt1.value();
2536       }
2537     }
2538   )");
2539 }
2540 
2541 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftUnset) {
2542   ExpectDiagnosticsFor(
2543       R"(
2544     #include "unchecked_optional_access_test.h"
2545 
2546     void target() {
2547       $ns::$optional<int> opt1 = $ns::nullopt;
2548       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2549 
2550       if (opt1 == opt2) {
2551         opt2.value(); // [[unsafe]]
2552       } else {
2553         opt2.value();
2554       }
2555     }
2556   )");
2557 }
2558 
2559 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightUnset) {
2560   ExpectDiagnosticsFor(
2561       R"(
2562     #include "unchecked_optional_access_test.h"
2563 
2564     void target() {
2565       $ns::$optional<int> opt1 = $ns::nullopt;
2566       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2567 
2568       if (opt2 == opt1) {
2569         opt2.value(); // [[unsafe]]
2570       } else {
2571         opt2.value();
2572       }
2573     }
2574   )");
2575 }
2576 
2577 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightNullopt) {
2578   ExpectDiagnosticsFor(
2579       R"(
2580     #include "unchecked_optional_access_test.h"
2581 
2582     void target() {
2583       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2584 
2585       if (opt == $ns::nullopt) {
2586         opt.value(); // [[unsafe]]
2587       } else {
2588         opt.value();
2589       }
2590     }
2591   )");
2592 }
2593 
2594 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftNullopt) {
2595   ExpectDiagnosticsFor(
2596       R"(
2597     #include "unchecked_optional_access_test.h"
2598 
2599     void target() {
2600       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2601 
2602       if ($ns::nullopt == opt) {
2603         opt.value(); // [[unsafe]]
2604       } else {
2605         opt.value();
2606       }
2607     }
2608   )");
2609 }
2610 
2611 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightValue) {
2612   ExpectDiagnosticsFor(
2613       R"(
2614     #include "unchecked_optional_access_test.h"
2615 
2616     void target() {
2617       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2618 
2619       if (opt == 3) {
2620         opt.value();
2621       } else {
2622         opt.value(); // [[unsafe]]
2623       }
2624     }
2625   )");
2626 }
2627 
2628 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftValue) {
2629   ExpectDiagnosticsFor(
2630       R"(
2631     #include "unchecked_optional_access_test.h"
2632 
2633     void target() {
2634       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2635 
2636       if (3 == opt) {
2637         opt.value();
2638       } else {
2639         opt.value(); // [[unsafe]]
2640       }
2641     }
2642   )");
2643 }
2644 
2645 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftSet) {
2646   ExpectDiagnosticsFor(
2647       R"(
2648     #include "unchecked_optional_access_test.h"
2649 
2650     void target() {
2651       $ns::$optional<int> opt1 = 3;
2652       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2653 
2654       if (opt1 != opt2) {
2655         opt2.value(); // [[unsafe]]
2656       } else {
2657         opt2.value();
2658       }
2659     }
2660   )");
2661 }
2662 
2663 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightSet) {
2664   ExpectDiagnosticsFor(
2665       R"(
2666     #include "unchecked_optional_access_test.h"
2667 
2668     void target() {
2669       $ns::$optional<int> opt1 = 3;
2670       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2671 
2672       if (opt2 != opt1) {
2673         opt2.value(); // [[unsafe]]
2674       } else {
2675         opt2.value();
2676       }
2677     }
2678   )");
2679 }
2680 
2681 TEST_P(UncheckedOptionalAccessTest, InequalityCheckVerifySetAfterEq) {
2682   ExpectDiagnosticsFor(
2683       R"(
2684     #include "unchecked_optional_access_test.h"
2685 
2686     void target() {
2687       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2688       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2689 
2690       if (opt1 != opt2) {
2691         if (opt1.has_value())
2692           opt2.value(); // [[unsafe]]
2693         if (opt2.has_value())
2694           opt1.value(); // [[unsafe]]
2695       }
2696     }
2697   )");
2698 }
2699 
2700 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftUnset) {
2701   ExpectDiagnosticsFor(
2702       R"(
2703     #include "unchecked_optional_access_test.h"
2704 
2705     void target() {
2706       $ns::$optional<int> opt1 = $ns::nullopt;
2707       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2708 
2709       if (opt1 != opt2) {
2710         opt2.value();
2711       } else {
2712         opt2.value(); // [[unsafe]]
2713       }
2714     }
2715   )");
2716 }
2717 
2718 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightUnset) {
2719   ExpectDiagnosticsFor(
2720       R"(
2721     #include "unchecked_optional_access_test.h"
2722 
2723     void target() {
2724       $ns::$optional<int> opt1 = $ns::nullopt;
2725       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2726 
2727       if (opt2 != opt1) {
2728         opt2.value();
2729       } else {
2730         opt2.value(); // [[unsafe]]
2731       }
2732     }
2733   )");
2734 }
2735 
2736 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightNullopt) {
2737   ExpectDiagnosticsFor(
2738       R"(
2739     #include "unchecked_optional_access_test.h"
2740 
2741     void target() {
2742       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2743 
2744       if (opt != $ns::nullopt) {
2745         opt.value();
2746       } else {
2747         opt.value(); // [[unsafe]]
2748       }
2749     }
2750   )");
2751 }
2752 
2753 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftNullopt) {
2754   ExpectDiagnosticsFor(
2755       R"(
2756     #include "unchecked_optional_access_test.h"
2757 
2758     void target() {
2759       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2760 
2761       if ($ns::nullopt != opt) {
2762         opt.value();
2763       } else {
2764         opt.value(); // [[unsafe]]
2765       }
2766     }
2767   )");
2768 }
2769 
2770 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightValue) {
2771   ExpectDiagnosticsFor(
2772       R"(
2773     #include "unchecked_optional_access_test.h"
2774 
2775     void target() {
2776       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2777 
2778       if (opt != 3) {
2779         opt.value(); // [[unsafe]]
2780       } else {
2781         opt.value();
2782       }
2783     }
2784   )");
2785 }
2786 
2787 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftValue) {
2788   ExpectDiagnosticsFor(
2789       R"(
2790     #include "unchecked_optional_access_test.h"
2791 
2792     void target() {
2793       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2794 
2795       if (3 != opt) {
2796         opt.value(); // [[unsafe]]
2797       } else {
2798         opt.value();
2799       }
2800     }
2801   )");
2802 }
2803 
2804 // Verifies that the model sees through aliases.
2805 TEST_P(UncheckedOptionalAccessTest, WithAlias) {
2806   ExpectDiagnosticsFor(
2807       R"(
2808     #include "unchecked_optional_access_test.h"
2809 
2810     template <typename T>
2811     using MyOptional = $ns::$optional<T>;
2812 
2813     void target(MyOptional<int> opt) {
2814       opt.value(); // [[unsafe]]
2815     }
2816   )");
2817 }
2818 
2819 TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) {
2820   // Basic test that nested values are populated.  We nest an optional because
2821   // its easy to use in a test, but the type of the nested value shouldn't
2822   // matter.
2823   ExpectDiagnosticsFor(
2824       R"(
2825     #include "unchecked_optional_access_test.h"
2826 
2827     using Foo = $ns::$optional<std::string>;
2828 
2829     void target($ns::$optional<Foo> foo) {
2830       if (foo && *foo) {
2831         foo->value();
2832       }
2833     }
2834   )");
2835 
2836   // Mutation is supported for nested values.
2837   ExpectDiagnosticsFor(
2838       R"(
2839     #include "unchecked_optional_access_test.h"
2840 
2841     using Foo = $ns::$optional<std::string>;
2842 
2843     void target($ns::$optional<Foo> foo) {
2844       if (foo && *foo) {
2845         foo->reset();
2846         foo->value(); // [[unsafe]]
2847       }
2848     }
2849   )");
2850 }
2851 
2852 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignValue) {
2853   ExpectDiagnosticsFor(
2854       R"(
2855     #include "unchecked_optional_access_test.h"
2856 
2857     using OptionalInt = $ns::$optional<int>;
2858 
2859     void target($ns::$optional<OptionalInt> opt) {
2860       if (!opt) return;
2861 
2862       // Accessing the outer optional is OK now.
2863       *opt;
2864 
2865       // But accessing the nested optional is still unsafe because we haven't
2866       // checked it.
2867       **opt;  // [[unsafe]]
2868 
2869       *opt = 1;
2870 
2871       // Accessing the nested optional is safe after assigning a value to it.
2872       **opt;
2873     }
2874   )");
2875 }
2876 
2877 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignOptional) {
2878   ExpectDiagnosticsFor(
2879       R"(
2880     #include "unchecked_optional_access_test.h"
2881 
2882     using OptionalInt = $ns::$optional<int>;
2883 
2884     void target($ns::$optional<OptionalInt> opt) {
2885       if (!opt) return;
2886 
2887       // Accessing the outer optional is OK now.
2888       *opt;
2889 
2890       // But accessing the nested optional is still unsafe because we haven't
2891       // checked it.
2892       **opt;  // [[unsafe]]
2893 
2894       // Assign from `optional<short>` so that we trigger conversion assignment
2895       // instead of move assignment.
2896       *opt = $ns::$optional<short>();
2897 
2898       // Accessing the nested optional is still unsafe after assigning an empty
2899       // optional to it.
2900       **opt;  // [[unsafe]]
2901     }
2902   )");
2903 }
2904 
2905 // Tests that structs can be nested. We use an optional field because its easy
2906 // to use in a test, but the type of the field shouldn't matter.
2907 TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) {
2908   ExpectDiagnosticsFor(
2909       R"(
2910     #include "unchecked_optional_access_test.h"
2911 
2912     struct Foo {
2913       $ns::$optional<std::string> opt;
2914     };
2915 
2916     void target($ns::$optional<Foo> foo) {
2917       if (foo && foo->opt) {
2918         foo->opt.value();
2919       }
2920     }
2921   )");
2922 }
2923 
2924 // FIXME: A case that we should handle but currently don't.
2925 // When there is a field of type reference to non-optional, we may
2926 // stop recursively creating storage locations.
2927 // E.g., the field `second` below in `pair` should eventually lead to
2928 // the optional `x` in `A`.
2929 TEST_P(UncheckedOptionalAccessTest, NestedOptionalThroughNonOptionalRefField) {
2930   ExpectDiagnosticsFor(R"(
2931     #include "unchecked_optional_access_test.h"
2932 
2933     struct A {
2934       $ns::$optional<int> x;
2935     };
2936 
2937     struct pair {
2938       int first;
2939       const A &second;
2940     };
2941 
2942     struct B {
2943       $ns::$optional<pair>& nonConstGetRef();
2944     };
2945 
2946     void target(B b) {
2947       const auto& maybe_pair = b.nonConstGetRef();
2948       if (!maybe_pair.has_value())
2949         return;
2950 
2951       if(!maybe_pair->second.x.has_value())
2952         return;
2953       maybe_pair->second.x.value();  // [[unsafe]]
2954     }
2955   )");
2956 }
2957 
2958 TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) {
2959   ExpectDiagnosticsFor(
2960       R"(
2961     #include "unchecked_optional_access_test.h"
2962 
2963     using Foo = $ns::$optional<std::string>;
2964 
2965     void target($ns::$optional<Foo> foo, bool b) {
2966       if (!foo.has_value()) return;
2967       if (b) {
2968         if (!foo->has_value()) return;
2969         // We have created `foo.value()`.
2970         foo->value();
2971       } else {
2972         if (!foo->has_value()) return;
2973         // We have created `foo.value()` again, in a different environment.
2974         foo->value();
2975       }
2976       // Now we merge the two values. UncheckedOptionalAccessModel::merge() will
2977       // throw away the "value" property.
2978       foo->value();
2979     }
2980   )");
2981 }
2982 
2983 // This test is aimed at the core model, not the diagnostic. It is a regression
2984 // test against a crash when using non-trivial smart pointers, like
2985 // `std::unique_ptr`. As such, it doesn't test the access itself, which would be
2986 // ignored regardless because of `IgnoreSmartPointerDereference = true`, above.
2987 TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) {
2988   ExpectDiagnosticsFor(
2989       R"(
2990     #include "unchecked_optional_access_test.h"
2991 
2992     template <typename T>
2993     struct smart_ptr {
2994       typename std::add_lvalue_reference<T>::type operator*() &;
2995     };
2996 
2997     void target() {
2998       smart_ptr<$ns::$optional<int>> x;
2999       // Verify that this assignment does not crash.
3000       *x = 3;
3001     }
3002   )");
3003 }
3004 
3005 TEST_P(UncheckedOptionalAccessTest, CorrelatedBranches) {
3006   ExpectDiagnosticsFor(R"code(
3007     #include "unchecked_optional_access_test.h"
3008 
3009     void target(bool b, $ns::$optional<int> opt) {
3010       if (b || opt.has_value()) {
3011         if (!b) {
3012           opt.value();
3013         }
3014       }
3015     }
3016   )code");
3017 
3018   ExpectDiagnosticsFor(R"code(
3019     #include "unchecked_optional_access_test.h"
3020 
3021     void target(bool b, $ns::$optional<int> opt) {
3022       if (b && !opt.has_value()) return;
3023       if (b) {
3024         opt.value();
3025       }
3026     }
3027   )code");
3028 
3029   ExpectDiagnosticsFor(
3030       R"code(
3031     #include "unchecked_optional_access_test.h"
3032 
3033     void target(bool b, $ns::$optional<int> opt) {
3034       if (opt.has_value()) b = true;
3035       if (b) {
3036         opt.value(); // [[unsafe]]
3037       }
3038     }
3039   )code");
3040 
3041   ExpectDiagnosticsFor(R"code(
3042     #include "unchecked_optional_access_test.h"
3043 
3044     void target(bool b, $ns::$optional<int> opt) {
3045       if (b) return;
3046       if (opt.has_value()) b = true;
3047       if (b) {
3048         opt.value();
3049       }
3050     }
3051   )code");
3052 
3053   ExpectDiagnosticsFor(R"(
3054     #include "unchecked_optional_access_test.h"
3055 
3056     void target(bool b, $ns::$optional<int> opt) {
3057       if (opt.has_value() == b) {
3058         if (b) {
3059           opt.value();
3060         }
3061       }
3062     }
3063   )");
3064 
3065   ExpectDiagnosticsFor(R"(
3066     #include "unchecked_optional_access_test.h"
3067 
3068     void target(bool b, $ns::$optional<int> opt) {
3069       if (opt.has_value() != b) {
3070         if (!b) {
3071           opt.value();
3072         }
3073       }
3074     }
3075   )");
3076 
3077   ExpectDiagnosticsFor(R"(
3078     #include "unchecked_optional_access_test.h"
3079 
3080     void target(bool b) {
3081       $ns::$optional<int> opt1 = $ns::nullopt;
3082       $ns::$optional<int> opt2;
3083       if (b) {
3084         opt2 = $ns::nullopt;
3085       } else {
3086         opt2 = $ns::nullopt;
3087       }
3088       if (opt2.has_value()) {
3089         opt1.value();
3090       }
3091     }
3092   )");
3093 }
3094 
3095 TEST_P(UncheckedOptionalAccessTest, JoinDistinctValues) {
3096   ExpectDiagnosticsFor(
3097       R"code(
3098     #include "unchecked_optional_access_test.h"
3099 
3100     void target(bool b) {
3101       $ns::$optional<int> opt;
3102       if (b) {
3103         opt = Make<$ns::$optional<int>>();
3104       } else {
3105         opt = Make<$ns::$optional<int>>();
3106       }
3107       if (opt.has_value()) {
3108         opt.value();
3109       } else {
3110         opt.value(); // [[unsafe]]
3111       }
3112     }
3113   )code");
3114 
3115   ExpectDiagnosticsFor(R"code(
3116     #include "unchecked_optional_access_test.h"
3117 
3118     void target(bool b) {
3119       $ns::$optional<int> opt;
3120       if (b) {
3121         opt = Make<$ns::$optional<int>>();
3122         if (!opt.has_value()) return;
3123       } else {
3124         opt = Make<$ns::$optional<int>>();
3125         if (!opt.has_value()) return;
3126       }
3127       opt.value();
3128     }
3129   )code");
3130 
3131   ExpectDiagnosticsFor(
3132       R"code(
3133     #include "unchecked_optional_access_test.h"
3134 
3135     void target(bool b) {
3136       $ns::$optional<int> opt;
3137       if (b) {
3138         opt = Make<$ns::$optional<int>>();
3139         if (!opt.has_value()) return;
3140       } else {
3141         opt = Make<$ns::$optional<int>>();
3142       }
3143       opt.value(); // [[unsafe]]
3144     }
3145   )code");
3146 
3147   ExpectDiagnosticsFor(
3148       R"code(
3149     #include "unchecked_optional_access_test.h"
3150 
3151     void target(bool b) {
3152       $ns::$optional<int> opt;
3153       if (b) {
3154         opt = 1;
3155       } else {
3156         opt = 2;
3157       }
3158       opt.value();
3159     }
3160   )code");
3161 
3162   ExpectDiagnosticsFor(
3163       R"code(
3164     #include "unchecked_optional_access_test.h"
3165 
3166     void target(bool b) {
3167       $ns::$optional<int> opt;
3168       if (b) {
3169         opt = 1;
3170       } else {
3171         opt = Make<$ns::$optional<int>>();
3172       }
3173       opt.value(); // [[unsafe]]
3174     }
3175   )code");
3176 }
3177 
3178 TEST_P(UncheckedOptionalAccessTest, AccessValueInLoop) {
3179   ExpectDiagnosticsFor(R"(
3180     #include "unchecked_optional_access_test.h"
3181 
3182     void target() {
3183       $ns::$optional<int> opt = 3;
3184       while (Make<bool>()) {
3185         opt.value();
3186       }
3187     }
3188   )");
3189 }
3190 
3191 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopWithCheckSafe) {
3192   ExpectDiagnosticsFor(R"(
3193     #include "unchecked_optional_access_test.h"
3194 
3195     void target() {
3196       $ns::$optional<int> opt = 3;
3197       while (Make<bool>()) {
3198         opt.value();
3199 
3200         opt = Make<$ns::$optional<int>>();
3201         if (!opt.has_value()) return;
3202       }
3203     }
3204   )");
3205 }
3206 
3207 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopNoCheckUnsafe) {
3208   ExpectDiagnosticsFor(
3209       R"(
3210     #include "unchecked_optional_access_test.h"
3211 
3212     void target() {
3213       $ns::$optional<int> opt = 3;
3214       while (Make<bool>()) {
3215         opt.value(); // [[unsafe]]
3216 
3217         opt = Make<$ns::$optional<int>>();
3218       }
3219     }
3220   )");
3221 }
3222 
3223 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnsetUnsafe) {
3224   ExpectDiagnosticsFor(
3225       R"(
3226     #include "unchecked_optional_access_test.h"
3227 
3228     void target() {
3229       $ns::$optional<int> opt = 3;
3230       while (Make<bool>())
3231         opt = $ns::nullopt;
3232       $ns::$optional<int> opt2 = $ns::nullopt;
3233       if (opt.has_value())
3234         opt2 = $ns::$optional<int>(3);
3235       opt2.value(); // [[unsafe]]
3236     }
3237   )");
3238 }
3239 
3240 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToSetUnsafe) {
3241   ExpectDiagnosticsFor(
3242       R"(
3243     #include "unchecked_optional_access_test.h"
3244 
3245     void target() {
3246       $ns::$optional<int> opt = $ns::nullopt;
3247       while (Make<bool>())
3248         opt = $ns::$optional<int>(3);
3249       $ns::$optional<int> opt2 = $ns::nullopt;
3250       if (!opt.has_value())
3251         opt2 = $ns::$optional<int>(3);
3252       opt2.value(); // [[unsafe]]
3253     }
3254   )");
3255 }
3256 
3257 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnknownUnsafe) {
3258   ExpectDiagnosticsFor(
3259       R"(
3260     #include "unchecked_optional_access_test.h"
3261 
3262     void target() {
3263       $ns::$optional<int> opt = $ns::nullopt;
3264       while (Make<bool>())
3265         opt = Make<$ns::$optional<int>>();
3266       $ns::$optional<int> opt2 = $ns::nullopt;
3267       if (!opt.has_value())
3268         opt2 = $ns::$optional<int>(3);
3269       opt2.value(); // [[unsafe]]
3270     }
3271   )");
3272 }
3273 
3274 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopBadConditionUnsafe) {
3275   ExpectDiagnosticsFor(
3276       R"(
3277     #include "unchecked_optional_access_test.h"
3278 
3279     void target() {
3280       $ns::$optional<int> opt = 3;
3281       while (Make<bool>()) {
3282         opt.value(); // [[unsafe]]
3283 
3284         opt = Make<$ns::$optional<int>>();
3285         if (!opt.has_value()) continue;
3286       }
3287     }
3288   )");
3289 }
3290 
3291 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromStruct) {
3292   ExpectDiagnosticsFor(R"(
3293     #include "unchecked_optional_access_test.h"
3294 
3295     struct kv { $ns::$optional<int> opt; int x; };
3296     int target() {
3297       auto [contents, x] = Make<kv>();
3298       return contents ? *contents : x;
3299     }
3300   )");
3301 
3302   ExpectDiagnosticsFor(R"(
3303     #include "unchecked_optional_access_test.h"
3304 
3305     template <typename T1, typename T2>
3306     struct pair { T1 fst;  T2 snd; };
3307     int target() {
3308       auto [contents, x] = Make<pair<$ns::$optional<int>, int>>();
3309       return contents ? *contents : x;
3310     }
3311   )");
3312 }
3313 
3314 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromTupleLikeType) {
3315   ExpectDiagnosticsFor(R"(
3316     #include "unchecked_optional_access_test.h"
3317 
3318     namespace std {
3319     template <class> struct tuple_size;
3320     template <size_t, class> struct tuple_element;
3321     template <class...> class tuple;
3322 
3323     template <class... T>
3324     struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {};
3325 
3326     template <size_t I, class... T>
3327     struct tuple_element<I, tuple<T...>> {
3328       using type =  __type_pack_element<I, T...>;
3329     };
3330 
3331     template <class...> class tuple {};
3332     template <size_t I, class... T>
3333     typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
3334     } // namespace std
3335 
3336     std::tuple<$ns::$optional<const char *>, int> get_opt();
3337     void target() {
3338       auto [content, ck] = get_opt();
3339       content ? *content : "";
3340     }
3341   )");
3342 }
3343 
3344 TEST_P(UncheckedOptionalAccessTest, CtorInitializerNullopt) {
3345   using namespace ast_matchers;
3346   ExpectDiagnosticsFor(
3347       R"(
3348     #include "unchecked_optional_access_test.h"
3349 
3350     struct Target {
3351       Target(): opt($ns::nullopt) {
3352         opt.value(); // [[unsafe]]
3353       }
3354       $ns::$optional<int> opt;
3355     };
3356   )",
3357       cxxConstructorDecl(ofClass(hasName("Target"))));
3358 }
3359 
3360 TEST_P(UncheckedOptionalAccessTest, CtorInitializerValue) {
3361   using namespace ast_matchers;
3362   ExpectDiagnosticsFor(
3363       R"(
3364     #include "unchecked_optional_access_test.h"
3365 
3366     struct Target {
3367       Target(): opt(3) {
3368         opt.value();
3369       }
3370       $ns::$optional<int> opt;
3371     };
3372   )",
3373       cxxConstructorDecl(ofClass(hasName("Target"))));
3374 }
3375 
3376 // This is regression test, it shouldn't crash.
3377 TEST_P(UncheckedOptionalAccessTest, Bitfield) {
3378   using namespace ast_matchers;
3379   ExpectDiagnosticsFor(
3380       R"(
3381     #include "unchecked_optional_access_test.h"
3382     struct Dst {
3383       unsigned int n : 1;
3384     };
3385     void target() {
3386       $ns::$optional<bool> v;
3387       Dst d;
3388       if (v.has_value())
3389         d.n = v.value();
3390     }
3391   )");
3392 }
3393 
3394 TEST_P(UncheckedOptionalAccessTest, LambdaParam) {
3395   ExpectDiagnosticsForLambda(R"(
3396     #include "unchecked_optional_access_test.h"
3397 
3398     void target() {
3399       []($ns::$optional<int> opt) {
3400         if (opt.has_value()) {
3401           opt.value();
3402         } else {
3403           opt.value(); // [[unsafe]]
3404         }
3405       }(Make<$ns::$optional<int>>());
3406     }
3407   )");
3408 }
3409 
3410 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopy) {
3411   ExpectDiagnosticsForLambda(R"(
3412     #include "unchecked_optional_access_test.h"
3413 
3414     void target($ns::$optional<int> opt) {
3415       [opt]() {
3416         if (opt.has_value()) {
3417           opt.value();
3418         } else {
3419           opt.value(); // [[unsafe]]
3420         }
3421       }();
3422     }
3423   )");
3424 }
3425 
3426 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReference) {
3427   ExpectDiagnosticsForLambda(R"(
3428     #include "unchecked_optional_access_test.h"
3429 
3430     void target($ns::$optional<int> opt) {
3431       [&opt]() {
3432         if (opt.has_value()) {
3433           opt.value();
3434         } else {
3435           opt.value(); // [[unsafe]]
3436         }
3437       }();
3438     }
3439   )");
3440 }
3441 
3442 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureWithInitializer) {
3443   ExpectDiagnosticsForLambda(R"(
3444     #include "unchecked_optional_access_test.h"
3445 
3446     void target($ns::$optional<int> opt) {
3447       [opt2=opt]() {
3448         if (opt2.has_value()) {
3449           opt2.value();
3450         } else {
3451           opt2.value(); // [[unsafe]]
3452         }
3453       }();
3454     }
3455   )");
3456 }
3457 
3458 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopyImplicit) {
3459   ExpectDiagnosticsForLambda(R"(
3460     #include "unchecked_optional_access_test.h"
3461 
3462     void target($ns::$optional<int> opt) {
3463       [=]() {
3464         if (opt.has_value()) {
3465           opt.value();
3466         } else {
3467           opt.value(); // [[unsafe]]
3468         }
3469       }();
3470     }
3471   )");
3472 }
3473 
3474 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReferenceImplicit) {
3475   ExpectDiagnosticsForLambda(R"(
3476     #include "unchecked_optional_access_test.h"
3477 
3478     void target($ns::$optional<int> opt) {
3479       [&]() {
3480         if (opt.has_value()) {
3481           opt.value();
3482         } else {
3483           opt.value(); // [[unsafe]]
3484         }
3485       }();
3486     }
3487   )");
3488 }
3489 
3490 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureThis) {
3491   ExpectDiagnosticsForLambda(R"(
3492     #include "unchecked_optional_access_test.h"
3493 
3494     struct Foo {
3495       $ns::$optional<int> opt;
3496 
3497       void target() {
3498         [this]() {
3499           if (opt.has_value()) {
3500             opt.value();
3501           } else {
3502             opt.value(); // [[unsafe]]
3503           }
3504         }();
3505       }
3506     };
3507   )");
3508 }
3509 
3510 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureStateNotPropagated) {
3511   // We can't propagate information from the surrounding context.
3512   ExpectDiagnosticsForLambda(R"(
3513     #include "unchecked_optional_access_test.h"
3514 
3515     void target($ns::$optional<int> opt) {
3516       if (opt.has_value()) {
3517         [&opt]() {
3518           opt.value(); // [[unsafe]]
3519         }();
3520       }
3521     }
3522   )");
3523 }
3524 
3525 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptional) {
3526   ExpectDiagnosticsFor(R"(
3527     #include "unchecked_optional_access_test.h"
3528 
3529     struct Derived : public $ns::$optional<int> {};
3530 
3531     void target(Derived opt) {
3532       *opt;  // [[unsafe]]
3533       if (opt.has_value())
3534         *opt;
3535 
3536       // The same thing, but with a pointer receiver.
3537       Derived *popt = &opt;
3538       **popt;  // [[unsafe]]
3539       if (popt->has_value())
3540         **popt;
3541     }
3542   )");
3543 }
3544 
3545 TEST_P(UncheckedOptionalAccessTest, ClassTemplateDerivedFromOptional) {
3546   ExpectDiagnosticsFor(R"(
3547     #include "unchecked_optional_access_test.h"
3548 
3549     template <class T>
3550     struct Derived : public $ns::$optional<T> {};
3551 
3552     void target(Derived<int> opt) {
3553       *opt;  // [[unsafe]]
3554       if (opt.has_value())
3555         *opt;
3556 
3557       // The same thing, but with a pointer receiver.
3558       Derived<int> *popt = &opt;
3559       **popt;  // [[unsafe]]
3560       if (popt->has_value())
3561         **popt;
3562     }
3563   )");
3564 }
3565 
3566 TEST_P(UncheckedOptionalAccessTest, ClassDerivedPrivatelyFromOptional) {
3567   // Classes that derive privately from optional can themselves still call
3568   // member functions of optional. Check that we model the optional correctly
3569   // in this situation.
3570   ExpectDiagnosticsFor(R"(
3571     #include "unchecked_optional_access_test.h"
3572 
3573     struct Derived : private $ns::$optional<int> {
3574       void Method() {
3575         **this;  // [[unsafe]]
3576         if (this->has_value())
3577           **this;
3578       }
3579     };
3580   )",
3581                        ast_matchers::hasName("Method"));
3582 }
3583 
3584 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptionalValueConstructor) {
3585   ExpectDiagnosticsFor(R"(
3586     #include "unchecked_optional_access_test.h"
3587 
3588     struct Derived : public $ns::$optional<int> {
3589       Derived(int);
3590     };
3591 
3592     void target(Derived opt) {
3593       *opt;  // [[unsafe]]
3594       opt = 1;
3595       *opt;
3596     }
3597   )");
3598 }
3599 
3600 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessor) {
3601   ExpectDiagnosticsFor(R"cc(
3602     #include "unchecked_optional_access_test.h"
3603 
3604     struct A {
3605       const $ns::$optional<int>& get() const { return x; }
3606       $ns::$optional<int> x;
3607     };
3608 
3609     void target(A& a) {
3610       if (a.get().has_value()) {
3611         a.get().value();
3612       }
3613     }
3614   )cc");
3615 }
3616 
3617 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModInBetween) {
3618   ExpectDiagnosticsFor(R"cc(
3619     #include "unchecked_optional_access_test.h"
3620 
3621     struct A {
3622       const $ns::$optional<int>& get() const { return x; }
3623       void clear();
3624       $ns::$optional<int> x;
3625     };
3626 
3627     void target(A& a) {
3628       if (a.get().has_value()) {
3629         a.clear();
3630         a.get().value();  // [[unsafe]]
3631       }
3632     }
3633   )cc");
3634 }
3635 
3636 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModReturningOptional) {
3637   ExpectDiagnosticsFor(R"cc(
3638     #include "unchecked_optional_access_test.h"
3639 
3640     struct A {
3641       const $ns::$optional<int>& get() const { return x; }
3642       $ns::$optional<int> take();
3643       $ns::$optional<int> x;
3644     };
3645 
3646     void target(A& a) {
3647       if (a.get().has_value()) {
3648         $ns::$optional<int> other = a.take();
3649         a.get().value();  // [[unsafe]]
3650         if (other.has_value()) {
3651           other.value();
3652         }
3653       }
3654     }
3655   )cc");
3656 }
3657 
3658 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorDifferentObjects) {
3659   ExpectDiagnosticsFor(R"cc(
3660     #include "unchecked_optional_access_test.h"
3661 
3662     struct A {
3663       const $ns::$optional<int>& get() const { return x; }
3664       $ns::$optional<int> x;
3665     };
3666 
3667     void target(A& a1, A& a2) {
3668       if (a1.get().has_value()) {
3669         a2.get().value();  // [[unsafe]]
3670       }
3671     }
3672   )cc");
3673 }
3674 
3675 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorLoop) {
3676   ExpectDiagnosticsFor(R"cc(
3677     #include "unchecked_optional_access_test.h"
3678 
3679     struct A {
3680       const $ns::$optional<int>& get() const { return x; }
3681       $ns::$optional<int> x;
3682     };
3683 
3684     void target(A& a, int N) {
3685       for (int i = 0; i < N; ++i) {
3686         if (a.get().has_value()) {
3687           a.get().value();
3688         }
3689       }
3690     }
3691   )cc");
3692 }
3693 
3694 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessor) {
3695   ExpectDiagnosticsFor(R"cc(
3696     #include "unchecked_optional_access_test.h"
3697 
3698     struct A {
3699       $ns::$optional<int> get() const { return x; }
3700       $ns::$optional<int> x;
3701     };
3702 
3703     void target(A& a) {
3704       if (a.get().has_value()) {
3705         a.get().value();
3706       }
3707     }
3708   )cc");
3709 }
3710 
3711 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessorWithModInBetween) {
3712   ExpectDiagnosticsFor(R"cc(
3713     #include "unchecked_optional_access_test.h"
3714 
3715     struct A {
3716       $ns::$optional<int> get() const { return x; }
3717       void clear();
3718       $ns::$optional<int> x;
3719     };
3720 
3721     void target(A& a) {
3722       if (a.get().has_value()) {
3723         a.clear();
3724         a.get().value();  // [[unsafe]]
3725       }
3726     }
3727   )cc");
3728 }
3729 
3730 TEST_P(UncheckedOptionalAccessTest, ConstPointerAccessor) {
3731   ExpectDiagnosticsFor(R"cc(
3732      #include "unchecked_optional_access_test.h"
3733 
3734     struct A {
3735       $ns::$optional<int> x;
3736     };
3737 
3738     struct MyUniquePtr {
3739       A* operator->() const;
3740     };
3741 
3742     void target(MyUniquePtr p) {
3743       if (p->x) {
3744         *p->x;
3745       }
3746     }
3747   )cc",
3748                        /*IgnoreSmartPointerDereference=*/false);
3749 }
3750 
3751 TEST_P(UncheckedOptionalAccessTest, ConstPointerAccessorWithModInBetween) {
3752   ExpectDiagnosticsFor(R"cc(
3753     #include "unchecked_optional_access_test.h"
3754 
3755     struct A {
3756       $ns::$optional<int> x;
3757     };
3758 
3759     struct MyUniquePtr {
3760       A* operator->() const;
3761       void reset(A*);
3762     };
3763 
3764     void target(MyUniquePtr p) {
3765       if (p->x) {
3766         p.reset(nullptr);
3767         *p->x;  // [[unsafe]]
3768       }
3769     }
3770   )cc",
3771                        /*IgnoreSmartPointerDereference=*/false);
3772 }
3773 
3774 TEST_P(UncheckedOptionalAccessTest, SmartPointerAccessorMixed) {
3775   ExpectDiagnosticsFor(R"cc(
3776      #include "unchecked_optional_access_test.h"
3777 
3778     struct A {
3779       $ns::$optional<int> x;
3780     };
3781 
3782     namespace absl {
3783     template<typename T>
3784     class StatusOr {
3785       public:
3786       bool ok() const;
3787 
3788       const T& operator*() const&;
3789       T& operator*() &;
3790 
3791       const T* operator->() const;
3792       T* operator->();
3793 
3794       const T& value() const;
3795       T& value();
3796     };
3797     }
3798 
3799     void target(absl::StatusOr<A> &mut, const absl::StatusOr<A> &imm) {
3800       if (!mut.ok() || !imm.ok())
3801         return;
3802 
3803       if (mut->x.has_value()) {
3804         mut->x.value();
3805         ((*mut).x).value();
3806         (mut.value().x).value();
3807 
3808         // check flagged after modifying
3809         mut = imm;
3810         mut->x.value();  // [[unsafe]]
3811       }
3812       if (imm->x.has_value()) {
3813         imm->x.value();
3814         ((*imm).x).value();
3815         (imm.value().x).value();
3816       }
3817     }
3818   )cc",
3819                        /*IgnoreSmartPointerDereference=*/false);
3820 }
3821 
3822 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessor) {
3823   ExpectDiagnosticsFor(R"cc(
3824     #include "unchecked_optional_access_test.h"
3825 
3826     struct A {
3827       bool isFoo() const { return f; }
3828       bool f;
3829     };
3830 
3831     void target(A& a) {
3832       std::optional<int> opt;
3833       if (a.isFoo()) {
3834         opt = 1;
3835       }
3836       if (a.isFoo()) {
3837         opt.value();
3838       }
3839     }
3840   )cc");
3841 }
3842 
3843 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessorWithModInBetween) {
3844   ExpectDiagnosticsFor(R"cc(
3845     #include "unchecked_optional_access_test.h"
3846 
3847     struct A {
3848       bool isFoo() const { return f; }
3849       void clear();
3850       bool f;
3851     };
3852 
3853     void target(A& a) {
3854       std::optional<int> opt;
3855       if (a.isFoo()) {
3856         opt = 1;
3857       }
3858       a.clear();
3859       if (a.isFoo()) {
3860         opt.value();  // [[unsafe]]
3861       }
3862     }
3863   )cc");
3864 }
3865 
3866 // FIXME: Add support for:
3867 // - constructors (copy, move)
3868 // - assignment operators (default, copy, move)
3869 // - invalidation (passing optional by non-const reference/pointer)
3870