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