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