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