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