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