xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (revision 1f6741c1645954b1f4b2fbca470a20081f5e75af)
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     ExpectDiagnosticsFor(SourceCode, ast_matchers::hasName("target"));
1287   }
1288 
1289   void ExpectDiagnosticsForLambda(std::string SourceCode) {
1290     ExpectDiagnosticsFor(
1291         SourceCode, ast_matchers::hasDeclContext(
1292                         ast_matchers::cxxRecordDecl(ast_matchers::isLambda())));
1293   }
1294 
1295   template <typename FuncDeclMatcher>
1296   void ExpectDiagnosticsFor(std::string SourceCode,
1297                             FuncDeclMatcher FuncMatcher) {
1298     // Run in C++17 and C++20 mode to cover differences in the AST between modes
1299     // (e.g. C++20 can contain `CXXRewrittenBinaryOperator`).
1300     for (const char *CxxMode : {"-std=c++17", "-std=c++20"})
1301       ExpectDiagnosticsFor(SourceCode, FuncMatcher, CxxMode);
1302   }
1303 
1304   template <typename FuncDeclMatcher>
1305   void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher,
1306                             const char *CxxMode) {
1307     ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName);
1308     ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName);
1309 
1310     std::vector<std::pair<std::string, std::string>> Headers;
1311     Headers.emplace_back("cstddef.h", CSDtdDefHeader);
1312     Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader);
1313     Headers.emplace_back("std_string.h", StdStringHeader);
1314     Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader);
1315     Headers.emplace_back("std_utility.h", StdUtilityHeader);
1316     Headers.emplace_back("std_optional.h", StdOptionalHeader);
1317     Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader);
1318     Headers.emplace_back("absl_optional.h", AbslOptionalHeader);
1319     Headers.emplace_back("base_optional.h", BaseOptionalHeader);
1320     Headers.emplace_back("unchecked_optional_access_test.h", R"(
1321       #include "absl_optional.h"
1322       #include "base_optional.h"
1323       #include "std_initializer_list.h"
1324       #include "std_optional.h"
1325       #include "std_string.h"
1326       #include "std_utility.h"
1327 
1328       template <typename T>
1329       T Make();
1330     )");
1331     UncheckedOptionalAccessModelOptions Options{
1332         /*IgnoreSmartPointerDereference=*/true};
1333     std::vector<SourceLocation> Diagnostics;
1334     llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
1335         AnalysisInputs<UncheckedOptionalAccessModel>(
1336             SourceCode, std::move(FuncMatcher),
1337             [](ASTContext &Ctx, Environment &Env) {
1338               return UncheckedOptionalAccessModel(Ctx, Env);
1339             })
1340             .withDiagnosisCallbacks(
1341                 {/*Before=*/[&Diagnostics,
1342                              Diagnoser =
1343                                  UncheckedOptionalAccessDiagnoser(Options)](
1344                                 ASTContext &Ctx, const CFGElement &Elt,
1345                                 const TransferStateForDiagnostics<
1346                                     UncheckedOptionalAccessLattice>
1347                                     &State) mutable {
1348                    auto EltDiagnostics = Diagnoser(Elt, Ctx, State);
1349                    llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
1350                  },
1351                  /*After=*/nullptr})
1352             .withASTBuildArgs(
1353                 {"-fsyntax-only", CxxMode, "-Wno-undefined-inline"})
1354             .withASTBuildVirtualMappedFiles(
1355                 tooling::FileContentMappings(Headers.begin(), Headers.end())),
1356         /*VerifyResults=*/[&Diagnostics](
1357                               const llvm::DenseMap<unsigned, std::string>
1358                                   &Annotations,
1359                               const AnalysisOutputs &AO) {
1360           llvm::DenseSet<unsigned> AnnotationLines;
1361           for (const auto &[Line, _] : Annotations) {
1362             AnnotationLines.insert(Line);
1363           }
1364           auto &SrcMgr = AO.ASTCtx.getSourceManager();
1365           llvm::DenseSet<unsigned> DiagnosticLines;
1366           for (SourceLocation &Loc : Diagnostics) {
1367             unsigned Line = SrcMgr.getPresumedLineNumber(Loc);
1368             DiagnosticLines.insert(Line);
1369             if (!AnnotationLines.contains(Line)) {
1370               IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
1371                   new DiagnosticOptions());
1372               TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
1373                                 DiagOpts.get());
1374               TD.emitDiagnostic(FullSourceLoc(Loc, SrcMgr),
1375                                 DiagnosticsEngine::Error,
1376                                 "unexpected diagnostic", {}, {});
1377             }
1378           }
1379 
1380           EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines));
1381         });
1382     if (Error)
1383       FAIL() << llvm::toString(std::move(Error));
1384   }
1385 };
1386 
1387 INSTANTIATE_TEST_SUITE_P(
1388     UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
1389     ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
1390                       OptionalTypeIdentifier{"absl", "optional"},
1391                       OptionalTypeIdentifier{"base", "Optional"}),
1392     [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
1393       return Info.param.NamespaceName;
1394     });
1395 
1396 // Verifies that similarly-named types are ignored.
1397 TEST_P(UncheckedOptionalAccessTest, NonTrackedOptionalType) {
1398   ExpectDiagnosticsFor(
1399       R"(
1400     namespace other {
1401     namespace $ns {
1402     template <typename T>
1403     struct $optional {
1404       T value();
1405     };
1406     }
1407 
1408     void target($ns::$optional<int> opt) {
1409       opt.value();
1410     }
1411     }
1412   )");
1413 }
1414 
1415 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
1416   ExpectDiagnosticsFor(R"(
1417     void target() {
1418       (void)0;
1419     }
1420   )");
1421 }
1422 
1423 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
1424   ExpectDiagnosticsFor(
1425       R"(
1426     #include "unchecked_optional_access_test.h"
1427 
1428     void target($ns::$optional<int> opt) {
1429       opt.value(); // [[unsafe]]
1430     }
1431   )");
1432 
1433   ExpectDiagnosticsFor(
1434       R"(
1435     #include "unchecked_optional_access_test.h"
1436 
1437     void target($ns::$optional<int> opt) {
1438       std::move(opt).value(); // [[unsafe]]
1439     }
1440   )");
1441 }
1442 
1443 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
1444   ExpectDiagnosticsFor(
1445       R"(
1446     #include "unchecked_optional_access_test.h"
1447 
1448     void target($ns::$optional<int> opt) {
1449       *opt; // [[unsafe]]
1450     }
1451   )");
1452 
1453   ExpectDiagnosticsFor(
1454       R"(
1455     #include "unchecked_optional_access_test.h"
1456 
1457     void target($ns::$optional<int> opt) {
1458       *std::move(opt); // [[unsafe]]
1459     }
1460   )");
1461 }
1462 
1463 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
1464   ExpectDiagnosticsFor(
1465       R"(
1466     #include "unchecked_optional_access_test.h"
1467 
1468     struct Foo {
1469       void foo();
1470     };
1471 
1472     void target($ns::$optional<Foo> opt) {
1473       opt->foo(); // [[unsafe]]
1474     }
1475   )");
1476 
1477   ExpectDiagnosticsFor(
1478       R"(
1479     #include "unchecked_optional_access_test.h"
1480 
1481     struct Foo {
1482       void foo();
1483     };
1484 
1485     void target($ns::$optional<Foo> opt) {
1486       std::move(opt)->foo(); // [[unsafe]]
1487     }
1488   )");
1489 }
1490 
1491 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
1492   ExpectDiagnosticsFor(R"(
1493     #include "unchecked_optional_access_test.h"
1494 
1495     void target($ns::$optional<int> opt) {
1496       if (opt.has_value()) {
1497         opt.value();
1498       }
1499     }
1500   )");
1501 }
1502 
1503 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
1504   ExpectDiagnosticsFor(R"(
1505     #include "unchecked_optional_access_test.h"
1506 
1507     void target($ns::$optional<int> opt) {
1508       if (opt) {
1509         opt.value();
1510       }
1511     }
1512   )");
1513 }
1514 
1515 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
1516   ExpectDiagnosticsFor(
1517       R"(
1518     #include "unchecked_optional_access_test.h"
1519 
1520     void target() {
1521       Make<$ns::$optional<int>>().value(); // [[unsafe]]
1522       (void)0;
1523     }
1524   )");
1525 
1526   ExpectDiagnosticsFor(
1527       R"(
1528     #include "unchecked_optional_access_test.h"
1529 
1530     void target($ns::$optional<int> opt) {
1531       std::move(opt).value(); // [[unsafe]]
1532     }
1533   )");
1534 }
1535 
1536 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
1537   ExpectDiagnosticsFor(
1538       R"(
1539     #include "unchecked_optional_access_test.h"
1540 
1541     void target() {
1542       $ns::$optional<int> opt;
1543       opt.value(); // [[unsafe]]
1544     }
1545   )");
1546 }
1547 
1548 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
1549   ExpectDiagnosticsFor(
1550       R"(
1551     #include "unchecked_optional_access_test.h"
1552 
1553     void target() {
1554       $ns::$optional<int> opt($ns::nullopt);
1555       opt.value(); // [[unsafe]]
1556     }
1557   )");
1558 }
1559 
1560 TEST_P(UncheckedOptionalAccessTest, NulloptConstructorWithSugaredType) {
1561   ExpectDiagnosticsFor(
1562       R"(
1563     #include "unchecked_optional_access_test.h"
1564     template <typename T>
1565     using wrapper = T;
1566 
1567     template <typename T>
1568     wrapper<T> wrap(T);
1569 
1570     void target() {
1571       $ns::$optional<int> opt(wrap($ns::nullopt));
1572       opt.value(); // [[unsafe]]
1573     }
1574   )");
1575 }
1576 
1577 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
1578   ExpectDiagnosticsFor(R"(
1579     #include "unchecked_optional_access_test.h"
1580 
1581     void target() {
1582       $ns::$optional<int> opt($ns::in_place, 3);
1583       opt.value();
1584     }
1585   )");
1586 
1587   ExpectDiagnosticsFor(R"(
1588     #include "unchecked_optional_access_test.h"
1589 
1590     struct Foo {};
1591 
1592     void target() {
1593       $ns::$optional<Foo> opt($ns::in_place);
1594       opt.value();
1595     }
1596   )");
1597 
1598   ExpectDiagnosticsFor(R"(
1599     #include "unchecked_optional_access_test.h"
1600 
1601     struct Foo {
1602       explicit Foo(int, bool);
1603     };
1604 
1605     void target() {
1606       $ns::$optional<Foo> opt($ns::in_place, 3, false);
1607       opt.value();
1608     }
1609   )");
1610 
1611   ExpectDiagnosticsFor(R"(
1612     #include "unchecked_optional_access_test.h"
1613 
1614     struct Foo {
1615       explicit Foo(std::initializer_list<int>);
1616     };
1617 
1618     void target() {
1619       $ns::$optional<Foo> opt($ns::in_place, {3});
1620       opt.value();
1621     }
1622   )");
1623 }
1624 
1625 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
1626   ExpectDiagnosticsFor(R"(
1627     #include "unchecked_optional_access_test.h"
1628 
1629     void target() {
1630       $ns::$optional<int> opt(21);
1631       opt.value();
1632     }
1633   )");
1634 
1635   ExpectDiagnosticsFor(R"(
1636     #include "unchecked_optional_access_test.h"
1637 
1638     void target() {
1639       $ns::$optional<int> opt = $ns::$optional<int>(21);
1640       opt.value();
1641     }
1642   )");
1643   ExpectDiagnosticsFor(R"(
1644     #include "unchecked_optional_access_test.h"
1645 
1646     void target() {
1647       $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1648       opt.value();
1649     }
1650   )");
1651 
1652   ExpectDiagnosticsFor(R"(
1653     #include "unchecked_optional_access_test.h"
1654 
1655     struct MyString {
1656       MyString(const char*);
1657     };
1658 
1659     void target() {
1660       $ns::$optional<MyString> opt("foo");
1661       opt.value();
1662     }
1663   )");
1664 
1665   ExpectDiagnosticsFor(R"(
1666     #include "unchecked_optional_access_test.h"
1667 
1668     struct Foo {};
1669 
1670     struct Bar {
1671       Bar(const Foo&);
1672     };
1673 
1674     void target() {
1675       $ns::$optional<Bar> opt(Make<Foo>());
1676       opt.value();
1677     }
1678   )");
1679 
1680   ExpectDiagnosticsFor(R"(
1681     #include "unchecked_optional_access_test.h"
1682 
1683     struct Foo {
1684       explicit Foo(int);
1685     };
1686 
1687     void target() {
1688       $ns::$optional<Foo> opt(3);
1689       opt.value();
1690     }
1691   )");
1692 }
1693 
1694 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
1695   ExpectDiagnosticsFor(
1696       R"(
1697     #include "unchecked_optional_access_test.h"
1698 
1699     struct Foo {};
1700 
1701     struct Bar {
1702       Bar(const Foo&);
1703     };
1704 
1705     void target() {
1706       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1707       opt.value(); // [[unsafe]]
1708     }
1709   )");
1710 
1711   ExpectDiagnosticsFor(
1712       R"(
1713     #include "unchecked_optional_access_test.h"
1714 
1715     struct Foo {};
1716 
1717     struct Bar {
1718       explicit Bar(const Foo&);
1719     };
1720 
1721     void target() {
1722       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1723       opt.value(); // [[unsafe]]
1724     }
1725   )");
1726 
1727   ExpectDiagnosticsFor(
1728       R"(
1729     #include "unchecked_optional_access_test.h"
1730 
1731     struct Foo {};
1732 
1733     struct Bar {
1734       Bar(const Foo&);
1735     };
1736 
1737     void target() {
1738       $ns::$optional<Foo> opt1 = $ns::nullopt;
1739       $ns::$optional<Bar> opt2(opt1);
1740       opt2.value(); // [[unsafe]]
1741     }
1742   )");
1743 
1744   ExpectDiagnosticsFor(R"(
1745     #include "unchecked_optional_access_test.h"
1746 
1747     struct Foo {};
1748 
1749     struct Bar {
1750       Bar(const Foo&);
1751     };
1752 
1753     void target() {
1754       $ns::$optional<Foo> opt1(Make<Foo>());
1755       $ns::$optional<Bar> opt2(opt1);
1756       opt2.value();
1757     }
1758   )");
1759 
1760   ExpectDiagnosticsFor(R"(
1761     #include "unchecked_optional_access_test.h"
1762 
1763     struct Foo {};
1764 
1765     struct Bar {
1766       explicit Bar(const Foo&);
1767     };
1768 
1769     void target() {
1770       $ns::$optional<Foo> opt1(Make<Foo>());
1771       $ns::$optional<Bar> opt2(opt1);
1772       opt2.value();
1773     }
1774   )");
1775 }
1776 
1777 TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
1778   ExpectDiagnosticsFor(R"(
1779     #include "unchecked_optional_access_test.h"
1780 
1781     void target() {
1782       $ns::$optional<int> opt = $ns::make_optional(0);
1783       opt.value();
1784     }
1785   )");
1786 
1787   ExpectDiagnosticsFor(R"(
1788     #include "unchecked_optional_access_test.h"
1789 
1790     struct Foo {
1791       Foo(int, int);
1792     };
1793 
1794     void target() {
1795       $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1796       opt.value();
1797     }
1798   )");
1799 
1800   ExpectDiagnosticsFor(R"(
1801     #include "unchecked_optional_access_test.h"
1802 
1803     struct Foo {
1804       constexpr Foo(std::initializer_list<char>);
1805     };
1806 
1807     void target() {
1808       char a = 'a';
1809       $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1810       opt.value();
1811     }
1812   )");
1813 }
1814 
1815 TEST_P(UncheckedOptionalAccessTest, ValueOr) {
1816   ExpectDiagnosticsFor(R"(
1817     #include "unchecked_optional_access_test.h"
1818 
1819     void target() {
1820       $ns::$optional<int> opt;
1821       opt.value_or(0);
1822       (void)0;
1823     }
1824   )");
1825 }
1826 
1827 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointers) {
1828   ExpectDiagnosticsFor(
1829       R"code(
1830     #include "unchecked_optional_access_test.h"
1831 
1832     void target($ns::$optional<int*> opt) {
1833       if (opt.value_or(nullptr) != nullptr) {
1834         opt.value();
1835       } else {
1836         opt.value(); // [[unsafe]]
1837       }
1838     }
1839   )code");
1840 }
1841 
1842 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonIntegers) {
1843   ExpectDiagnosticsFor(
1844       R"code(
1845     #include "unchecked_optional_access_test.h"
1846 
1847     void target($ns::$optional<int> opt) {
1848       if (opt.value_or(0) != 0) {
1849         opt.value();
1850       } else {
1851         opt.value(); // [[unsafe]]
1852       }
1853     }
1854   )code");
1855 }
1856 
1857 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonStrings) {
1858   ExpectDiagnosticsFor(
1859       R"code(
1860     #include "unchecked_optional_access_test.h"
1861 
1862     void target($ns::$optional<std::string> opt) {
1863       if (!opt.value_or("").empty()) {
1864         opt.value();
1865       } else {
1866         opt.value(); // [[unsafe]]
1867       }
1868     }
1869   )code");
1870 
1871   ExpectDiagnosticsFor(
1872       R"code(
1873     #include "unchecked_optional_access_test.h"
1874 
1875     void target($ns::$optional<std::string> opt) {
1876       if (opt.value_or("") != "") {
1877         opt.value();
1878       } else {
1879         opt.value(); // [[unsafe]]
1880       }
1881     }
1882   )code");
1883 }
1884 
1885 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointerToOptional) {
1886   // FIXME: make `opt` a parameter directly, once we ensure that all `optional`
1887   // values have a `has_value` property.
1888   ExpectDiagnosticsFor(
1889       R"code(
1890     #include "unchecked_optional_access_test.h"
1891 
1892     void target($ns::$optional<int> p) {
1893       $ns::$optional<int> *opt = &p;
1894       if (opt->value_or(0) != 0) {
1895         opt->value();
1896       } else {
1897         opt->value(); // [[unsafe]]
1898       }
1899     }
1900   )code");
1901 }
1902 
1903 TEST_P(UncheckedOptionalAccessTest, Emplace) {
1904   ExpectDiagnosticsFor(R"(
1905     #include "unchecked_optional_access_test.h"
1906 
1907     void target() {
1908       $ns::$optional<int> opt;
1909       opt.emplace(0);
1910       opt.value();
1911     }
1912   )");
1913 
1914   ExpectDiagnosticsFor(R"(
1915     #include "unchecked_optional_access_test.h"
1916 
1917     void target($ns::$optional<int> *opt) {
1918       opt->emplace(0);
1919       opt->value();
1920     }
1921   )");
1922 
1923   // FIXME: Add tests that call `emplace` in conditional branches:
1924   //  ExpectDiagnosticsFor(
1925   //      R"(
1926   //    #include "unchecked_optional_access_test.h"
1927   //
1928   //    void target($ns::$optional<int> opt, bool b) {
1929   //      if (b) {
1930   //        opt.emplace(0);
1931   //      }
1932   //      if (b) {
1933   //        opt.value();
1934   //      } else {
1935   //        opt.value(); // [[unsafe]]
1936   //      }
1937   //    }
1938   //  )");
1939 }
1940 
1941 TEST_P(UncheckedOptionalAccessTest, Reset) {
1942   ExpectDiagnosticsFor(
1943       R"(
1944     #include "unchecked_optional_access_test.h"
1945 
1946     void target() {
1947       $ns::$optional<int> opt = $ns::make_optional(0);
1948       opt.reset();
1949       opt.value(); // [[unsafe]]
1950     }
1951   )");
1952 
1953   ExpectDiagnosticsFor(
1954       R"(
1955     #include "unchecked_optional_access_test.h"
1956 
1957     void target($ns::$optional<int> &opt) {
1958       if (opt.has_value()) {
1959         opt.reset();
1960         opt.value(); // [[unsafe]]
1961       }
1962     }
1963   )");
1964 
1965   // FIXME: Add tests that call `reset` in conditional branches:
1966   //  ExpectDiagnosticsFor(
1967   //      R"(
1968   //    #include "unchecked_optional_access_test.h"
1969   //
1970   //    void target(bool b) {
1971   //      $ns::$optional<int> opt = $ns::make_optional(0);
1972   //      if (b) {
1973   //        opt.reset();
1974   //      }
1975   //      if (b) {
1976   //        opt.value(); // [[unsafe]]
1977   //      } else {
1978   //        opt.value();
1979   //      }
1980   //    }
1981   //  )");
1982 }
1983 
1984 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) {
1985   ExpectDiagnosticsFor(R"(
1986     #include "unchecked_optional_access_test.h"
1987 
1988     struct Foo {};
1989 
1990     void target() {
1991       $ns::$optional<Foo> opt;
1992       opt = Foo();
1993       opt.value();
1994     }
1995   )");
1996 
1997   ExpectDiagnosticsFor(R"(
1998     #include "unchecked_optional_access_test.h"
1999 
2000     struct Foo {};
2001 
2002     void target() {
2003       $ns::$optional<Foo> opt;
2004       (opt = Foo()).value();
2005       (void)0;
2006     }
2007   )");
2008 
2009   ExpectDiagnosticsFor(R"(
2010     #include "unchecked_optional_access_test.h"
2011 
2012     struct MyString {
2013       MyString(const char*);
2014     };
2015 
2016     void target() {
2017       $ns::$optional<MyString> opt;
2018       opt = "foo";
2019       opt.value();
2020     }
2021   )");
2022 
2023   ExpectDiagnosticsFor(R"(
2024     #include "unchecked_optional_access_test.h"
2025 
2026     struct MyString {
2027       MyString(const char*);
2028     };
2029 
2030     void target() {
2031       $ns::$optional<MyString> opt;
2032       (opt = "foo").value();
2033     }
2034   )");
2035 }
2036 
2037 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) {
2038   ExpectDiagnosticsFor(
2039       R"(
2040     #include "unchecked_optional_access_test.h"
2041 
2042     struct Foo {};
2043 
2044     struct Bar {
2045       Bar(const Foo&);
2046     };
2047 
2048     void target() {
2049       $ns::$optional<Foo> opt1 = Foo();
2050       $ns::$optional<Bar> opt2;
2051       opt2 = opt1;
2052       opt2.value();
2053     }
2054   )");
2055 
2056   ExpectDiagnosticsFor(
2057       R"(
2058     #include "unchecked_optional_access_test.h"
2059 
2060     struct Foo {};
2061 
2062     struct Bar {
2063       Bar(const Foo&);
2064     };
2065 
2066     void target() {
2067       $ns::$optional<Foo> opt1;
2068       $ns::$optional<Bar> opt2;
2069       if (opt2.has_value()) {
2070         opt2 = opt1;
2071         opt2.value(); // [[unsafe]]
2072       }
2073     }
2074   )");
2075 
2076   ExpectDiagnosticsFor(
2077       R"(
2078     #include "unchecked_optional_access_test.h"
2079 
2080     struct Foo {};
2081 
2082     struct Bar {
2083       Bar(const Foo&);
2084     };
2085 
2086     void target() {
2087       $ns::$optional<Foo> opt1 = Foo();
2088       $ns::$optional<Bar> opt2;
2089       (opt2 = opt1).value();
2090       (void)0;
2091     }
2092   )");
2093 }
2094 
2095 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) {
2096   ExpectDiagnosticsFor(
2097       R"(
2098     #include "unchecked_optional_access_test.h"
2099 
2100     void target() {
2101       $ns::$optional<int> opt = 3;
2102       opt = $ns::nullopt;
2103       opt.value(); // [[unsafe]]
2104     }
2105   )");
2106 
2107   ExpectDiagnosticsFor(
2108       R"(
2109     #include "unchecked_optional_access_test.h"
2110 
2111     void target() {
2112       $ns::$optional<int> opt = 3;
2113       (opt = $ns::nullopt).value(); // [[unsafe]]
2114     }
2115   )");
2116 }
2117 
2118 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) {
2119   ExpectDiagnosticsFor(
2120       R"(
2121     #include "unchecked_optional_access_test.h"
2122 
2123     void target() {
2124       $ns::$optional<int> opt1 = $ns::nullopt;
2125       $ns::$optional<int> opt2 = 3;
2126 
2127       opt1.swap(opt2);
2128 
2129       opt1.value();
2130 
2131       opt2.value(); // [[unsafe]]
2132     }
2133   )");
2134 
2135   ExpectDiagnosticsFor(
2136       R"(
2137     #include "unchecked_optional_access_test.h"
2138 
2139     void target() {
2140       $ns::$optional<int> opt1 = $ns::nullopt;
2141       $ns::$optional<int> opt2 = 3;
2142 
2143       opt2.swap(opt1);
2144 
2145       opt1.value();
2146 
2147       opt2.value(); // [[unsafe]]
2148     }
2149   )");
2150 }
2151 
2152 TEST_P(UncheckedOptionalAccessTest, OptionalReturnedFromFuntionCall) {
2153   ExpectDiagnosticsFor(
2154       R"(
2155     #include "unchecked_optional_access_test.h"
2156 
2157     struct S {
2158       $ns::$optional<float> x;
2159     } s;
2160     S getOptional() {
2161       return s;
2162     }
2163 
2164     void target() {
2165       getOptional().x = 0;
2166     }
2167   )");
2168 }
2169 
2170 TEST_P(UncheckedOptionalAccessTest, NonConstMethodMayClearOptionalField) {
2171   ExpectDiagnosticsFor(
2172       R"(
2173     #include "unchecked_optional_access_test.h"
2174 
2175     struct Foo {
2176       $ns::$optional<std::string> opt;
2177       void clear();  // assume this may modify the opt field's state
2178     };
2179 
2180     void target(Foo& foo) {
2181       if (foo.opt) {
2182         foo.opt.value();
2183         foo.clear();
2184         foo.opt.value();  // [[unsafe]]
2185       }
2186     }
2187   )");
2188 }
2189 
2190 TEST_P(UncheckedOptionalAccessTest,
2191        NonConstMethodMayNotClearConstOptionalField) {
2192   ExpectDiagnosticsFor(
2193       R"(
2194     #include "unchecked_optional_access_test.h"
2195 
2196     struct Foo {
2197       const $ns::$optional<std::string> opt;
2198       void clear();
2199     };
2200 
2201     void target(Foo& foo) {
2202       if (foo.opt) {
2203         foo.opt.value();
2204         foo.clear();
2205         foo.opt.value();
2206       }
2207     }
2208   )");
2209 }
2210 
2211 TEST_P(UncheckedOptionalAccessTest, StdSwap) {
2212   ExpectDiagnosticsFor(
2213       R"(
2214     #include "unchecked_optional_access_test.h"
2215 
2216     void target() {
2217       $ns::$optional<int> opt1 = $ns::nullopt;
2218       $ns::$optional<int> opt2 = 3;
2219 
2220       std::swap(opt1, opt2);
2221 
2222       opt1.value();
2223 
2224       opt2.value(); // [[unsafe]]
2225     }
2226   )");
2227 
2228   ExpectDiagnosticsFor(
2229       R"(
2230     #include "unchecked_optional_access_test.h"
2231 
2232     void target() {
2233       $ns::$optional<int> opt1 = $ns::nullopt;
2234       $ns::$optional<int> opt2 = 3;
2235 
2236       std::swap(opt2, opt1);
2237 
2238       opt1.value();
2239 
2240       opt2.value(); // [[unsafe]]
2241     }
2242   )");
2243 }
2244 
2245 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocLeft) {
2246   ExpectDiagnosticsFor(
2247       R"(
2248     #include "unchecked_optional_access_test.h"
2249 
2250     struct L { $ns::$optional<int> hd; L* tl; };
2251 
2252     void target() {
2253       $ns::$optional<int> foo = 3;
2254       L bar;
2255 
2256       // Any `tl` beyond the first is not modeled.
2257       bar.tl->tl->hd.swap(foo);
2258 
2259       bar.tl->tl->hd.value(); // [[unsafe]]
2260       foo.value(); // [[unsafe]]
2261     }
2262   )");
2263 }
2264 
2265 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocRight) {
2266   ExpectDiagnosticsFor(
2267       R"(
2268     #include "unchecked_optional_access_test.h"
2269 
2270     struct L { $ns::$optional<int> hd; L* tl; };
2271 
2272     void target() {
2273       $ns::$optional<int> foo = 3;
2274       L bar;
2275 
2276       // Any `tl` beyond the first is not modeled.
2277       foo.swap(bar.tl->tl->hd);
2278 
2279       bar.tl->tl->hd.value(); // [[unsafe]]
2280       foo.value(); // [[unsafe]]
2281     }
2282   )");
2283 }
2284 
2285 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftSet) {
2286   ExpectDiagnosticsFor(
2287       R"(
2288     #include "unchecked_optional_access_test.h"
2289 
2290     struct S { int x; };
2291     struct A { $ns::$optional<S> late; };
2292     struct B { A f3; };
2293     struct C { B f2; };
2294     struct D { C f1; };
2295 
2296     void target() {
2297       $ns::$optional<S> foo = S{3};
2298       D bar;
2299 
2300       bar.f1.f2.f3.late.swap(foo);
2301 
2302       bar.f1.f2.f3.late.value();
2303       foo.value(); // [[unsafe]]
2304     }
2305   )");
2306 }
2307 
2308 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftUnset) {
2309   ExpectDiagnosticsFor(
2310       R"(
2311     #include "unchecked_optional_access_test.h"
2312 
2313     struct S { int x; };
2314     struct A { $ns::$optional<S> late; };
2315     struct B { A f3; };
2316     struct C { B f2; };
2317     struct D { C f1; };
2318 
2319     void target() {
2320       $ns::$optional<S> foo;
2321       D bar;
2322 
2323       bar.f1.f2.f3.late.swap(foo);
2324 
2325       bar.f1.f2.f3.late.value(); // [[unsafe]]
2326       foo.value(); // [[unsafe]]
2327     }
2328   )");
2329 }
2330 
2331 // fixme: use recursion instead of depth.
2332 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightSet) {
2333   ExpectDiagnosticsFor(
2334       R"(
2335     #include "unchecked_optional_access_test.h"
2336 
2337     struct S { int x; };
2338     struct A { $ns::$optional<S> late; };
2339     struct B { A f3; };
2340     struct C { B f2; };
2341     struct D { C f1; };
2342 
2343     void target() {
2344       $ns::$optional<S> foo = S{3};
2345       D bar;
2346 
2347       foo.swap(bar.f1.f2.f3.late);
2348 
2349       bar.f1.f2.f3.late.value();
2350       foo.value(); // [[unsafe]]
2351     }
2352   )");
2353 }
2354 
2355 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightUnset) {
2356   ExpectDiagnosticsFor(
2357       R"(
2358     #include "unchecked_optional_access_test.h"
2359 
2360     struct S { int x; };
2361     struct A { $ns::$optional<S> late; };
2362     struct B { A f3; };
2363     struct C { B f2; };
2364     struct D { C f1; };
2365 
2366     void target() {
2367       $ns::$optional<S> foo;
2368       D bar;
2369 
2370       foo.swap(bar.f1.f2.f3.late);
2371 
2372       bar.f1.f2.f3.late.value(); // [[unsafe]]
2373       foo.value(); // [[unsafe]]
2374     }
2375   )");
2376 }
2377 
2378 TEST_P(UncheckedOptionalAccessTest, UniquePtrToOptional) {
2379   // We suppress diagnostics for optionals in smart pointers (other than
2380   // `optional` itself).
2381   ExpectDiagnosticsFor(
2382       R"(
2383     #include "unchecked_optional_access_test.h"
2384 
2385     template <typename T>
2386     struct smart_ptr {
2387       T& operator*() &;
2388       T* operator->();
2389     };
2390 
2391     void target() {
2392       smart_ptr<$ns::$optional<bool>> foo;
2393       foo->value();
2394       (*foo).value();
2395     }
2396   )");
2397 }
2398 
2399 TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) {
2400   // We suppress diagnostics for optional fields reachable from smart pointers
2401   // (other than `optional` itself) through (exactly) one member access.
2402   ExpectDiagnosticsFor(
2403       R"(
2404     #include "unchecked_optional_access_test.h"
2405 
2406     template <typename T>
2407     struct smart_ptr {
2408       T& operator*() &;
2409       T* operator->();
2410     };
2411 
2412     struct Foo {
2413       $ns::$optional<int> opt;
2414     };
2415 
2416     void target() {
2417       smart_ptr<Foo> foo;
2418       *foo->opt;
2419       *(*foo).opt;
2420     }
2421   )");
2422 }
2423 
2424 TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) {
2425   ExpectDiagnosticsFor(
2426       R"(
2427     #include "unchecked_optional_access_test.h"
2428 
2429     $ns::$optional<int> MakeOpt();
2430 
2431     void target() {
2432       $ns::$optional<int> opt = 0;
2433       opt = MakeOpt();
2434       opt.value(); // [[unsafe]]
2435     }
2436   )");
2437   ExpectDiagnosticsFor(
2438       R"(
2439     #include "unchecked_optional_access_test.h"
2440 
2441     const $ns::$optional<int>& MakeOpt();
2442 
2443     void target() {
2444       $ns::$optional<int> opt = 0;
2445       opt = MakeOpt();
2446       opt.value(); // [[unsafe]]
2447     }
2448   )");
2449 
2450   ExpectDiagnosticsFor(
2451       R"(
2452     #include "unchecked_optional_access_test.h"
2453 
2454     using IntOpt = $ns::$optional<int>;
2455     IntOpt MakeOpt();
2456 
2457     void target() {
2458       IntOpt opt = 0;
2459       opt = MakeOpt();
2460       opt.value(); // [[unsafe]]
2461     }
2462   )");
2463 
2464   ExpectDiagnosticsFor(
2465       R"(
2466     #include "unchecked_optional_access_test.h"
2467 
2468     using IntOpt = $ns::$optional<int>;
2469     const IntOpt& MakeOpt();
2470 
2471     void target() {
2472       IntOpt opt = 0;
2473       opt = MakeOpt();
2474       opt.value(); // [[unsafe]]
2475     }
2476   )");
2477 }
2478 
2479 
2480 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftSet) {
2481   ExpectDiagnosticsFor(
2482       R"(
2483     #include "unchecked_optional_access_test.h"
2484 
2485     void target() {
2486       $ns::$optional<int> opt1 = 3;
2487       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2488 
2489       if (opt1 == opt2) {
2490         opt2.value();
2491       } else {
2492         opt2.value(); // [[unsafe]]
2493       }
2494     }
2495   )");
2496 }
2497 
2498 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightSet) {
2499   ExpectDiagnosticsFor(
2500       R"(
2501     #include "unchecked_optional_access_test.h"
2502 
2503     void target() {
2504       $ns::$optional<int> opt1 = 3;
2505       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2506 
2507       if (opt2 == opt1) {
2508         opt2.value();
2509       } else {
2510         opt2.value(); // [[unsafe]]
2511       }
2512     }
2513   )");
2514 }
2515 
2516 TEST_P(UncheckedOptionalAccessTest, EqualityCheckVerifySetAfterEq) {
2517   ExpectDiagnosticsFor(
2518       R"(
2519     #include "unchecked_optional_access_test.h"
2520 
2521     void target() {
2522       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2523       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2524 
2525       if (opt1 == opt2) {
2526         if (opt1.has_value())
2527           opt2.value();
2528         if (opt2.has_value())
2529           opt1.value();
2530       }
2531     }
2532   )");
2533 }
2534 
2535 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftUnset) {
2536   ExpectDiagnosticsFor(
2537       R"(
2538     #include "unchecked_optional_access_test.h"
2539 
2540     void target() {
2541       $ns::$optional<int> opt1 = $ns::nullopt;
2542       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2543 
2544       if (opt1 == opt2) {
2545         opt2.value(); // [[unsafe]]
2546       } else {
2547         opt2.value();
2548       }
2549     }
2550   )");
2551 }
2552 
2553 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightUnset) {
2554   ExpectDiagnosticsFor(
2555       R"(
2556     #include "unchecked_optional_access_test.h"
2557 
2558     void target() {
2559       $ns::$optional<int> opt1 = $ns::nullopt;
2560       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2561 
2562       if (opt2 == opt1) {
2563         opt2.value(); // [[unsafe]]
2564       } else {
2565         opt2.value();
2566       }
2567     }
2568   )");
2569 }
2570 
2571 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightNullopt) {
2572   ExpectDiagnosticsFor(
2573       R"(
2574     #include "unchecked_optional_access_test.h"
2575 
2576     void target() {
2577       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2578 
2579       if (opt == $ns::nullopt) {
2580         opt.value(); // [[unsafe]]
2581       } else {
2582         opt.value();
2583       }
2584     }
2585   )");
2586 }
2587 
2588 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftNullopt) {
2589   ExpectDiagnosticsFor(
2590       R"(
2591     #include "unchecked_optional_access_test.h"
2592 
2593     void target() {
2594       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2595 
2596       if ($ns::nullopt == opt) {
2597         opt.value(); // [[unsafe]]
2598       } else {
2599         opt.value();
2600       }
2601     }
2602   )");
2603 }
2604 
2605 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightValue) {
2606   ExpectDiagnosticsFor(
2607       R"(
2608     #include "unchecked_optional_access_test.h"
2609 
2610     void target() {
2611       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2612 
2613       if (opt == 3) {
2614         opt.value();
2615       } else {
2616         opt.value(); // [[unsafe]]
2617       }
2618     }
2619   )");
2620 }
2621 
2622 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftValue) {
2623   ExpectDiagnosticsFor(
2624       R"(
2625     #include "unchecked_optional_access_test.h"
2626 
2627     void target() {
2628       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2629 
2630       if (3 == opt) {
2631         opt.value();
2632       } else {
2633         opt.value(); // [[unsafe]]
2634       }
2635     }
2636   )");
2637 }
2638 
2639 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftSet) {
2640   ExpectDiagnosticsFor(
2641       R"(
2642     #include "unchecked_optional_access_test.h"
2643 
2644     void target() {
2645       $ns::$optional<int> opt1 = 3;
2646       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2647 
2648       if (opt1 != opt2) {
2649         opt2.value(); // [[unsafe]]
2650       } else {
2651         opt2.value();
2652       }
2653     }
2654   )");
2655 }
2656 
2657 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightSet) {
2658   ExpectDiagnosticsFor(
2659       R"(
2660     #include "unchecked_optional_access_test.h"
2661 
2662     void target() {
2663       $ns::$optional<int> opt1 = 3;
2664       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2665 
2666       if (opt2 != opt1) {
2667         opt2.value(); // [[unsafe]]
2668       } else {
2669         opt2.value();
2670       }
2671     }
2672   )");
2673 }
2674 
2675 TEST_P(UncheckedOptionalAccessTest, InequalityCheckVerifySetAfterEq) {
2676   ExpectDiagnosticsFor(
2677       R"(
2678     #include "unchecked_optional_access_test.h"
2679 
2680     void target() {
2681       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2682       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2683 
2684       if (opt1 != opt2) {
2685         if (opt1.has_value())
2686           opt2.value(); // [[unsafe]]
2687         if (opt2.has_value())
2688           opt1.value(); // [[unsafe]]
2689       }
2690     }
2691   )");
2692 }
2693 
2694 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftUnset) {
2695   ExpectDiagnosticsFor(
2696       R"(
2697     #include "unchecked_optional_access_test.h"
2698 
2699     void target() {
2700       $ns::$optional<int> opt1 = $ns::nullopt;
2701       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2702 
2703       if (opt1 != opt2) {
2704         opt2.value();
2705       } else {
2706         opt2.value(); // [[unsafe]]
2707       }
2708     }
2709   )");
2710 }
2711 
2712 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightUnset) {
2713   ExpectDiagnosticsFor(
2714       R"(
2715     #include "unchecked_optional_access_test.h"
2716 
2717     void target() {
2718       $ns::$optional<int> opt1 = $ns::nullopt;
2719       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2720 
2721       if (opt2 != opt1) {
2722         opt2.value();
2723       } else {
2724         opt2.value(); // [[unsafe]]
2725       }
2726     }
2727   )");
2728 }
2729 
2730 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightNullopt) {
2731   ExpectDiagnosticsFor(
2732       R"(
2733     #include "unchecked_optional_access_test.h"
2734 
2735     void target() {
2736       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2737 
2738       if (opt != $ns::nullopt) {
2739         opt.value();
2740       } else {
2741         opt.value(); // [[unsafe]]
2742       }
2743     }
2744   )");
2745 }
2746 
2747 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftNullopt) {
2748   ExpectDiagnosticsFor(
2749       R"(
2750     #include "unchecked_optional_access_test.h"
2751 
2752     void target() {
2753       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2754 
2755       if ($ns::nullopt != opt) {
2756         opt.value();
2757       } else {
2758         opt.value(); // [[unsafe]]
2759       }
2760     }
2761   )");
2762 }
2763 
2764 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightValue) {
2765   ExpectDiagnosticsFor(
2766       R"(
2767     #include "unchecked_optional_access_test.h"
2768 
2769     void target() {
2770       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2771 
2772       if (opt != 3) {
2773         opt.value(); // [[unsafe]]
2774       } else {
2775         opt.value();
2776       }
2777     }
2778   )");
2779 }
2780 
2781 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftValue) {
2782   ExpectDiagnosticsFor(
2783       R"(
2784     #include "unchecked_optional_access_test.h"
2785 
2786     void target() {
2787       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2788 
2789       if (3 != opt) {
2790         opt.value(); // [[unsafe]]
2791       } else {
2792         opt.value();
2793       }
2794     }
2795   )");
2796 }
2797 
2798 // Verifies that the model sees through aliases.
2799 TEST_P(UncheckedOptionalAccessTest, WithAlias) {
2800   ExpectDiagnosticsFor(
2801       R"(
2802     #include "unchecked_optional_access_test.h"
2803 
2804     template <typename T>
2805     using MyOptional = $ns::$optional<T>;
2806 
2807     void target(MyOptional<int> opt) {
2808       opt.value(); // [[unsafe]]
2809     }
2810   )");
2811 }
2812 
2813 TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) {
2814   // Basic test that nested values are populated.  We nest an optional because
2815   // its easy to use in a test, but the type of the nested value shouldn't
2816   // matter.
2817   ExpectDiagnosticsFor(
2818       R"(
2819     #include "unchecked_optional_access_test.h"
2820 
2821     using Foo = $ns::$optional<std::string>;
2822 
2823     void target($ns::$optional<Foo> foo) {
2824       if (foo && *foo) {
2825         foo->value();
2826       }
2827     }
2828   )");
2829 
2830   // Mutation is supported for nested values.
2831   ExpectDiagnosticsFor(
2832       R"(
2833     #include "unchecked_optional_access_test.h"
2834 
2835     using Foo = $ns::$optional<std::string>;
2836 
2837     void target($ns::$optional<Foo> foo) {
2838       if (foo && *foo) {
2839         foo->reset();
2840         foo->value(); // [[unsafe]]
2841       }
2842     }
2843   )");
2844 }
2845 
2846 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignValue) {
2847   ExpectDiagnosticsFor(
2848       R"(
2849     #include "unchecked_optional_access_test.h"
2850 
2851     using OptionalInt = $ns::$optional<int>;
2852 
2853     void target($ns::$optional<OptionalInt> opt) {
2854       if (!opt) return;
2855 
2856       // Accessing the outer optional is OK now.
2857       *opt;
2858 
2859       // But accessing the nested optional is still unsafe because we haven't
2860       // checked it.
2861       **opt;  // [[unsafe]]
2862 
2863       *opt = 1;
2864 
2865       // Accessing the nested optional is safe after assigning a value to it.
2866       **opt;
2867     }
2868   )");
2869 }
2870 
2871 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignOptional) {
2872   ExpectDiagnosticsFor(
2873       R"(
2874     #include "unchecked_optional_access_test.h"
2875 
2876     using OptionalInt = $ns::$optional<int>;
2877 
2878     void target($ns::$optional<OptionalInt> opt) {
2879       if (!opt) return;
2880 
2881       // Accessing the outer optional is OK now.
2882       *opt;
2883 
2884       // But accessing the nested optional is still unsafe because we haven't
2885       // checked it.
2886       **opt;  // [[unsafe]]
2887 
2888       // Assign from `optional<short>` so that we trigger conversion assignment
2889       // instead of move assignment.
2890       *opt = $ns::$optional<short>();
2891 
2892       // Accessing the nested optional is still unsafe after assigning an empty
2893       // optional to it.
2894       **opt;  // [[unsafe]]
2895     }
2896   )");
2897 }
2898 
2899 // Tests that structs can be nested. We use an optional field because its easy
2900 // to use in a test, but the type of the field shouldn't matter.
2901 TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) {
2902   ExpectDiagnosticsFor(
2903       R"(
2904     #include "unchecked_optional_access_test.h"
2905 
2906     struct Foo {
2907       $ns::$optional<std::string> opt;
2908     };
2909 
2910     void target($ns::$optional<Foo> foo) {
2911       if (foo && foo->opt) {
2912         foo->opt.value();
2913       }
2914     }
2915   )");
2916 }
2917 
2918 // FIXME: A case that we should handle but currently don't.
2919 // When there is a field of type reference to non-optional, we may
2920 // stop recursively creating storage locations.
2921 // E.g., the field `second` below in `pair` should eventually lead to
2922 // the optional `x` in `A`.
2923 TEST_P(UncheckedOptionalAccessTest, NestedOptionalThroughNonOptionalRefField) {
2924   ExpectDiagnosticsFor(R"(
2925     #include "unchecked_optional_access_test.h"
2926 
2927     struct A {
2928       $ns::$optional<int> x;
2929     };
2930 
2931     struct pair {
2932       int first;
2933       const A &second;
2934     };
2935 
2936     struct B {
2937       $ns::$optional<pair>& nonConstGetRef();
2938     };
2939 
2940     void target(B b) {
2941       const auto& maybe_pair = b.nonConstGetRef();
2942       if (!maybe_pair.has_value())
2943         return;
2944 
2945       if(!maybe_pair->second.x.has_value())
2946         return;
2947       maybe_pair->second.x.value();  // [[unsafe]]
2948     }
2949   )");
2950 }
2951 
2952 TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) {
2953   ExpectDiagnosticsFor(
2954       R"(
2955     #include "unchecked_optional_access_test.h"
2956 
2957     using Foo = $ns::$optional<std::string>;
2958 
2959     void target($ns::$optional<Foo> foo, bool b) {
2960       if (!foo.has_value()) return;
2961       if (b) {
2962         if (!foo->has_value()) return;
2963         // We have created `foo.value()`.
2964         foo->value();
2965       } else {
2966         if (!foo->has_value()) return;
2967         // We have created `foo.value()` again, in a different environment.
2968         foo->value();
2969       }
2970       // Now we merge the two values. UncheckedOptionalAccessModel::merge() will
2971       // throw away the "value" property.
2972       foo->value();
2973     }
2974   )");
2975 }
2976 
2977 // This test is aimed at the core model, not the diagnostic. It is a regression
2978 // test against a crash when using non-trivial smart pointers, like
2979 // `std::unique_ptr`. As such, it doesn't test the access itself, which would be
2980 // ignored regardless because of `IgnoreSmartPointerDereference = true`, above.
2981 TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) {
2982   ExpectDiagnosticsFor(
2983       R"(
2984     #include "unchecked_optional_access_test.h"
2985 
2986     template <typename T>
2987     struct smart_ptr {
2988       typename std::add_lvalue_reference<T>::type operator*() &;
2989     };
2990 
2991     void target() {
2992       smart_ptr<$ns::$optional<int>> x;
2993       // Verify that this assignment does not crash.
2994       *x = 3;
2995     }
2996   )");
2997 }
2998 
2999 TEST_P(UncheckedOptionalAccessTest, CorrelatedBranches) {
3000   ExpectDiagnosticsFor(R"code(
3001     #include "unchecked_optional_access_test.h"
3002 
3003     void target(bool b, $ns::$optional<int> opt) {
3004       if (b || opt.has_value()) {
3005         if (!b) {
3006           opt.value();
3007         }
3008       }
3009     }
3010   )code");
3011 
3012   ExpectDiagnosticsFor(R"code(
3013     #include "unchecked_optional_access_test.h"
3014 
3015     void target(bool b, $ns::$optional<int> opt) {
3016       if (b && !opt.has_value()) return;
3017       if (b) {
3018         opt.value();
3019       }
3020     }
3021   )code");
3022 
3023   ExpectDiagnosticsFor(
3024       R"code(
3025     #include "unchecked_optional_access_test.h"
3026 
3027     void target(bool b, $ns::$optional<int> opt) {
3028       if (opt.has_value()) b = true;
3029       if (b) {
3030         opt.value(); // [[unsafe]]
3031       }
3032     }
3033   )code");
3034 
3035   ExpectDiagnosticsFor(R"code(
3036     #include "unchecked_optional_access_test.h"
3037 
3038     void target(bool b, $ns::$optional<int> opt) {
3039       if (b) return;
3040       if (opt.has_value()) b = true;
3041       if (b) {
3042         opt.value();
3043       }
3044     }
3045   )code");
3046 
3047   ExpectDiagnosticsFor(R"(
3048     #include "unchecked_optional_access_test.h"
3049 
3050     void target(bool b, $ns::$optional<int> opt) {
3051       if (opt.has_value() == b) {
3052         if (b) {
3053           opt.value();
3054         }
3055       }
3056     }
3057   )");
3058 
3059   ExpectDiagnosticsFor(R"(
3060     #include "unchecked_optional_access_test.h"
3061 
3062     void target(bool b, $ns::$optional<int> opt) {
3063       if (opt.has_value() != b) {
3064         if (!b) {
3065           opt.value();
3066         }
3067       }
3068     }
3069   )");
3070 
3071   ExpectDiagnosticsFor(R"(
3072     #include "unchecked_optional_access_test.h"
3073 
3074     void target(bool b) {
3075       $ns::$optional<int> opt1 = $ns::nullopt;
3076       $ns::$optional<int> opt2;
3077       if (b) {
3078         opt2 = $ns::nullopt;
3079       } else {
3080         opt2 = $ns::nullopt;
3081       }
3082       if (opt2.has_value()) {
3083         opt1.value();
3084       }
3085     }
3086   )");
3087 }
3088 
3089 TEST_P(UncheckedOptionalAccessTest, JoinDistinctValues) {
3090   ExpectDiagnosticsFor(
3091       R"code(
3092     #include "unchecked_optional_access_test.h"
3093 
3094     void target(bool b) {
3095       $ns::$optional<int> opt;
3096       if (b) {
3097         opt = Make<$ns::$optional<int>>();
3098       } else {
3099         opt = Make<$ns::$optional<int>>();
3100       }
3101       if (opt.has_value()) {
3102         opt.value();
3103       } else {
3104         opt.value(); // [[unsafe]]
3105       }
3106     }
3107   )code");
3108 
3109   ExpectDiagnosticsFor(R"code(
3110     #include "unchecked_optional_access_test.h"
3111 
3112     void target(bool b) {
3113       $ns::$optional<int> opt;
3114       if (b) {
3115         opt = Make<$ns::$optional<int>>();
3116         if (!opt.has_value()) return;
3117       } else {
3118         opt = Make<$ns::$optional<int>>();
3119         if (!opt.has_value()) return;
3120       }
3121       opt.value();
3122     }
3123   )code");
3124 
3125   ExpectDiagnosticsFor(
3126       R"code(
3127     #include "unchecked_optional_access_test.h"
3128 
3129     void target(bool b) {
3130       $ns::$optional<int> opt;
3131       if (b) {
3132         opt = Make<$ns::$optional<int>>();
3133         if (!opt.has_value()) return;
3134       } else {
3135         opt = Make<$ns::$optional<int>>();
3136       }
3137       opt.value(); // [[unsafe]]
3138     }
3139   )code");
3140 
3141   ExpectDiagnosticsFor(
3142       R"code(
3143     #include "unchecked_optional_access_test.h"
3144 
3145     void target(bool b) {
3146       $ns::$optional<int> opt;
3147       if (b) {
3148         opt = 1;
3149       } else {
3150         opt = 2;
3151       }
3152       opt.value();
3153     }
3154   )code");
3155 
3156   ExpectDiagnosticsFor(
3157       R"code(
3158     #include "unchecked_optional_access_test.h"
3159 
3160     void target(bool b) {
3161       $ns::$optional<int> opt;
3162       if (b) {
3163         opt = 1;
3164       } else {
3165         opt = Make<$ns::$optional<int>>();
3166       }
3167       opt.value(); // [[unsafe]]
3168     }
3169   )code");
3170 }
3171 
3172 TEST_P(UncheckedOptionalAccessTest, AccessValueInLoop) {
3173   ExpectDiagnosticsFor(R"(
3174     #include "unchecked_optional_access_test.h"
3175 
3176     void target() {
3177       $ns::$optional<int> opt = 3;
3178       while (Make<bool>()) {
3179         opt.value();
3180       }
3181     }
3182   )");
3183 }
3184 
3185 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopWithCheckSafe) {
3186   ExpectDiagnosticsFor(R"(
3187     #include "unchecked_optional_access_test.h"
3188 
3189     void target() {
3190       $ns::$optional<int> opt = 3;
3191       while (Make<bool>()) {
3192         opt.value();
3193 
3194         opt = Make<$ns::$optional<int>>();
3195         if (!opt.has_value()) return;
3196       }
3197     }
3198   )");
3199 }
3200 
3201 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopNoCheckUnsafe) {
3202   ExpectDiagnosticsFor(
3203       R"(
3204     #include "unchecked_optional_access_test.h"
3205 
3206     void target() {
3207       $ns::$optional<int> opt = 3;
3208       while (Make<bool>()) {
3209         opt.value(); // [[unsafe]]
3210 
3211         opt = Make<$ns::$optional<int>>();
3212       }
3213     }
3214   )");
3215 }
3216 
3217 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnsetUnsafe) {
3218   ExpectDiagnosticsFor(
3219       R"(
3220     #include "unchecked_optional_access_test.h"
3221 
3222     void target() {
3223       $ns::$optional<int> opt = 3;
3224       while (Make<bool>())
3225         opt = $ns::nullopt;
3226       $ns::$optional<int> opt2 = $ns::nullopt;
3227       if (opt.has_value())
3228         opt2 = $ns::$optional<int>(3);
3229       opt2.value(); // [[unsafe]]
3230     }
3231   )");
3232 }
3233 
3234 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToSetUnsafe) {
3235   ExpectDiagnosticsFor(
3236       R"(
3237     #include "unchecked_optional_access_test.h"
3238 
3239     void target() {
3240       $ns::$optional<int> opt = $ns::nullopt;
3241       while (Make<bool>())
3242         opt = $ns::$optional<int>(3);
3243       $ns::$optional<int> opt2 = $ns::nullopt;
3244       if (!opt.has_value())
3245         opt2 = $ns::$optional<int>(3);
3246       opt2.value(); // [[unsafe]]
3247     }
3248   )");
3249 }
3250 
3251 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnknownUnsafe) {
3252   ExpectDiagnosticsFor(
3253       R"(
3254     #include "unchecked_optional_access_test.h"
3255 
3256     void target() {
3257       $ns::$optional<int> opt = $ns::nullopt;
3258       while (Make<bool>())
3259         opt = Make<$ns::$optional<int>>();
3260       $ns::$optional<int> opt2 = $ns::nullopt;
3261       if (!opt.has_value())
3262         opt2 = $ns::$optional<int>(3);
3263       opt2.value(); // [[unsafe]]
3264     }
3265   )");
3266 }
3267 
3268 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopBadConditionUnsafe) {
3269   ExpectDiagnosticsFor(
3270       R"(
3271     #include "unchecked_optional_access_test.h"
3272 
3273     void target() {
3274       $ns::$optional<int> opt = 3;
3275       while (Make<bool>()) {
3276         opt.value(); // [[unsafe]]
3277 
3278         opt = Make<$ns::$optional<int>>();
3279         if (!opt.has_value()) continue;
3280       }
3281     }
3282   )");
3283 }
3284 
3285 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromStruct) {
3286   ExpectDiagnosticsFor(R"(
3287     #include "unchecked_optional_access_test.h"
3288 
3289     struct kv { $ns::$optional<int> opt; int x; };
3290     int target() {
3291       auto [contents, x] = Make<kv>();
3292       return contents ? *contents : x;
3293     }
3294   )");
3295 
3296   ExpectDiagnosticsFor(R"(
3297     #include "unchecked_optional_access_test.h"
3298 
3299     template <typename T1, typename T2>
3300     struct pair { T1 fst;  T2 snd; };
3301     int target() {
3302       auto [contents, x] = Make<pair<$ns::$optional<int>, int>>();
3303       return contents ? *contents : x;
3304     }
3305   )");
3306 }
3307 
3308 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromTupleLikeType) {
3309   ExpectDiagnosticsFor(R"(
3310     #include "unchecked_optional_access_test.h"
3311 
3312     namespace std {
3313     template <class> struct tuple_size;
3314     template <size_t, class> struct tuple_element;
3315     template <class...> class tuple;
3316 
3317     template <class... T>
3318     struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {};
3319 
3320     template <size_t I, class... T>
3321     struct tuple_element<I, tuple<T...>> {
3322       using type =  __type_pack_element<I, T...>;
3323     };
3324 
3325     template <class...> class tuple {};
3326     template <size_t I, class... T>
3327     typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
3328     } // namespace std
3329 
3330     std::tuple<$ns::$optional<const char *>, int> get_opt();
3331     void target() {
3332       auto [content, ck] = get_opt();
3333       content ? *content : "";
3334     }
3335   )");
3336 }
3337 
3338 TEST_P(UncheckedOptionalAccessTest, CtorInitializerNullopt) {
3339   using namespace ast_matchers;
3340   ExpectDiagnosticsFor(
3341       R"(
3342     #include "unchecked_optional_access_test.h"
3343 
3344     struct Target {
3345       Target(): opt($ns::nullopt) {
3346         opt.value(); // [[unsafe]]
3347       }
3348       $ns::$optional<int> opt;
3349     };
3350   )",
3351       cxxConstructorDecl(ofClass(hasName("Target"))));
3352 }
3353 
3354 TEST_P(UncheckedOptionalAccessTest, CtorInitializerValue) {
3355   using namespace ast_matchers;
3356   ExpectDiagnosticsFor(
3357       R"(
3358     #include "unchecked_optional_access_test.h"
3359 
3360     struct Target {
3361       Target(): opt(3) {
3362         opt.value();
3363       }
3364       $ns::$optional<int> opt;
3365     };
3366   )",
3367       cxxConstructorDecl(ofClass(hasName("Target"))));
3368 }
3369 
3370 // This is regression test, it shouldn't crash.
3371 TEST_P(UncheckedOptionalAccessTest, Bitfield) {
3372   using namespace ast_matchers;
3373   ExpectDiagnosticsFor(
3374       R"(
3375     #include "unchecked_optional_access_test.h"
3376     struct Dst {
3377       unsigned int n : 1;
3378     };
3379     void target() {
3380       $ns::$optional<bool> v;
3381       Dst d;
3382       if (v.has_value())
3383         d.n = v.value();
3384     }
3385   )");
3386 }
3387 
3388 TEST_P(UncheckedOptionalAccessTest, LambdaParam) {
3389   ExpectDiagnosticsForLambda(R"(
3390     #include "unchecked_optional_access_test.h"
3391 
3392     void target() {
3393       []($ns::$optional<int> opt) {
3394         if (opt.has_value()) {
3395           opt.value();
3396         } else {
3397           opt.value(); // [[unsafe]]
3398         }
3399       }(Make<$ns::$optional<int>>());
3400     }
3401   )");
3402 }
3403 
3404 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopy) {
3405   ExpectDiagnosticsForLambda(R"(
3406     #include "unchecked_optional_access_test.h"
3407 
3408     void target($ns::$optional<int> opt) {
3409       [opt]() {
3410         if (opt.has_value()) {
3411           opt.value();
3412         } else {
3413           opt.value(); // [[unsafe]]
3414         }
3415       }();
3416     }
3417   )");
3418 }
3419 
3420 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReference) {
3421   ExpectDiagnosticsForLambda(R"(
3422     #include "unchecked_optional_access_test.h"
3423 
3424     void target($ns::$optional<int> opt) {
3425       [&opt]() {
3426         if (opt.has_value()) {
3427           opt.value();
3428         } else {
3429           opt.value(); // [[unsafe]]
3430         }
3431       }();
3432     }
3433   )");
3434 }
3435 
3436 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureWithInitializer) {
3437   ExpectDiagnosticsForLambda(R"(
3438     #include "unchecked_optional_access_test.h"
3439 
3440     void target($ns::$optional<int> opt) {
3441       [opt2=opt]() {
3442         if (opt2.has_value()) {
3443           opt2.value();
3444         } else {
3445           opt2.value(); // [[unsafe]]
3446         }
3447       }();
3448     }
3449   )");
3450 }
3451 
3452 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopyImplicit) {
3453   ExpectDiagnosticsForLambda(R"(
3454     #include "unchecked_optional_access_test.h"
3455 
3456     void target($ns::$optional<int> opt) {
3457       [=]() {
3458         if (opt.has_value()) {
3459           opt.value();
3460         } else {
3461           opt.value(); // [[unsafe]]
3462         }
3463       }();
3464     }
3465   )");
3466 }
3467 
3468 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReferenceImplicit) {
3469   ExpectDiagnosticsForLambda(R"(
3470     #include "unchecked_optional_access_test.h"
3471 
3472     void target($ns::$optional<int> opt) {
3473       [&]() {
3474         if (opt.has_value()) {
3475           opt.value();
3476         } else {
3477           opt.value(); // [[unsafe]]
3478         }
3479       }();
3480     }
3481   )");
3482 }
3483 
3484 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureThis) {
3485   ExpectDiagnosticsForLambda(R"(
3486     #include "unchecked_optional_access_test.h"
3487 
3488     struct Foo {
3489       $ns::$optional<int> opt;
3490 
3491       void target() {
3492         [this]() {
3493           if (opt.has_value()) {
3494             opt.value();
3495           } else {
3496             opt.value(); // [[unsafe]]
3497           }
3498         }();
3499       }
3500     };
3501   )");
3502 }
3503 
3504 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureStateNotPropagated) {
3505   // We can't propagate information from the surrounding context.
3506   ExpectDiagnosticsForLambda(R"(
3507     #include "unchecked_optional_access_test.h"
3508 
3509     void target($ns::$optional<int> opt) {
3510       if (opt.has_value()) {
3511         [&opt]() {
3512           opt.value(); // [[unsafe]]
3513         }();
3514       }
3515     }
3516   )");
3517 }
3518 
3519 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptional) {
3520   ExpectDiagnosticsFor(R"(
3521     #include "unchecked_optional_access_test.h"
3522 
3523     struct Derived : public $ns::$optional<int> {};
3524 
3525     void target(Derived opt) {
3526       *opt;  // [[unsafe]]
3527       if (opt.has_value())
3528         *opt;
3529 
3530       // The same thing, but with a pointer receiver.
3531       Derived *popt = &opt;
3532       **popt;  // [[unsafe]]
3533       if (popt->has_value())
3534         **popt;
3535     }
3536   )");
3537 }
3538 
3539 TEST_P(UncheckedOptionalAccessTest, ClassTemplateDerivedFromOptional) {
3540   ExpectDiagnosticsFor(R"(
3541     #include "unchecked_optional_access_test.h"
3542 
3543     template <class T>
3544     struct Derived : public $ns::$optional<T> {};
3545 
3546     void target(Derived<int> opt) {
3547       *opt;  // [[unsafe]]
3548       if (opt.has_value())
3549         *opt;
3550 
3551       // The same thing, but with a pointer receiver.
3552       Derived<int> *popt = &opt;
3553       **popt;  // [[unsafe]]
3554       if (popt->has_value())
3555         **popt;
3556     }
3557   )");
3558 }
3559 
3560 TEST_P(UncheckedOptionalAccessTest, ClassDerivedPrivatelyFromOptional) {
3561   // Classes that derive privately from optional can themselves still call
3562   // member functions of optional. Check that we model the optional correctly
3563   // in this situation.
3564   ExpectDiagnosticsFor(R"(
3565     #include "unchecked_optional_access_test.h"
3566 
3567     struct Derived : private $ns::$optional<int> {
3568       void Method() {
3569         **this;  // [[unsafe]]
3570         if (this->has_value())
3571           **this;
3572       }
3573     };
3574   )",
3575                        ast_matchers::hasName("Method"));
3576 }
3577 
3578 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptionalValueConstructor) {
3579   ExpectDiagnosticsFor(R"(
3580     #include "unchecked_optional_access_test.h"
3581 
3582     struct Derived : public $ns::$optional<int> {
3583       Derived(int);
3584     };
3585 
3586     void target(Derived opt) {
3587       *opt;  // [[unsafe]]
3588       opt = 1;
3589       *opt;
3590     }
3591   )");
3592 }
3593 
3594 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessor) {
3595   ExpectDiagnosticsFor(R"cc(
3596     #include "unchecked_optional_access_test.h"
3597 
3598     struct A {
3599       const $ns::$optional<int>& get() const { return x; }
3600       $ns::$optional<int> x;
3601     };
3602 
3603     void target(A& a) {
3604       if (a.get().has_value()) {
3605         a.get().value();
3606       }
3607     }
3608   )cc");
3609 }
3610 
3611 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModInBetween) {
3612   ExpectDiagnosticsFor(R"cc(
3613     #include "unchecked_optional_access_test.h"
3614 
3615     struct A {
3616       const $ns::$optional<int>& get() const { return x; }
3617       void clear();
3618       $ns::$optional<int> x;
3619     };
3620 
3621     void target(A& a) {
3622       if (a.get().has_value()) {
3623         a.clear();
3624         a.get().value();  // [[unsafe]]
3625       }
3626     }
3627   )cc");
3628 }
3629 
3630 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModReturningOptional) {
3631   ExpectDiagnosticsFor(R"cc(
3632     #include "unchecked_optional_access_test.h"
3633 
3634     struct A {
3635       const $ns::$optional<int>& get() const { return x; }
3636       $ns::$optional<int> take();
3637       $ns::$optional<int> x;
3638     };
3639 
3640     void target(A& a) {
3641       if (a.get().has_value()) {
3642         $ns::$optional<int> other = a.take();
3643         a.get().value();  // [[unsafe]]
3644         if (other.has_value()) {
3645           other.value();
3646         }
3647       }
3648     }
3649   )cc");
3650 }
3651 
3652 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorDifferentObjects) {
3653   ExpectDiagnosticsFor(R"cc(
3654     #include "unchecked_optional_access_test.h"
3655 
3656     struct A {
3657       const $ns::$optional<int>& get() const { return x; }
3658       $ns::$optional<int> x;
3659     };
3660 
3661     void target(A& a1, A& a2) {
3662       if (a1.get().has_value()) {
3663         a2.get().value();  // [[unsafe]]
3664       }
3665     }
3666   )cc");
3667 }
3668 
3669 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorLoop) {
3670   ExpectDiagnosticsFor(R"cc(
3671     #include "unchecked_optional_access_test.h"
3672 
3673     struct A {
3674       const $ns::$optional<int>& get() const { return x; }
3675       $ns::$optional<int> x;
3676     };
3677 
3678     void target(A& a, int N) {
3679       for (int i = 0; i < N; ++i) {
3680         if (a.get().has_value()) {
3681           a.get().value();
3682         }
3683       }
3684     }
3685   )cc");
3686 }
3687 
3688 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessor) {
3689   ExpectDiagnosticsFor(R"cc(
3690     #include "unchecked_optional_access_test.h"
3691 
3692     struct A {
3693       $ns::$optional<int> get() const { return x; }
3694       $ns::$optional<int> x;
3695     };
3696 
3697     void target(A& a) {
3698       if (a.get().has_value()) {
3699         a.get().value();
3700       }
3701     }
3702   )cc");
3703 }
3704 
3705 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessorWithModInBetween) {
3706   ExpectDiagnosticsFor(R"cc(
3707     #include "unchecked_optional_access_test.h"
3708 
3709     struct A {
3710       $ns::$optional<int> get() const { return x; }
3711       void clear();
3712       $ns::$optional<int> x;
3713     };
3714 
3715     void target(A& a) {
3716       if (a.get().has_value()) {
3717         a.clear();
3718         a.get().value();  // [[unsafe]]
3719       }
3720     }
3721   )cc");
3722 }
3723 
3724 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessor) {
3725   ExpectDiagnosticsFor(R"cc(
3726     #include "unchecked_optional_access_test.h"
3727 
3728     struct A {
3729       bool isFoo() const { return f; }
3730       bool f;
3731     };
3732 
3733     void target(A& a) {
3734       std::optional<int> opt;
3735       if (a.isFoo()) {
3736         opt = 1;
3737       }
3738       if (a.isFoo()) {
3739         opt.value();
3740       }
3741     }
3742   )cc");
3743 }
3744 
3745 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessorWithModInBetween) {
3746   ExpectDiagnosticsFor(R"cc(
3747     #include "unchecked_optional_access_test.h"
3748 
3749     struct A {
3750       bool isFoo() const { return f; }
3751       void clear();
3752       bool f;
3753     };
3754 
3755     void target(A& a) {
3756       std::optional<int> opt;
3757       if (a.isFoo()) {
3758         opt = 1;
3759       }
3760       a.clear();
3761       if (a.isFoo()) {
3762         opt.value();  // [[unsafe]]
3763       }
3764     }
3765   )cc");
3766 }
3767 
3768 // FIXME: Add support for:
3769 // - constructors (copy, move)
3770 // - assignment operators (default, copy, move)
3771 // - invalidation (passing optional by non-const reference/pointer)
3772