xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (revision 8b5d3ba829c162fd4890fd65a4629ce0715825ee)
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   initializer_list() noexcept;
556 };
557 
558 } // namespace std
559 
560 #endif // INITIALIZER_LIST_H
561 )";
562 
563 static constexpr char StdOptionalHeader[] = R"(
564 #include "std_initializer_list.h"
565 #include "std_type_traits.h"
566 #include "std_utility.h"
567 
568 namespace std {
569 
570 struct in_place_t {};
571 constexpr in_place_t in_place;
572 
573 struct nullopt_t {
574   constexpr explicit nullopt_t() {}
575 };
576 constexpr nullopt_t nullopt;
577 
578 template <class _Tp>
579 struct __optional_destruct_base {
580   constexpr void reset() noexcept;
581 };
582 
583 template <class _Tp>
584 struct __optional_storage_base : __optional_destruct_base<_Tp> {
585   constexpr bool has_value() const noexcept;
586 };
587 
588 template <typename _Tp>
589 class optional : private __optional_storage_base<_Tp> {
590   using __base = __optional_storage_base<_Tp>;
591 
592  public:
593   using value_type = _Tp;
594 
595  private:
596   struct _CheckOptionalArgsConstructor {
597     template <class _Up>
598     static constexpr bool __enable_implicit() {
599       return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
600     }
601 
602     template <class _Up>
603     static constexpr bool __enable_explicit() {
604       return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
605     }
606   };
607   template <class _Up>
608   using _CheckOptionalArgsCtor =
609       _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value &&
610               _IsNotSame<__uncvref_t<_Up>, optional>::value,
611           _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>;
612   template <class _QualUp>
613   struct _CheckOptionalLikeConstructor {
614     template <class _Up, class _Opt = optional<_Up>>
615     using __check_constructible_from_opt =
616         _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>,
617             is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>,
618             is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>,
619             is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>;
620     template <class _Up, class _QUp = _QualUp>
621     static constexpr bool __enable_implicit() {
622       return is_convertible<_QUp, _Tp>::value &&
623              !__check_constructible_from_opt<_Up>::value;
624     }
625     template <class _Up, class _QUp = _QualUp>
626     static constexpr bool __enable_explicit() {
627       return !is_convertible<_QUp, _Tp>::value &&
628              !__check_constructible_from_opt<_Up>::value;
629     }
630   };
631 
632   template <class _Up, class _QualUp>
633   using _CheckOptionalLikeCtor =
634       _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value,
635           _CheckOptionalLikeConstructor<_QualUp>,
636           __check_tuple_constructor_fail>;
637 
638 
639   template <class _Up, class _QualUp>
640   using _CheckOptionalLikeAssign = _If<
641       _And<
642           _IsNotSame<_Up, _Tp>,
643           is_constructible<_Tp, _QualUp>,
644           is_assignable<_Tp&, _QualUp>
645       >::value,
646       _CheckOptionalLikeConstructor<_QualUp>,
647       __check_tuple_constructor_fail
648     >;
649 
650  public:
651   constexpr optional() noexcept {}
652   constexpr optional(const optional&) = default;
653   constexpr optional(optional&&) = default;
654   constexpr optional(nullopt_t) noexcept {}
655 
656   template <
657       class _InPlaceT, class... _Args,
658       class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>,
659                              is_constructible<value_type, _Args...>>::value>>
660   constexpr explicit optional(_InPlaceT, _Args&&... __args);
661 
662   template <class _Up, class... _Args,
663             class = enable_if_t<is_constructible_v<
664                 value_type, initializer_list<_Up>&, _Args...>>>
665   constexpr explicit optional(in_place_t, initializer_list<_Up> __il,
666                               _Args&&... __args);
667 
668   template <
669       class _Up = value_type,
670       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(),
671                 int> = 0>
672   constexpr optional(_Up&& __v);
673 
674   template <
675       class _Up,
676       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(),
677                 int> = 0>
678   constexpr explicit optional(_Up&& __v);
679 
680   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
681                                      template __enable_implicit<_Up>(),
682                                  int> = 0>
683   constexpr optional(const optional<_Up>& __v);
684 
685   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
686                                      template __enable_explicit<_Up>(),
687                                  int> = 0>
688   constexpr explicit optional(const optional<_Up>& __v);
689 
690   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
691                                      template __enable_implicit<_Up>(),
692                                  int> = 0>
693   constexpr optional(optional<_Up>&& __v);
694 
695   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
696                                      template __enable_explicit<_Up>(),
697                                  int> = 0>
698   constexpr explicit optional(optional<_Up>&& __v);
699 
700   constexpr optional& operator=(nullopt_t) noexcept;
701 
702   optional& operator=(const optional&);
703 
704   optional& operator=(optional&&);
705 
706   template <class _Up = value_type,
707             class = enable_if_t<_And<_IsNotSame<__uncvref_t<_Up>, optional>,
708                                    _Or<_IsNotSame<__uncvref_t<_Up>, value_type>,
709                                        _Not<is_scalar<value_type>>>,
710                                    is_constructible<value_type, _Up>,
711                                    is_assignable<value_type&, _Up>>::value>>
712   constexpr optional& operator=(_Up&& __v);
713 
714   template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>::
715                                      template __enable_assign<_Up>(),
716                                  int> = 0>
717   constexpr optional& operator=(const optional<_Up>& __v);
718 
719   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
720                                      template __enable_assign<_Up>(),
721                                  int> = 0>
722   constexpr optional& operator=(optional<_Up>&& __v);
723 
724   const _Tp& operator*() const&;
725   _Tp& operator*() &;
726   const _Tp&& operator*() const&&;
727   _Tp&& operator*() &&;
728 
729   const _Tp* operator->() const;
730   _Tp* operator->();
731 
732   const _Tp& value() const&;
733   _Tp& value() &;
734   const _Tp&& value() const&&;
735   _Tp&& value() &&;
736 
737   template <typename U>
738   constexpr _Tp value_or(U&& v) const&;
739   template <typename U>
740   _Tp value_or(U&& v) &&;
741 
742   template <typename... Args>
743   _Tp& emplace(Args&&... args);
744 
745   template <typename U, typename... Args>
746   _Tp& emplace(std::initializer_list<U> ilist, Args&&... args);
747 
748   using __base::reset;
749 
750   constexpr explicit operator bool() const noexcept;
751   using __base::has_value;
752 
753   constexpr void swap(optional& __opt) noexcept;
754 };
755 
756 template <typename T>
757 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
758 
759 template <typename T, typename... Args>
760 constexpr optional<T> make_optional(Args&&... args);
761 
762 template <typename T, typename U, typename... Args>
763 constexpr optional<T> make_optional(std::initializer_list<U> il,
764                                     Args&&... args);
765 
766 template <typename T, typename U>
767 constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs);
768 template <typename T, typename U>
769 constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs);
770 
771 template <typename T>
772 constexpr bool operator==(const optional<T> &opt, nullopt_t);
773 template <typename T>
774 constexpr bool operator==(nullopt_t, const optional<T> &opt);
775 template <typename T>
776 constexpr bool operator!=(const optional<T> &opt, nullopt_t);
777 template <typename T>
778 constexpr bool operator!=(nullopt_t, const optional<T> &opt);
779 
780 template <typename T, typename U>
781 constexpr bool operator==(const optional<T> &opt, const U &value);
782 template <typename T, typename U>
783 constexpr bool operator==(const T &value, const optional<U> &opt);
784 template <typename T, typename U>
785 constexpr bool operator!=(const optional<T> &opt, const U &value);
786 template <typename T, typename U>
787 constexpr bool operator!=(const T &value, const optional<U> &opt);
788 
789 } // namespace std
790 )";
791 
792 static constexpr char AbslOptionalHeader[] = R"(
793 #include "absl_type_traits.h"
794 #include "std_initializer_list.h"
795 #include "std_type_traits.h"
796 #include "std_utility.h"
797 
798 namespace absl {
799 
800 struct nullopt_t {
801   constexpr explicit nullopt_t() {}
802 };
803 constexpr nullopt_t nullopt;
804 
805 struct in_place_t {};
806 constexpr in_place_t in_place;
807 
808 template <typename T>
809 class optional;
810 
811 namespace optional_internal {
812 
813 template <typename T, typename U>
814 struct is_constructible_convertible_from_optional
815     : std::integral_constant<
816           bool, std::is_constructible<T, optional<U>&>::value ||
817                     std::is_constructible<T, optional<U>&&>::value ||
818                     std::is_constructible<T, const optional<U>&>::value ||
819                     std::is_constructible<T, const optional<U>&&>::value ||
820                     std::is_convertible<optional<U>&, T>::value ||
821                     std::is_convertible<optional<U>&&, T>::value ||
822                     std::is_convertible<const optional<U>&, T>::value ||
823                     std::is_convertible<const optional<U>&&, T>::value> {};
824 
825 template <typename T, typename U>
826 struct is_constructible_convertible_assignable_from_optional
827     : std::integral_constant<
828           bool, is_constructible_convertible_from_optional<T, U>::value ||
829                     std::is_assignable<T&, optional<U>&>::value ||
830                     std::is_assignable<T&, optional<U>&&>::value ||
831                     std::is_assignable<T&, const optional<U>&>::value ||
832                     std::is_assignable<T&, const optional<U>&&>::value> {};
833 
834 }  // namespace optional_internal
835 
836 template <typename T>
837 class optional {
838  public:
839   constexpr optional() noexcept;
840 
841   constexpr optional(nullopt_t) noexcept;
842 
843   optional(const optional&) = default;
844 
845   optional(optional&&) = default;
846 
847   template <typename InPlaceT, typename... Args,
848             absl::enable_if_t<absl::conjunction<
849                 std::is_same<InPlaceT, in_place_t>,
850                 std::is_constructible<T, Args&&...>>::value>* = nullptr>
851   constexpr explicit optional(InPlaceT, Args&&... args);
852 
853   template <typename U, typename... Args,
854             typename = typename std::enable_if<std::is_constructible<
855                 T, std::initializer_list<U>&, Args&&...>::value>::type>
856   constexpr explicit optional(in_place_t, std::initializer_list<U> il,
857                               Args&&... args);
858 
859   template <
860       typename U = T,
861       typename std::enable_if<
862           absl::conjunction<absl::negation<std::is_same<
863                                 in_place_t, typename std::decay<U>::type>>,
864                             absl::negation<std::is_same<
865                                 optional<T>, typename std::decay<U>::type>>,
866                             std::is_convertible<U&&, T>,
867                             std::is_constructible<T, U&&>>::value,
868           bool>::type = false>
869   constexpr optional(U&& v);
870 
871   template <
872       typename U = T,
873       typename std::enable_if<
874           absl::conjunction<absl::negation<std::is_same<
875                                 in_place_t, typename std::decay<U>::type>>,
876                             absl::negation<std::is_same<
877                                 optional<T>, typename std::decay<U>::type>>,
878                             absl::negation<std::is_convertible<U&&, T>>,
879                             std::is_constructible<T, U&&>>::value,
880           bool>::type = false>
881   explicit constexpr optional(U&& v);
882 
883   template <typename U,
884             typename std::enable_if<
885                 absl::conjunction<
886                     absl::negation<std::is_same<T, U>>,
887                     std::is_constructible<T, const U&>,
888                     absl::negation<
889                         optional_internal::
890                             is_constructible_convertible_from_optional<T, U>>,
891                     std::is_convertible<const U&, T>>::value,
892                 bool>::type = false>
893   optional(const optional<U>& rhs);
894 
895   template <typename U,
896             typename std::enable_if<
897                 absl::conjunction<
898                     absl::negation<std::is_same<T, U>>,
899                     std::is_constructible<T, const U&>,
900                     absl::negation<
901                         optional_internal::
902                             is_constructible_convertible_from_optional<T, U>>,
903                     absl::negation<std::is_convertible<const U&, T>>>::value,
904                 bool>::type = false>
905   explicit optional(const optional<U>& rhs);
906 
907   template <
908       typename U,
909       typename std::enable_if<
910           absl::conjunction<
911               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
912               absl::negation<
913                   optional_internal::is_constructible_convertible_from_optional<
914                       T, U>>,
915               std::is_convertible<U&&, T>>::value,
916           bool>::type = false>
917   optional(optional<U>&& rhs);
918 
919   template <
920       typename U,
921       typename std::enable_if<
922           absl::conjunction<
923               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
924               absl::negation<
925                   optional_internal::is_constructible_convertible_from_optional<
926                       T, U>>,
927               absl::negation<std::is_convertible<U&&, T>>>::value,
928           bool>::type = false>
929   explicit optional(optional<U>&& rhs);
930 
931   optional& operator=(nullopt_t) noexcept;
932 
933   optional& operator=(const optional& src);
934 
935   optional& operator=(optional&& src);
936 
937   template <
938       typename U = T,
939       typename = typename std::enable_if<absl::conjunction<
940           absl::negation<
941               std::is_same<optional<T>, typename std::decay<U>::type>>,
942           absl::negation<
943               absl::conjunction<std::is_scalar<T>,
944                                 std::is_same<T, typename std::decay<U>::type>>>,
945           std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
946   optional& operator=(U&& v);
947 
948   template <
949       typename U,
950       typename = typename std::enable_if<absl::conjunction<
951           absl::negation<std::is_same<T, U>>,
952           std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
953           absl::negation<
954               optional_internal::
955                   is_constructible_convertible_assignable_from_optional<
956                       T, U>>>::value>::type>
957   optional& operator=(const optional<U>& rhs);
958 
959   template <typename U,
960             typename = typename std::enable_if<absl::conjunction<
961                 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
962                 std::is_assignable<T&, U>,
963                 absl::negation<
964                     optional_internal::
965                         is_constructible_convertible_assignable_from_optional<
966                             T, U>>>::value>::type>
967   optional& operator=(optional<U>&& rhs);
968 
969   const T& operator*() const&;
970   T& operator*() &;
971   const T&& operator*() const&&;
972   T&& operator*() &&;
973 
974   const T* operator->() const;
975   T* operator->();
976 
977   const T& value() const&;
978   T& value() &;
979   const T&& value() const&&;
980   T&& value() &&;
981 
982   template <typename U>
983   constexpr T value_or(U&& v) const&;
984   template <typename U>
985   T value_or(U&& v) &&;
986 
987   template <typename... Args>
988   T& emplace(Args&&... args);
989 
990   template <typename U, typename... Args>
991   T& emplace(std::initializer_list<U> ilist, Args&&... args);
992 
993   void reset() noexcept;
994 
995   constexpr explicit operator bool() const noexcept;
996   constexpr bool has_value() const noexcept;
997 
998   void swap(optional& rhs) noexcept;
999 };
1000 
1001 template <typename T>
1002 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
1003 
1004 template <typename T, typename... Args>
1005 constexpr optional<T> make_optional(Args&&... args);
1006 
1007 template <typename T, typename U, typename... Args>
1008 constexpr optional<T> make_optional(std::initializer_list<U> il,
1009                                     Args&&... args);
1010 
1011 template <typename T, typename U>
1012 constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs);
1013 template <typename T, typename U>
1014 constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs);
1015 
1016 template <typename T>
1017 constexpr bool operator==(const optional<T> &opt, nullopt_t);
1018 template <typename T>
1019 constexpr bool operator==(nullopt_t, const optional<T> &opt);
1020 template <typename T>
1021 constexpr bool operator!=(const optional<T> &opt, nullopt_t);
1022 template <typename T>
1023 constexpr bool operator!=(nullopt_t, const optional<T> &opt);
1024 
1025 template <typename T, typename U>
1026 constexpr bool operator==(const optional<T> &opt, const U &value);
1027 template <typename T, typename U>
1028 constexpr bool operator==(const T &value, const optional<U> &opt);
1029 template <typename T, typename U>
1030 constexpr bool operator!=(const optional<T> &opt, const U &value);
1031 template <typename T, typename U>
1032 constexpr bool operator!=(const T &value, const optional<U> &opt);
1033 
1034 } // namespace absl
1035 )";
1036 
1037 static constexpr char BaseOptionalHeader[] = R"(
1038 #include "std_initializer_list.h"
1039 #include "std_type_traits.h"
1040 #include "std_utility.h"
1041 
1042 namespace base {
1043 
1044 struct in_place_t {};
1045 constexpr in_place_t in_place;
1046 
1047 struct nullopt_t {
1048   constexpr explicit nullopt_t() {}
1049 };
1050 constexpr nullopt_t nullopt;
1051 
1052 template <typename T>
1053 class Optional;
1054 
1055 namespace internal {
1056 
1057 template <typename T>
1058 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
1059 
1060 template <typename T, typename U>
1061 struct IsConvertibleFromOptional
1062     : std::integral_constant<
1063           bool, std::is_constructible<T, Optional<U>&>::value ||
1064                     std::is_constructible<T, const Optional<U>&>::value ||
1065                     std::is_constructible<T, Optional<U>&&>::value ||
1066                     std::is_constructible<T, const Optional<U>&&>::value ||
1067                     std::is_convertible<Optional<U>&, T>::value ||
1068                     std::is_convertible<const Optional<U>&, T>::value ||
1069                     std::is_convertible<Optional<U>&&, T>::value ||
1070                     std::is_convertible<const Optional<U>&&, T>::value> {};
1071 
1072 template <typename T, typename U>
1073 struct IsAssignableFromOptional
1074     : std::integral_constant<
1075           bool, IsConvertibleFromOptional<T, U>::value ||
1076                     std::is_assignable<T&, Optional<U>&>::value ||
1077                     std::is_assignable<T&, const Optional<U>&>::value ||
1078                     std::is_assignable<T&, Optional<U>&&>::value ||
1079                     std::is_assignable<T&, const Optional<U>&&>::value> {};
1080 
1081 }  // namespace internal
1082 
1083 template <typename T>
1084 class Optional {
1085  public:
1086   using value_type = T;
1087 
1088   constexpr Optional() = default;
1089   constexpr Optional(const Optional& other) noexcept = default;
1090   constexpr Optional(Optional&& other) noexcept = default;
1091 
1092   constexpr Optional(nullopt_t);
1093 
1094   template <typename U,
1095             typename std::enable_if<
1096                 std::is_constructible<T, const U&>::value &&
1097                     !internal::IsConvertibleFromOptional<T, U>::value &&
1098                     std::is_convertible<const U&, T>::value,
1099                 bool>::type = false>
1100   Optional(const Optional<U>& other) noexcept;
1101 
1102   template <typename U,
1103             typename std::enable_if<
1104                 std::is_constructible<T, const U&>::value &&
1105                     !internal::IsConvertibleFromOptional<T, U>::value &&
1106                     !std::is_convertible<const U&, T>::value,
1107                 bool>::type = false>
1108   explicit Optional(const Optional<U>& other) noexcept;
1109 
1110   template <typename U,
1111             typename std::enable_if<
1112                 std::is_constructible<T, U&&>::value &&
1113                     !internal::IsConvertibleFromOptional<T, U>::value &&
1114                     std::is_convertible<U&&, T>::value,
1115                 bool>::type = false>
1116   Optional(Optional<U>&& other) noexcept;
1117 
1118   template <typename U,
1119             typename std::enable_if<
1120                 std::is_constructible<T, U&&>::value &&
1121                     !internal::IsConvertibleFromOptional<T, U>::value &&
1122                     !std::is_convertible<U&&, T>::value,
1123                 bool>::type = false>
1124   explicit Optional(Optional<U>&& other) noexcept;
1125 
1126   template <class... Args>
1127   constexpr explicit Optional(in_place_t, Args&&... args);
1128 
1129   template <class U, class... Args,
1130             class = typename std::enable_if<std::is_constructible<
1131                 value_type, std::initializer_list<U>&, Args...>::value>::type>
1132   constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
1133                               Args&&... args);
1134 
1135   template <
1136       typename U = value_type,
1137       typename std::enable_if<
1138           std::is_constructible<T, U&&>::value &&
1139               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1140               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1141               std::is_convertible<U&&, T>::value,
1142           bool>::type = false>
1143   constexpr Optional(U&& value);
1144 
1145   template <
1146       typename U = value_type,
1147       typename std::enable_if<
1148           std::is_constructible<T, U&&>::value &&
1149               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1150               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1151               !std::is_convertible<U&&, T>::value,
1152           bool>::type = false>
1153   constexpr explicit Optional(U&& value);
1154 
1155   Optional& operator=(const Optional& other) noexcept;
1156 
1157   Optional& operator=(Optional&& other) noexcept;
1158 
1159   Optional& operator=(nullopt_t);
1160 
1161   template <typename U>
1162   typename std::enable_if<
1163       !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1164           std::is_constructible<T, U>::value &&
1165           std::is_assignable<T&, U>::value &&
1166           (!std::is_scalar<T>::value ||
1167            !std::is_same<typename std::decay<U>::type, T>::value),
1168       Optional&>::type
1169   operator=(U&& value) noexcept;
1170 
1171   template <typename U>
1172   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1173                               std::is_constructible<T, const U&>::value &&
1174                               std::is_assignable<T&, const U&>::value,
1175                           Optional&>::type
1176   operator=(const Optional<U>& other) noexcept;
1177 
1178   template <typename U>
1179   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1180                               std::is_constructible<T, U>::value &&
1181                               std::is_assignable<T&, U>::value,
1182                           Optional&>::type
1183   operator=(Optional<U>&& other) noexcept;
1184 
1185   const T& operator*() const&;
1186   T& operator*() &;
1187   const T&& operator*() const&&;
1188   T&& operator*() &&;
1189 
1190   const T* operator->() const;
1191   T* operator->();
1192 
1193   const T& value() const&;
1194   T& value() &;
1195   const T&& value() const&&;
1196   T&& value() &&;
1197 
1198   template <typename U>
1199   constexpr T value_or(U&& v) const&;
1200   template <typename U>
1201   T value_or(U&& v) &&;
1202 
1203   template <typename... Args>
1204   T& emplace(Args&&... args);
1205 
1206   template <typename U, typename... Args>
1207   T& emplace(std::initializer_list<U> ilist, Args&&... args);
1208 
1209   void reset() noexcept;
1210 
1211   constexpr explicit operator bool() const noexcept;
1212   constexpr bool has_value() const noexcept;
1213 
1214   void swap(Optional& other);
1215 };
1216 
1217 template <typename T>
1218 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v);
1219 
1220 template <typename T, typename... Args>
1221 constexpr Optional<T> make_optional(Args&&... args);
1222 
1223 template <typename T, typename U, typename... Args>
1224 constexpr Optional<T> make_optional(std::initializer_list<U> il,
1225                                     Args&&... args);
1226 
1227 template <typename T, typename U>
1228 constexpr bool operator==(const Optional<T> &lhs, const Optional<U> &rhs);
1229 template <typename T, typename U>
1230 constexpr bool operator!=(const Optional<T> &lhs, const Optional<U> &rhs);
1231 
1232 template <typename T>
1233 constexpr bool operator==(const Optional<T> &opt, nullopt_t);
1234 template <typename T>
1235 constexpr bool operator==(nullopt_t, const Optional<T> &opt);
1236 template <typename T>
1237 constexpr bool operator!=(const Optional<T> &opt, nullopt_t);
1238 template <typename T>
1239 constexpr bool operator!=(nullopt_t, const Optional<T> &opt);
1240 
1241 template <typename T, typename U>
1242 constexpr bool operator==(const Optional<T> &opt, const U &value);
1243 template <typename T, typename U>
1244 constexpr bool operator==(const T &value, const Optional<U> &opt);
1245 template <typename T, typename U>
1246 constexpr bool operator!=(const Optional<T> &opt, const U &value);
1247 template <typename T, typename U>
1248 constexpr bool operator!=(const T &value, const Optional<U> &opt);
1249 
1250 } // namespace base
1251 )";
1252 
1253 /// Replaces all occurrences of `Pattern` in `S` with `Replacement`.
1254 static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern,
1255                                   const std::string &Replacement) {
1256   size_t Pos = 0;
1257   while (true) {
1258     Pos = S.find(Pattern, Pos);
1259     if (Pos == std::string::npos)
1260       break;
1261     S.replace(Pos, Pattern.size(), Replacement);
1262   }
1263 }
1264 
1265 struct OptionalTypeIdentifier {
1266   std::string NamespaceName;
1267   std::string TypeName;
1268 };
1269 
1270 class UncheckedOptionalAccessTest
1271     : public ::testing::TestWithParam<OptionalTypeIdentifier> {
1272 protected:
1273   void ExpectDiagnosticsFor(std::string SourceCode) {
1274     ExpectDiagnosticsFor(SourceCode, ast_matchers::hasName("target"));
1275   }
1276 
1277   template <typename FuncDeclMatcher>
1278   void ExpectDiagnosticsFor(std::string SourceCode,
1279                             FuncDeclMatcher FuncMatcher) {
1280     ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName);
1281     ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName);
1282 
1283     std::vector<std::pair<std::string, std::string>> Headers;
1284     Headers.emplace_back("cstddef.h", CSDtdDefHeader);
1285     Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader);
1286     Headers.emplace_back("std_string.h", StdStringHeader);
1287     Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader);
1288     Headers.emplace_back("std_utility.h", StdUtilityHeader);
1289     Headers.emplace_back("std_optional.h", StdOptionalHeader);
1290     Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader);
1291     Headers.emplace_back("absl_optional.h", AbslOptionalHeader);
1292     Headers.emplace_back("base_optional.h", BaseOptionalHeader);
1293     Headers.emplace_back("unchecked_optional_access_test.h", R"(
1294       #include "absl_optional.h"
1295       #include "base_optional.h"
1296       #include "std_initializer_list.h"
1297       #include "std_optional.h"
1298       #include "std_string.h"
1299       #include "std_utility.h"
1300 
1301       template <typename T>
1302       T Make();
1303     )");
1304     UncheckedOptionalAccessModelOptions Options{
1305         /*IgnoreSmartPointerDereference=*/true};
1306     std::vector<SourceLocation> Diagnostics;
1307     llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
1308         AnalysisInputs<UncheckedOptionalAccessModel>(
1309             SourceCode, std::move(FuncMatcher),
1310             [](ASTContext &Ctx, Environment &) {
1311               return UncheckedOptionalAccessModel(Ctx);
1312             })
1313             .withPostVisitCFG(
1314                 [&Diagnostics,
1315                  Diagnoser = UncheckedOptionalAccessDiagnoser(Options)](
1316                     ASTContext &Ctx, const CFGElement &Elt,
1317                     const TransferStateForDiagnostics<NoopLattice>
1318                         &State) mutable {
1319                   auto EltDiagnostics =
1320                       Diagnoser.diagnose(Ctx, &Elt, State.Env);
1321                   llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
1322                 })
1323             .withASTBuildArgs(
1324                 {"-fsyntax-only", "-std=c++17", "-Wno-undefined-inline"})
1325             .withASTBuildVirtualMappedFiles(
1326                 tooling::FileContentMappings(Headers.begin(), Headers.end())),
1327         /*VerifyResults=*/[&Diagnostics](
1328                               const llvm::DenseMap<unsigned, std::string>
1329                                   &Annotations,
1330                               const AnalysisOutputs &AO) {
1331           llvm::DenseSet<unsigned> AnnotationLines;
1332           for (const auto &[Line, _] : Annotations) {
1333             AnnotationLines.insert(Line);
1334           }
1335           auto &SrcMgr = AO.ASTCtx.getSourceManager();
1336           llvm::DenseSet<unsigned> DiagnosticLines;
1337           for (SourceLocation &Loc : Diagnostics) {
1338             unsigned Line = SrcMgr.getPresumedLineNumber(Loc);
1339             DiagnosticLines.insert(Line);
1340             if (!AnnotationLines.contains(Line)) {
1341               IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
1342                   new DiagnosticOptions());
1343               TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
1344                                 DiagOpts.get());
1345               TD.emitDiagnostic(
1346                   FullSourceLoc(Loc, SrcMgr), DiagnosticsEngine::Error,
1347                   "unexpected diagnostic", std::nullopt, std::nullopt);
1348             }
1349           }
1350 
1351           EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines));
1352         });
1353     if (Error)
1354       FAIL() << llvm::toString(std::move(Error));
1355   }
1356 };
1357 
1358 INSTANTIATE_TEST_SUITE_P(
1359     UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
1360     ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
1361                       OptionalTypeIdentifier{"absl", "optional"},
1362                       OptionalTypeIdentifier{"base", "Optional"}),
1363     [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
1364       return Info.param.NamespaceName;
1365     });
1366 
1367 // Verifies that similarly-named types are ignored.
1368 TEST_P(UncheckedOptionalAccessTest, NonTrackedOptionalType) {
1369   ExpectDiagnosticsFor(
1370       R"(
1371     namespace other {
1372     namespace $ns {
1373     template <typename T>
1374     struct $optional {
1375       T value();
1376     };
1377     }
1378 
1379     void target($ns::$optional<int> opt) {
1380       opt.value();
1381     }
1382     }
1383   )");
1384 }
1385 
1386 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
1387   ExpectDiagnosticsFor(R"(
1388     void target() {
1389       (void)0;
1390     }
1391   )");
1392 }
1393 
1394 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
1395   ExpectDiagnosticsFor(
1396       R"(
1397     #include "unchecked_optional_access_test.h"
1398 
1399     void target($ns::$optional<int> opt) {
1400       opt.value(); // [[unsafe]]
1401     }
1402   )");
1403 
1404   ExpectDiagnosticsFor(
1405       R"(
1406     #include "unchecked_optional_access_test.h"
1407 
1408     void target($ns::$optional<int> opt) {
1409       std::move(opt).value(); // [[unsafe]]
1410     }
1411   )");
1412 }
1413 
1414 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
1415   ExpectDiagnosticsFor(
1416       R"(
1417     #include "unchecked_optional_access_test.h"
1418 
1419     void target($ns::$optional<int> opt) {
1420       *opt; // [[unsafe]]
1421     }
1422   )");
1423 
1424   ExpectDiagnosticsFor(
1425       R"(
1426     #include "unchecked_optional_access_test.h"
1427 
1428     void target($ns::$optional<int> opt) {
1429       *std::move(opt); // [[unsafe]]
1430     }
1431   )");
1432 }
1433 
1434 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
1435   ExpectDiagnosticsFor(
1436       R"(
1437     #include "unchecked_optional_access_test.h"
1438 
1439     struct Foo {
1440       void foo();
1441     };
1442 
1443     void target($ns::$optional<Foo> opt) {
1444       opt->foo(); // [[unsafe]]
1445     }
1446   )");
1447 
1448   ExpectDiagnosticsFor(
1449       R"(
1450     #include "unchecked_optional_access_test.h"
1451 
1452     struct Foo {
1453       void foo();
1454     };
1455 
1456     void target($ns::$optional<Foo> opt) {
1457       std::move(opt)->foo(); // [[unsafe]]
1458     }
1459   )");
1460 }
1461 
1462 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
1463   ExpectDiagnosticsFor(R"(
1464     #include "unchecked_optional_access_test.h"
1465 
1466     void target($ns::$optional<int> opt) {
1467       if (opt.has_value()) {
1468         opt.value();
1469       }
1470     }
1471   )");
1472 }
1473 
1474 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
1475   ExpectDiagnosticsFor(R"(
1476     #include "unchecked_optional_access_test.h"
1477 
1478     void target($ns::$optional<int> opt) {
1479       if (opt) {
1480         opt.value();
1481       }
1482     }
1483   )");
1484 }
1485 
1486 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
1487   ExpectDiagnosticsFor(
1488       R"(
1489     #include "unchecked_optional_access_test.h"
1490 
1491     void target() {
1492       Make<$ns::$optional<int>>().value(); // [[unsafe]]
1493       (void)0;
1494     }
1495   )");
1496 
1497   ExpectDiagnosticsFor(
1498       R"(
1499     #include "unchecked_optional_access_test.h"
1500 
1501     void target($ns::$optional<int> opt) {
1502       std::move(opt).value(); // [[unsafe]]
1503     }
1504   )");
1505 }
1506 
1507 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
1508   ExpectDiagnosticsFor(
1509       R"(
1510     #include "unchecked_optional_access_test.h"
1511 
1512     void target() {
1513       $ns::$optional<int> opt;
1514       opt.value(); // [[unsafe]]
1515     }
1516   )");
1517 }
1518 
1519 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
1520   ExpectDiagnosticsFor(
1521       R"(
1522     #include "unchecked_optional_access_test.h"
1523 
1524     void target() {
1525       $ns::$optional<int> opt($ns::nullopt);
1526       opt.value(); // [[unsafe]]
1527     }
1528   )");
1529 }
1530 
1531 TEST_P(UncheckedOptionalAccessTest, NulloptConstructorWithSugaredType) {
1532   ExpectDiagnosticsFor(
1533       R"(
1534     #include "unchecked_optional_access_test.h"
1535     template <typename T>
1536     using wrapper = T;
1537 
1538     template <typename T>
1539     wrapper<T> wrap(T);
1540 
1541     void target() {
1542       $ns::$optional<int> opt(wrap($ns::nullopt));
1543       opt.value(); // [[unsafe]]
1544     }
1545   )");
1546 }
1547 
1548 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
1549   ExpectDiagnosticsFor(R"(
1550     #include "unchecked_optional_access_test.h"
1551 
1552     void target() {
1553       $ns::$optional<int> opt($ns::in_place, 3);
1554       opt.value();
1555     }
1556   )");
1557 
1558   ExpectDiagnosticsFor(R"(
1559     #include "unchecked_optional_access_test.h"
1560 
1561     struct Foo {};
1562 
1563     void target() {
1564       $ns::$optional<Foo> opt($ns::in_place);
1565       opt.value();
1566     }
1567   )");
1568 
1569   ExpectDiagnosticsFor(R"(
1570     #include "unchecked_optional_access_test.h"
1571 
1572     struct Foo {
1573       explicit Foo(int, bool);
1574     };
1575 
1576     void target() {
1577       $ns::$optional<Foo> opt($ns::in_place, 3, false);
1578       opt.value();
1579     }
1580   )");
1581 
1582   ExpectDiagnosticsFor(R"(
1583     #include "unchecked_optional_access_test.h"
1584 
1585     struct Foo {
1586       explicit Foo(std::initializer_list<int>);
1587     };
1588 
1589     void target() {
1590       $ns::$optional<Foo> opt($ns::in_place, {3});
1591       opt.value();
1592     }
1593   )");
1594 }
1595 
1596 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
1597   ExpectDiagnosticsFor(R"(
1598     #include "unchecked_optional_access_test.h"
1599 
1600     void target() {
1601       $ns::$optional<int> opt(21);
1602       opt.value();
1603     }
1604   )");
1605 
1606   ExpectDiagnosticsFor(R"(
1607     #include "unchecked_optional_access_test.h"
1608 
1609     void target() {
1610       $ns::$optional<int> opt = $ns::$optional<int>(21);
1611       opt.value();
1612     }
1613   )");
1614   ExpectDiagnosticsFor(R"(
1615     #include "unchecked_optional_access_test.h"
1616 
1617     void target() {
1618       $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1619       opt.value();
1620     }
1621   )");
1622 
1623   ExpectDiagnosticsFor(R"(
1624     #include "unchecked_optional_access_test.h"
1625 
1626     struct MyString {
1627       MyString(const char*);
1628     };
1629 
1630     void target() {
1631       $ns::$optional<MyString> opt("foo");
1632       opt.value();
1633     }
1634   )");
1635 
1636   ExpectDiagnosticsFor(R"(
1637     #include "unchecked_optional_access_test.h"
1638 
1639     struct Foo {};
1640 
1641     struct Bar {
1642       Bar(const Foo&);
1643     };
1644 
1645     void target() {
1646       $ns::$optional<Bar> opt(Make<Foo>());
1647       opt.value();
1648     }
1649   )");
1650 
1651   ExpectDiagnosticsFor(R"(
1652     #include "unchecked_optional_access_test.h"
1653 
1654     struct Foo {
1655       explicit Foo(int);
1656     };
1657 
1658     void target() {
1659       $ns::$optional<Foo> opt(3);
1660       opt.value();
1661     }
1662   )");
1663 }
1664 
1665 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
1666   ExpectDiagnosticsFor(
1667       R"(
1668     #include "unchecked_optional_access_test.h"
1669 
1670     struct Foo {};
1671 
1672     struct Bar {
1673       Bar(const Foo&);
1674     };
1675 
1676     void target() {
1677       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1678       opt.value(); // [[unsafe]]
1679     }
1680   )");
1681 
1682   ExpectDiagnosticsFor(
1683       R"(
1684     #include "unchecked_optional_access_test.h"
1685 
1686     struct Foo {};
1687 
1688     struct Bar {
1689       explicit Bar(const Foo&);
1690     };
1691 
1692     void target() {
1693       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1694       opt.value(); // [[unsafe]]
1695     }
1696   )");
1697 
1698   ExpectDiagnosticsFor(
1699       R"(
1700     #include "unchecked_optional_access_test.h"
1701 
1702     struct Foo {};
1703 
1704     struct Bar {
1705       Bar(const Foo&);
1706     };
1707 
1708     void target() {
1709       $ns::$optional<Foo> opt1 = $ns::nullopt;
1710       $ns::$optional<Bar> opt2(opt1);
1711       opt2.value(); // [[unsafe]]
1712     }
1713   )");
1714 
1715   ExpectDiagnosticsFor(R"(
1716     #include "unchecked_optional_access_test.h"
1717 
1718     struct Foo {};
1719 
1720     struct Bar {
1721       Bar(const Foo&);
1722     };
1723 
1724     void target() {
1725       $ns::$optional<Foo> opt1(Make<Foo>());
1726       $ns::$optional<Bar> opt2(opt1);
1727       opt2.value();
1728     }
1729   )");
1730 
1731   ExpectDiagnosticsFor(R"(
1732     #include "unchecked_optional_access_test.h"
1733 
1734     struct Foo {};
1735 
1736     struct Bar {
1737       explicit Bar(const Foo&);
1738     };
1739 
1740     void target() {
1741       $ns::$optional<Foo> opt1(Make<Foo>());
1742       $ns::$optional<Bar> opt2(opt1);
1743       opt2.value();
1744     }
1745   )");
1746 }
1747 
1748 TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
1749   ExpectDiagnosticsFor(R"(
1750     #include "unchecked_optional_access_test.h"
1751 
1752     void target() {
1753       $ns::$optional<int> opt = $ns::make_optional(0);
1754       opt.value();
1755     }
1756   )");
1757 
1758   ExpectDiagnosticsFor(R"(
1759     #include "unchecked_optional_access_test.h"
1760 
1761     struct Foo {
1762       Foo(int, int);
1763     };
1764 
1765     void target() {
1766       $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1767       opt.value();
1768     }
1769   )");
1770 
1771   ExpectDiagnosticsFor(R"(
1772     #include "unchecked_optional_access_test.h"
1773 
1774     struct Foo {
1775       constexpr Foo(std::initializer_list<char>);
1776     };
1777 
1778     void target() {
1779       char a = 'a';
1780       $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1781       opt.value();
1782     }
1783   )");
1784 }
1785 
1786 TEST_P(UncheckedOptionalAccessTest, ValueOr) {
1787   ExpectDiagnosticsFor(R"(
1788     #include "unchecked_optional_access_test.h"
1789 
1790     void target() {
1791       $ns::$optional<int> opt;
1792       opt.value_or(0);
1793       (void)0;
1794     }
1795   )");
1796 }
1797 
1798 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointers) {
1799   ExpectDiagnosticsFor(
1800       R"code(
1801     #include "unchecked_optional_access_test.h"
1802 
1803     void target($ns::$optional<int*> opt) {
1804       if (opt.value_or(nullptr) != nullptr) {
1805         opt.value();
1806       } else {
1807         opt.value(); // [[unsafe]]
1808       }
1809     }
1810   )code");
1811 }
1812 
1813 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonIntegers) {
1814   ExpectDiagnosticsFor(
1815       R"code(
1816     #include "unchecked_optional_access_test.h"
1817 
1818     void target($ns::$optional<int> opt) {
1819       if (opt.value_or(0) != 0) {
1820         opt.value();
1821       } else {
1822         opt.value(); // [[unsafe]]
1823       }
1824     }
1825   )code");
1826 }
1827 
1828 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonStrings) {
1829   ExpectDiagnosticsFor(
1830       R"code(
1831     #include "unchecked_optional_access_test.h"
1832 
1833     void target($ns::$optional<std::string> opt) {
1834       if (!opt.value_or("").empty()) {
1835         opt.value();
1836       } else {
1837         opt.value(); // [[unsafe]]
1838       }
1839     }
1840   )code");
1841 
1842   ExpectDiagnosticsFor(
1843       R"code(
1844     #include "unchecked_optional_access_test.h"
1845 
1846     void target($ns::$optional<std::string> opt) {
1847       if (opt.value_or("") != "") {
1848         opt.value();
1849       } else {
1850         opt.value(); // [[unsafe]]
1851       }
1852     }
1853   )code");
1854 }
1855 
1856 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointerToOptional) {
1857   // FIXME: make `opt` a parameter directly, once we ensure that all `optional`
1858   // values have a `has_value` property.
1859   ExpectDiagnosticsFor(
1860       R"code(
1861     #include "unchecked_optional_access_test.h"
1862 
1863     void target($ns::$optional<int> p) {
1864       $ns::$optional<int> *opt = &p;
1865       if (opt->value_or(0) != 0) {
1866         opt->value();
1867       } else {
1868         opt->value(); // [[unsafe]]
1869       }
1870     }
1871   )code");
1872 }
1873 
1874 TEST_P(UncheckedOptionalAccessTest, Emplace) {
1875   ExpectDiagnosticsFor(R"(
1876     #include "unchecked_optional_access_test.h"
1877 
1878     void target() {
1879       $ns::$optional<int> opt;
1880       opt.emplace(0);
1881       opt.value();
1882     }
1883   )");
1884 
1885   ExpectDiagnosticsFor(R"(
1886     #include "unchecked_optional_access_test.h"
1887 
1888     void target($ns::$optional<int> *opt) {
1889       opt->emplace(0);
1890       opt->value();
1891     }
1892   )");
1893 
1894   // FIXME: Add tests that call `emplace` in conditional branches:
1895   //  ExpectDiagnosticsFor(
1896   //      R"(
1897   //    #include "unchecked_optional_access_test.h"
1898   //
1899   //    void target($ns::$optional<int> opt, bool b) {
1900   //      if (b) {
1901   //        opt.emplace(0);
1902   //      }
1903   //      if (b) {
1904   //        opt.value();
1905   //      } else {
1906   //        opt.value(); // [[unsafe]]
1907   //      }
1908   //    }
1909   //  )");
1910 }
1911 
1912 TEST_P(UncheckedOptionalAccessTest, Reset) {
1913   ExpectDiagnosticsFor(
1914       R"(
1915     #include "unchecked_optional_access_test.h"
1916 
1917     void target() {
1918       $ns::$optional<int> opt = $ns::make_optional(0);
1919       opt.reset();
1920       opt.value(); // [[unsafe]]
1921     }
1922   )");
1923 
1924   ExpectDiagnosticsFor(
1925       R"(
1926     #include "unchecked_optional_access_test.h"
1927 
1928     void target($ns::$optional<int> &opt) {
1929       if (opt.has_value()) {
1930         opt.reset();
1931         opt.value(); // [[unsafe]]
1932       }
1933     }
1934   )");
1935 
1936   // FIXME: Add tests that call `reset` in conditional branches:
1937   //  ExpectDiagnosticsFor(
1938   //      R"(
1939   //    #include "unchecked_optional_access_test.h"
1940   //
1941   //    void target(bool b) {
1942   //      $ns::$optional<int> opt = $ns::make_optional(0);
1943   //      if (b) {
1944   //        opt.reset();
1945   //      }
1946   //      if (b) {
1947   //        opt.value(); // [[unsafe]]
1948   //      } else {
1949   //        opt.value();
1950   //      }
1951   //    }
1952   //  )");
1953 }
1954 
1955 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) {
1956   ExpectDiagnosticsFor(R"(
1957     #include "unchecked_optional_access_test.h"
1958 
1959     struct Foo {};
1960 
1961     void target() {
1962       $ns::$optional<Foo> opt;
1963       opt = Foo();
1964       opt.value();
1965     }
1966   )");
1967 
1968   ExpectDiagnosticsFor(R"(
1969     #include "unchecked_optional_access_test.h"
1970 
1971     struct Foo {};
1972 
1973     void target() {
1974       $ns::$optional<Foo> opt;
1975       (opt = Foo()).value();
1976       (void)0;
1977     }
1978   )");
1979 
1980   ExpectDiagnosticsFor(R"(
1981     #include "unchecked_optional_access_test.h"
1982 
1983     struct MyString {
1984       MyString(const char*);
1985     };
1986 
1987     void target() {
1988       $ns::$optional<MyString> opt;
1989       opt = "foo";
1990       opt.value();
1991     }
1992   )");
1993 
1994   ExpectDiagnosticsFor(R"(
1995     #include "unchecked_optional_access_test.h"
1996 
1997     struct MyString {
1998       MyString(const char*);
1999     };
2000 
2001     void target() {
2002       $ns::$optional<MyString> opt;
2003       (opt = "foo").value();
2004     }
2005   )");
2006 }
2007 
2008 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) {
2009   ExpectDiagnosticsFor(
2010       R"(
2011     #include "unchecked_optional_access_test.h"
2012 
2013     struct Foo {};
2014 
2015     struct Bar {
2016       Bar(const Foo&);
2017     };
2018 
2019     void target() {
2020       $ns::$optional<Foo> opt1 = Foo();
2021       $ns::$optional<Bar> opt2;
2022       opt2 = opt1;
2023       opt2.value();
2024     }
2025   )");
2026 
2027   ExpectDiagnosticsFor(
2028       R"(
2029     #include "unchecked_optional_access_test.h"
2030 
2031     struct Foo {};
2032 
2033     struct Bar {
2034       Bar(const Foo&);
2035     };
2036 
2037     void target() {
2038       $ns::$optional<Foo> opt1;
2039       $ns::$optional<Bar> opt2;
2040       if (opt2.has_value()) {
2041         opt2 = opt1;
2042         opt2.value(); // [[unsafe]]
2043       }
2044     }
2045   )");
2046 
2047   ExpectDiagnosticsFor(
2048       R"(
2049     #include "unchecked_optional_access_test.h"
2050 
2051     struct Foo {};
2052 
2053     struct Bar {
2054       Bar(const Foo&);
2055     };
2056 
2057     void target() {
2058       $ns::$optional<Foo> opt1 = Foo();
2059       $ns::$optional<Bar> opt2;
2060       (opt2 = opt1).value();
2061       (void)0;
2062     }
2063   )");
2064 }
2065 
2066 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) {
2067   ExpectDiagnosticsFor(
2068       R"(
2069     #include "unchecked_optional_access_test.h"
2070 
2071     void target() {
2072       $ns::$optional<int> opt = 3;
2073       opt = $ns::nullopt;
2074       opt.value(); // [[unsafe]]
2075     }
2076   )");
2077 
2078   ExpectDiagnosticsFor(
2079       R"(
2080     #include "unchecked_optional_access_test.h"
2081 
2082     void target() {
2083       $ns::$optional<int> opt = 3;
2084       (opt = $ns::nullopt).value(); // [[unsafe]]
2085     }
2086   )");
2087 }
2088 
2089 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) {
2090   ExpectDiagnosticsFor(
2091       R"(
2092     #include "unchecked_optional_access_test.h"
2093 
2094     void target() {
2095       $ns::$optional<int> opt1 = $ns::nullopt;
2096       $ns::$optional<int> opt2 = 3;
2097 
2098       opt1.swap(opt2);
2099 
2100       opt1.value();
2101 
2102       opt2.value(); // [[unsafe]]
2103     }
2104   )");
2105 
2106   ExpectDiagnosticsFor(
2107       R"(
2108     #include "unchecked_optional_access_test.h"
2109 
2110     void target() {
2111       $ns::$optional<int> opt1 = $ns::nullopt;
2112       $ns::$optional<int> opt2 = 3;
2113 
2114       opt2.swap(opt1);
2115 
2116       opt1.value();
2117 
2118       opt2.value(); // [[unsafe]]
2119     }
2120   )");
2121 }
2122 
2123 TEST_P(UncheckedOptionalAccessTest, StdSwap) {
2124   ExpectDiagnosticsFor(
2125       R"(
2126     #include "unchecked_optional_access_test.h"
2127 
2128     void target() {
2129       $ns::$optional<int> opt1 = $ns::nullopt;
2130       $ns::$optional<int> opt2 = 3;
2131 
2132       std::swap(opt1, opt2);
2133 
2134       opt1.value();
2135 
2136       opt2.value(); // [[unsafe]]
2137     }
2138   )");
2139 
2140   ExpectDiagnosticsFor(
2141       R"(
2142     #include "unchecked_optional_access_test.h"
2143 
2144     void target() {
2145       $ns::$optional<int> opt1 = $ns::nullopt;
2146       $ns::$optional<int> opt2 = 3;
2147 
2148       std::swap(opt2, opt1);
2149 
2150       opt1.value();
2151 
2152       opt2.value(); // [[unsafe]]
2153     }
2154   )");
2155 }
2156 
2157 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocLeft) {
2158   ExpectDiagnosticsFor(
2159       R"(
2160     #include "unchecked_optional_access_test.h"
2161 
2162     struct L { $ns::$optional<int> hd; L* tl; };
2163 
2164     void target() {
2165       $ns::$optional<int> foo = 3;
2166       L bar;
2167 
2168       // Any `tl` beyond the first is not modeled.
2169       bar.tl->tl->hd.swap(foo);
2170 
2171       bar.tl->tl->hd.value(); // [[unsafe]]
2172       foo.value(); // [[unsafe]]
2173     }
2174   )");
2175 }
2176 
2177 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocRight) {
2178   ExpectDiagnosticsFor(
2179       R"(
2180     #include "unchecked_optional_access_test.h"
2181 
2182     struct L { $ns::$optional<int> hd; L* tl; };
2183 
2184     void target() {
2185       $ns::$optional<int> foo = 3;
2186       L bar;
2187 
2188       // Any `tl` beyond the first is not modeled.
2189       foo.swap(bar.tl->tl->hd);
2190 
2191       bar.tl->tl->hd.value(); // [[unsafe]]
2192       foo.value(); // [[unsafe]]
2193     }
2194   )");
2195 }
2196 
2197 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftSet) {
2198   ExpectDiagnosticsFor(
2199       R"(
2200     #include "unchecked_optional_access_test.h"
2201 
2202     struct S { int x; };
2203     struct A { $ns::$optional<S> late; };
2204     struct B { A f3; };
2205     struct C { B f2; };
2206     struct D { C f1; };
2207 
2208     void target() {
2209       $ns::$optional<S> foo = S{3};
2210       D bar;
2211 
2212       bar.f1.f2.f3.late.swap(foo);
2213 
2214       bar.f1.f2.f3.late.value();
2215       foo.value(); // [[unsafe]]
2216     }
2217   )");
2218 }
2219 
2220 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftUnset) {
2221   ExpectDiagnosticsFor(
2222       R"(
2223     #include "unchecked_optional_access_test.h"
2224 
2225     struct S { int x; };
2226     struct A { $ns::$optional<S> late; };
2227     struct B { A f3; };
2228     struct C { B f2; };
2229     struct D { C f1; };
2230 
2231     void target() {
2232       $ns::$optional<S> foo;
2233       D bar;
2234 
2235       bar.f1.f2.f3.late.swap(foo);
2236 
2237       bar.f1.f2.f3.late.value(); // [[unsafe]]
2238       foo.value(); // [[unsafe]]
2239     }
2240   )");
2241 }
2242 
2243 // fixme: use recursion instead of depth.
2244 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightSet) {
2245   ExpectDiagnosticsFor(
2246       R"(
2247     #include "unchecked_optional_access_test.h"
2248 
2249     struct S { int x; };
2250     struct A { $ns::$optional<S> late; };
2251     struct B { A f3; };
2252     struct C { B f2; };
2253     struct D { C f1; };
2254 
2255     void target() {
2256       $ns::$optional<S> foo = S{3};
2257       D bar;
2258 
2259       foo.swap(bar.f1.f2.f3.late);
2260 
2261       bar.f1.f2.f3.late.value();
2262       foo.value(); // [[unsafe]]
2263     }
2264   )");
2265 }
2266 
2267 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightUnset) {
2268   ExpectDiagnosticsFor(
2269       R"(
2270     #include "unchecked_optional_access_test.h"
2271 
2272     struct S { int x; };
2273     struct A { $ns::$optional<S> late; };
2274     struct B { A f3; };
2275     struct C { B f2; };
2276     struct D { C f1; };
2277 
2278     void target() {
2279       $ns::$optional<S> foo;
2280       D bar;
2281 
2282       foo.swap(bar.f1.f2.f3.late);
2283 
2284       bar.f1.f2.f3.late.value(); // [[unsafe]]
2285       foo.value(); // [[unsafe]]
2286     }
2287   )");
2288 }
2289 
2290 TEST_P(UncheckedOptionalAccessTest, UniquePtrToOptional) {
2291   // We suppress diagnostics for optionals in smart pointers (other than
2292   // `optional` itself).
2293   ExpectDiagnosticsFor(
2294       R"(
2295     #include "unchecked_optional_access_test.h"
2296 
2297     template <typename T>
2298     struct smart_ptr {
2299       T& operator*() &;
2300       T* operator->();
2301     };
2302 
2303     void target() {
2304       smart_ptr<$ns::$optional<bool>> foo;
2305       foo->value();
2306       (*foo).value();
2307     }
2308   )");
2309 }
2310 
2311 TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) {
2312   // We suppress diagnostics for optional fields reachable from smart pointers
2313   // (other than `optional` itself) through (exactly) one member access.
2314   ExpectDiagnosticsFor(
2315       R"(
2316     #include "unchecked_optional_access_test.h"
2317 
2318     template <typename T>
2319     struct smart_ptr {
2320       T& operator*() &;
2321       T* operator->();
2322     };
2323 
2324     struct Foo {
2325       $ns::$optional<int> opt;
2326     };
2327 
2328     void target() {
2329       smart_ptr<Foo> foo;
2330       *foo->opt;
2331       *(*foo).opt;
2332     }
2333   )");
2334 }
2335 
2336 TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) {
2337   ExpectDiagnosticsFor(
2338       R"(
2339     #include "unchecked_optional_access_test.h"
2340 
2341     $ns::$optional<int> MakeOpt();
2342 
2343     void target() {
2344       $ns::$optional<int> opt = 0;
2345       opt = MakeOpt();
2346       opt.value(); // [[unsafe]]
2347     }
2348   )");
2349   ExpectDiagnosticsFor(
2350       R"(
2351     #include "unchecked_optional_access_test.h"
2352 
2353     const $ns::$optional<int>& MakeOpt();
2354 
2355     void target() {
2356       $ns::$optional<int> opt = 0;
2357       opt = MakeOpt();
2358       opt.value(); // [[unsafe]]
2359     }
2360   )");
2361 
2362   ExpectDiagnosticsFor(
2363       R"(
2364     #include "unchecked_optional_access_test.h"
2365 
2366     using IntOpt = $ns::$optional<int>;
2367     IntOpt MakeOpt();
2368 
2369     void target() {
2370       IntOpt opt = 0;
2371       opt = MakeOpt();
2372       opt.value(); // [[unsafe]]
2373     }
2374   )");
2375 
2376   ExpectDiagnosticsFor(
2377       R"(
2378     #include "unchecked_optional_access_test.h"
2379 
2380     using IntOpt = $ns::$optional<int>;
2381     const IntOpt& MakeOpt();
2382 
2383     void target() {
2384       IntOpt opt = 0;
2385       opt = MakeOpt();
2386       opt.value(); // [[unsafe]]
2387     }
2388   )");
2389 }
2390 
2391 
2392 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftSet) {
2393   ExpectDiagnosticsFor(
2394       R"(
2395     #include "unchecked_optional_access_test.h"
2396 
2397     void target() {
2398       $ns::$optional<int> opt1 = 3;
2399       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2400 
2401       if (opt1 == opt2) {
2402         opt2.value();
2403       } else {
2404         opt2.value(); // [[unsafe]]
2405       }
2406     }
2407   )");
2408 }
2409 
2410 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightSet) {
2411   ExpectDiagnosticsFor(
2412       R"(
2413     #include "unchecked_optional_access_test.h"
2414 
2415     void target() {
2416       $ns::$optional<int> opt1 = 3;
2417       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2418 
2419       if (opt2 == opt1) {
2420         opt2.value();
2421       } else {
2422         opt2.value(); // [[unsafe]]
2423       }
2424     }
2425   )");
2426 }
2427 
2428 TEST_P(UncheckedOptionalAccessTest, EqualityCheckVerifySetAfterEq) {
2429   ExpectDiagnosticsFor(
2430       R"(
2431     #include "unchecked_optional_access_test.h"
2432 
2433     void target() {
2434       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2435       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2436 
2437       if (opt1 == opt2) {
2438         if (opt1.has_value())
2439           opt2.value();
2440         if (opt2.has_value())
2441           opt1.value();
2442       }
2443     }
2444   )");
2445 }
2446 
2447 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftUnset) {
2448   ExpectDiagnosticsFor(
2449       R"(
2450     #include "unchecked_optional_access_test.h"
2451 
2452     void target() {
2453       $ns::$optional<int> opt1 = $ns::nullopt;
2454       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2455 
2456       if (opt1 == opt2) {
2457         opt2.value(); // [[unsafe]]
2458       } else {
2459         opt2.value();
2460       }
2461     }
2462   )");
2463 }
2464 
2465 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightUnset) {
2466   ExpectDiagnosticsFor(
2467       R"(
2468     #include "unchecked_optional_access_test.h"
2469 
2470     void target() {
2471       $ns::$optional<int> opt1 = $ns::nullopt;
2472       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2473 
2474       if (opt2 == opt1) {
2475         opt2.value(); // [[unsafe]]
2476       } else {
2477         opt2.value();
2478       }
2479     }
2480   )");
2481 }
2482 
2483 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightNullopt) {
2484   ExpectDiagnosticsFor(
2485       R"(
2486     #include "unchecked_optional_access_test.h"
2487 
2488     void target() {
2489       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2490 
2491       if (opt == $ns::nullopt) {
2492         opt.value(); // [[unsafe]]
2493       } else {
2494         opt.value();
2495       }
2496     }
2497   )");
2498 }
2499 
2500 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftNullopt) {
2501   ExpectDiagnosticsFor(
2502       R"(
2503     #include "unchecked_optional_access_test.h"
2504 
2505     void target() {
2506       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2507 
2508       if ($ns::nullopt == opt) {
2509         opt.value(); // [[unsafe]]
2510       } else {
2511         opt.value();
2512       }
2513     }
2514   )");
2515 }
2516 
2517 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightValue) {
2518   ExpectDiagnosticsFor(
2519       R"(
2520     #include "unchecked_optional_access_test.h"
2521 
2522     void target() {
2523       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2524 
2525       if (opt == 3) {
2526         opt.value();
2527       } else {
2528         opt.value(); // [[unsafe]]
2529       }
2530     }
2531   )");
2532 }
2533 
2534 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftValue) {
2535   ExpectDiagnosticsFor(
2536       R"(
2537     #include "unchecked_optional_access_test.h"
2538 
2539     void target() {
2540       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2541 
2542       if (3 == opt) {
2543         opt.value();
2544       } else {
2545         opt.value(); // [[unsafe]]
2546       }
2547     }
2548   )");
2549 }
2550 
2551 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftSet) {
2552   ExpectDiagnosticsFor(
2553       R"(
2554     #include "unchecked_optional_access_test.h"
2555 
2556     void target() {
2557       $ns::$optional<int> opt1 = 3;
2558       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2559 
2560       if (opt1 != opt2) {
2561         opt2.value(); // [[unsafe]]
2562       } else {
2563         opt2.value();
2564       }
2565     }
2566   )");
2567 }
2568 
2569 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightSet) {
2570   ExpectDiagnosticsFor(
2571       R"(
2572     #include "unchecked_optional_access_test.h"
2573 
2574     void target() {
2575       $ns::$optional<int> opt1 = 3;
2576       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2577 
2578       if (opt2 != opt1) {
2579         opt2.value(); // [[unsafe]]
2580       } else {
2581         opt2.value();
2582       }
2583     }
2584   )");
2585 }
2586 
2587 TEST_P(UncheckedOptionalAccessTest, InequalityCheckVerifySetAfterEq) {
2588   ExpectDiagnosticsFor(
2589       R"(
2590     #include "unchecked_optional_access_test.h"
2591 
2592     void target() {
2593       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2594       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2595 
2596       if (opt1 != opt2) {
2597         if (opt1.has_value())
2598           opt2.value(); // [[unsafe]]
2599         if (opt2.has_value())
2600           opt1.value(); // [[unsafe]]
2601       }
2602     }
2603   )");
2604 }
2605 
2606 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftUnset) {
2607   ExpectDiagnosticsFor(
2608       R"(
2609     #include "unchecked_optional_access_test.h"
2610 
2611     void target() {
2612       $ns::$optional<int> opt1 = $ns::nullopt;
2613       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2614 
2615       if (opt1 != opt2) {
2616         opt2.value();
2617       } else {
2618         opt2.value(); // [[unsafe]]
2619       }
2620     }
2621   )");
2622 }
2623 
2624 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightUnset) {
2625   ExpectDiagnosticsFor(
2626       R"(
2627     #include "unchecked_optional_access_test.h"
2628 
2629     void target() {
2630       $ns::$optional<int> opt1 = $ns::nullopt;
2631       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2632 
2633       if (opt2 != opt1) {
2634         opt2.value();
2635       } else {
2636         opt2.value(); // [[unsafe]]
2637       }
2638     }
2639   )");
2640 }
2641 
2642 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightNullopt) {
2643   ExpectDiagnosticsFor(
2644       R"(
2645     #include "unchecked_optional_access_test.h"
2646 
2647     void target() {
2648       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2649 
2650       if (opt != $ns::nullopt) {
2651         opt.value();
2652       } else {
2653         opt.value(); // [[unsafe]]
2654       }
2655     }
2656   )");
2657 }
2658 
2659 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftNullopt) {
2660   ExpectDiagnosticsFor(
2661       R"(
2662     #include "unchecked_optional_access_test.h"
2663 
2664     void target() {
2665       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2666 
2667       if ($ns::nullopt != opt) {
2668         opt.value();
2669       } else {
2670         opt.value(); // [[unsafe]]
2671       }
2672     }
2673   )");
2674 }
2675 
2676 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightValue) {
2677   ExpectDiagnosticsFor(
2678       R"(
2679     #include "unchecked_optional_access_test.h"
2680 
2681     void target() {
2682       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2683 
2684       if (opt != 3) {
2685         opt.value(); // [[unsafe]]
2686       } else {
2687         opt.value();
2688       }
2689     }
2690   )");
2691 }
2692 
2693 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftValue) {
2694   ExpectDiagnosticsFor(
2695       R"(
2696     #include "unchecked_optional_access_test.h"
2697 
2698     void target() {
2699       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2700 
2701       if (3 != opt) {
2702         opt.value(); // [[unsafe]]
2703       } else {
2704         opt.value();
2705       }
2706     }
2707   )");
2708 }
2709 
2710 // Verifies that the model sees through aliases.
2711 TEST_P(UncheckedOptionalAccessTest, WithAlias) {
2712   ExpectDiagnosticsFor(
2713       R"(
2714     #include "unchecked_optional_access_test.h"
2715 
2716     template <typename T>
2717     using MyOptional = $ns::$optional<T>;
2718 
2719     void target(MyOptional<int> opt) {
2720       opt.value(); // [[unsafe]]
2721     }
2722   )");
2723 }
2724 
2725 TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) {
2726   // Basic test that nested values are populated.  We nest an optional because
2727   // its easy to use in a test, but the type of the nested value shouldn't
2728   // matter.
2729   ExpectDiagnosticsFor(
2730       R"(
2731     #include "unchecked_optional_access_test.h"
2732 
2733     using Foo = $ns::$optional<std::string>;
2734 
2735     void target($ns::$optional<Foo> foo) {
2736       if (foo && *foo) {
2737         foo->value();
2738       }
2739     }
2740   )");
2741 
2742   // Mutation is supported for nested values.
2743   ExpectDiagnosticsFor(
2744       R"(
2745     #include "unchecked_optional_access_test.h"
2746 
2747     using Foo = $ns::$optional<std::string>;
2748 
2749     void target($ns::$optional<Foo> foo) {
2750       if (foo && *foo) {
2751         foo->reset();
2752         foo->value(); // [[unsafe]]
2753       }
2754     }
2755   )");
2756 }
2757 
2758 // Tests that structs can be nested. We use an optional field because its easy
2759 // to use in a test, but the type of the field shouldn't matter.
2760 TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) {
2761   ExpectDiagnosticsFor(
2762       R"(
2763     #include "unchecked_optional_access_test.h"
2764 
2765     struct Foo {
2766       $ns::$optional<std::string> opt;
2767     };
2768 
2769     void target($ns::$optional<Foo> foo) {
2770       if (foo && foo->opt) {
2771         foo->opt.value();
2772       }
2773     }
2774   )");
2775 }
2776 
2777 TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) {
2778   ExpectDiagnosticsFor(
2779       R"(
2780     #include "unchecked_optional_access_test.h"
2781 
2782     using Foo = $ns::$optional<std::string>;
2783 
2784     void target($ns::$optional<Foo> foo, bool b) {
2785       if (!foo.has_value()) return;
2786       if (b) {
2787         if (!foo->has_value()) return;
2788         // We have created `foo.value()`.
2789         foo->value();
2790       } else {
2791         if (!foo->has_value()) return;
2792         // We have created `foo.value()` again, in a different environment.
2793         foo->value();
2794       }
2795       // Now we merge the two values. UncheckedOptionalAccessModel::merge() will
2796       // throw away the "value" property.
2797       foo->value();
2798     }
2799   )");
2800 }
2801 
2802 // This test is aimed at the core model, not the diagnostic. It is a regression
2803 // test against a crash when using non-trivial smart pointers, like
2804 // `std::unique_ptr`. As such, it doesn't test the access itself, which would be
2805 // ignored regardless because of `IgnoreSmartPointerDereference = true`, above.
2806 TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) {
2807   ExpectDiagnosticsFor(
2808       R"(
2809     #include "unchecked_optional_access_test.h"
2810 
2811     template <typename T>
2812     struct smart_ptr {
2813       typename std::add_lvalue_reference<T>::type operator*() &;
2814     };
2815 
2816     void target() {
2817       smart_ptr<$ns::$optional<int>> x;
2818       // Verify that this assignment does not crash.
2819       *x = 3;
2820     }
2821   )");
2822 }
2823 
2824 TEST_P(UncheckedOptionalAccessTest, CorrelatedBranches) {
2825   ExpectDiagnosticsFor(R"code(
2826     #include "unchecked_optional_access_test.h"
2827 
2828     void target(bool b, $ns::$optional<int> opt) {
2829       if (b || opt.has_value()) {
2830         if (!b) {
2831           opt.value();
2832         }
2833       }
2834     }
2835   )code");
2836 
2837   ExpectDiagnosticsFor(R"code(
2838     #include "unchecked_optional_access_test.h"
2839 
2840     void target(bool b, $ns::$optional<int> opt) {
2841       if (b && !opt.has_value()) return;
2842       if (b) {
2843         opt.value();
2844       }
2845     }
2846   )code");
2847 
2848   ExpectDiagnosticsFor(
2849       R"code(
2850     #include "unchecked_optional_access_test.h"
2851 
2852     void target(bool b, $ns::$optional<int> opt) {
2853       if (opt.has_value()) b = true;
2854       if (b) {
2855         opt.value(); // [[unsafe]]
2856       }
2857     }
2858   )code");
2859 
2860   ExpectDiagnosticsFor(R"code(
2861     #include "unchecked_optional_access_test.h"
2862 
2863     void target(bool b, $ns::$optional<int> opt) {
2864       if (b) return;
2865       if (opt.has_value()) b = true;
2866       if (b) {
2867         opt.value();
2868       }
2869     }
2870   )code");
2871 
2872   ExpectDiagnosticsFor(R"(
2873     #include "unchecked_optional_access_test.h"
2874 
2875     void target(bool b, $ns::$optional<int> opt) {
2876       if (opt.has_value() == b) {
2877         if (b) {
2878           opt.value();
2879         }
2880       }
2881     }
2882   )");
2883 
2884   ExpectDiagnosticsFor(R"(
2885     #include "unchecked_optional_access_test.h"
2886 
2887     void target(bool b, $ns::$optional<int> opt) {
2888       if (opt.has_value() != b) {
2889         if (!b) {
2890           opt.value();
2891         }
2892       }
2893     }
2894   )");
2895 
2896   ExpectDiagnosticsFor(R"(
2897     #include "unchecked_optional_access_test.h"
2898 
2899     void target(bool b) {
2900       $ns::$optional<int> opt1 = $ns::nullopt;
2901       $ns::$optional<int> opt2;
2902       if (b) {
2903         opt2 = $ns::nullopt;
2904       } else {
2905         opt2 = $ns::nullopt;
2906       }
2907       if (opt2.has_value()) {
2908         opt1.value();
2909       }
2910     }
2911   )");
2912 }
2913 
2914 TEST_P(UncheckedOptionalAccessTest, JoinDistinctValues) {
2915   ExpectDiagnosticsFor(
2916       R"code(
2917     #include "unchecked_optional_access_test.h"
2918 
2919     void target(bool b) {
2920       $ns::$optional<int> opt;
2921       if (b) {
2922         opt = Make<$ns::$optional<int>>();
2923       } else {
2924         opt = Make<$ns::$optional<int>>();
2925       }
2926       if (opt.has_value()) {
2927         opt.value();
2928       } else {
2929         opt.value(); // [[unsafe]]
2930       }
2931     }
2932   )code");
2933 
2934   ExpectDiagnosticsFor(R"code(
2935     #include "unchecked_optional_access_test.h"
2936 
2937     void target(bool b) {
2938       $ns::$optional<int> opt;
2939       if (b) {
2940         opt = Make<$ns::$optional<int>>();
2941         if (!opt.has_value()) return;
2942       } else {
2943         opt = Make<$ns::$optional<int>>();
2944         if (!opt.has_value()) return;
2945       }
2946       opt.value();
2947     }
2948   )code");
2949 
2950   ExpectDiagnosticsFor(
2951       R"code(
2952     #include "unchecked_optional_access_test.h"
2953 
2954     void target(bool b) {
2955       $ns::$optional<int> opt;
2956       if (b) {
2957         opt = Make<$ns::$optional<int>>();
2958         if (!opt.has_value()) return;
2959       } else {
2960         opt = Make<$ns::$optional<int>>();
2961       }
2962       opt.value(); // [[unsafe]]
2963     }
2964   )code");
2965 
2966   ExpectDiagnosticsFor(
2967       R"code(
2968     #include "unchecked_optional_access_test.h"
2969 
2970     void target(bool b) {
2971       $ns::$optional<int> opt;
2972       if (b) {
2973         opt = 1;
2974       } else {
2975         opt = 2;
2976       }
2977       opt.value();
2978     }
2979   )code");
2980 
2981   ExpectDiagnosticsFor(
2982       R"code(
2983     #include "unchecked_optional_access_test.h"
2984 
2985     void target(bool b) {
2986       $ns::$optional<int> opt;
2987       if (b) {
2988         opt = 1;
2989       } else {
2990         opt = Make<$ns::$optional<int>>();
2991       }
2992       opt.value(); // [[unsafe]]
2993     }
2994   )code");
2995 }
2996 
2997 TEST_P(UncheckedOptionalAccessTest, AccessValueInLoop) {
2998   ExpectDiagnosticsFor(R"(
2999     #include "unchecked_optional_access_test.h"
3000 
3001     void target() {
3002       $ns::$optional<int> opt = 3;
3003       while (Make<bool>()) {
3004         opt.value();
3005       }
3006     }
3007   )");
3008 }
3009 
3010 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopWithCheckSafe) {
3011   ExpectDiagnosticsFor(R"(
3012     #include "unchecked_optional_access_test.h"
3013 
3014     void target() {
3015       $ns::$optional<int> opt = 3;
3016       while (Make<bool>()) {
3017         opt.value();
3018 
3019         opt = Make<$ns::$optional<int>>();
3020         if (!opt.has_value()) return;
3021       }
3022     }
3023   )");
3024 }
3025 
3026 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopNoCheckUnsafe) {
3027   ExpectDiagnosticsFor(
3028       R"(
3029     #include "unchecked_optional_access_test.h"
3030 
3031     void target() {
3032       $ns::$optional<int> opt = 3;
3033       while (Make<bool>()) {
3034         opt.value(); // [[unsafe]]
3035 
3036         opt = Make<$ns::$optional<int>>();
3037       }
3038     }
3039   )");
3040 }
3041 
3042 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnsetUnsafe) {
3043   ExpectDiagnosticsFor(
3044       R"(
3045     #include "unchecked_optional_access_test.h"
3046 
3047     void target() {
3048       $ns::$optional<int> opt = 3;
3049       while (Make<bool>())
3050         opt = $ns::nullopt;
3051       $ns::$optional<int> opt2 = $ns::nullopt;
3052       if (opt.has_value())
3053         opt2 = $ns::$optional<int>(3);
3054       opt2.value(); // [[unsafe]]
3055     }
3056   )");
3057 }
3058 
3059 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToSetUnsafe) {
3060   ExpectDiagnosticsFor(
3061       R"(
3062     #include "unchecked_optional_access_test.h"
3063 
3064     void target() {
3065       $ns::$optional<int> opt = $ns::nullopt;
3066       while (Make<bool>())
3067         opt = $ns::$optional<int>(3);
3068       $ns::$optional<int> opt2 = $ns::nullopt;
3069       if (!opt.has_value())
3070         opt2 = $ns::$optional<int>(3);
3071       opt2.value(); // [[unsafe]]
3072     }
3073   )");
3074 }
3075 
3076 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnknownUnsafe) {
3077   ExpectDiagnosticsFor(
3078       R"(
3079     #include "unchecked_optional_access_test.h"
3080 
3081     void target() {
3082       $ns::$optional<int> opt = $ns::nullopt;
3083       while (Make<bool>())
3084         opt = Make<$ns::$optional<int>>();
3085       $ns::$optional<int> opt2 = $ns::nullopt;
3086       if (!opt.has_value())
3087         opt2 = $ns::$optional<int>(3);
3088       opt2.value(); // [[unsafe]]
3089     }
3090   )");
3091 }
3092 
3093 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopBadConditionUnsafe) {
3094   ExpectDiagnosticsFor(
3095       R"(
3096     #include "unchecked_optional_access_test.h"
3097 
3098     void target() {
3099       $ns::$optional<int> opt = 3;
3100       while (Make<bool>()) {
3101         opt.value(); // [[unsafe]]
3102 
3103         opt = Make<$ns::$optional<int>>();
3104         if (!opt.has_value()) continue;
3105       }
3106     }
3107   )");
3108 }
3109 
3110 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromStruct) {
3111   ExpectDiagnosticsFor(R"(
3112     #include "unchecked_optional_access_test.h"
3113 
3114     struct kv { $ns::$optional<int> opt; int x; };
3115     int target() {
3116       auto [contents, x] = Make<kv>();
3117       return contents ? *contents : x;
3118     }
3119   )");
3120 
3121   ExpectDiagnosticsFor(R"(
3122     #include "unchecked_optional_access_test.h"
3123 
3124     template <typename T1, typename T2>
3125     struct pair { T1 fst;  T2 snd; };
3126     int target() {
3127       auto [contents, x] = Make<pair<$ns::$optional<int>, int>>();
3128       return contents ? *contents : x;
3129     }
3130   )");
3131 }
3132 
3133 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromTupleLikeType) {
3134   ExpectDiagnosticsFor(R"(
3135     #include "unchecked_optional_access_test.h"
3136 
3137     namespace std {
3138     template <class> struct tuple_size;
3139     template <size_t, class> struct tuple_element;
3140     template <class...> class tuple;
3141 
3142     template <class... T>
3143     struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {};
3144 
3145     template <size_t I, class... T>
3146     struct tuple_element<I, tuple<T...>> {
3147       using type =  __type_pack_element<I, T...>;
3148     };
3149 
3150     template <class...> class tuple {};
3151     template <size_t I, class... T>
3152     typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
3153     } // namespace std
3154 
3155     std::tuple<$ns::$optional<const char *>, int> get_opt();
3156     void target() {
3157       auto [content, ck] = get_opt();
3158       content ? *content : "";
3159     }
3160   )");
3161 }
3162 
3163 TEST_P(UncheckedOptionalAccessTest, CtorInitializerNullopt) {
3164   using namespace ast_matchers;
3165   ExpectDiagnosticsFor(
3166       R"(
3167     #include "unchecked_optional_access_test.h"
3168 
3169     struct Target {
3170       Target(): opt($ns::nullopt) {
3171         opt.value(); // [[unsafe]]
3172       }
3173       $ns::$optional<int> opt;
3174     };
3175   )",
3176       cxxConstructorDecl(ofClass(hasName("Target"))));
3177 }
3178 
3179 TEST_P(UncheckedOptionalAccessTest, CtorInitializerValue) {
3180   using namespace ast_matchers;
3181   ExpectDiagnosticsFor(
3182       R"(
3183     #include "unchecked_optional_access_test.h"
3184 
3185     struct Target {
3186       Target(): opt(3) {
3187         opt.value();
3188       }
3189       $ns::$optional<int> opt;
3190     };
3191   )",
3192       cxxConstructorDecl(ofClass(hasName("Target"))));
3193 }
3194 
3195 // This is regression test, it shouldn't crash.
3196 TEST_P(UncheckedOptionalAccessTest, Bitfield) {
3197   using namespace ast_matchers;
3198   ExpectDiagnosticsFor(
3199       R"(
3200     #include "unchecked_optional_access_test.h"
3201     struct Dst {
3202       unsigned int n : 1;
3203     };
3204     void target() {
3205       $ns::$optional<bool> v;
3206       Dst d;
3207       if (v.has_value())
3208         d.n = v.value();
3209     }
3210   )");
3211 }
3212 // FIXME: Add support for:
3213 // - constructors (copy, move)
3214 // - assignment operators (default, copy, move)
3215 // - invalidation (passing optional by non-const reference/pointer)
3216