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