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