xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (revision 14bc11a651971bbbdf96565898be2c94fa2b1cf5)
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   void ExpectDiagnosticsForLambda(std::string SourceCode) {
1284     ExpectDiagnosticsFor(
1285         SourceCode, ast_matchers::hasDeclContext(
1286                         ast_matchers::cxxRecordDecl(ast_matchers::isLambda())));
1287   }
1288 
1289   template <typename FuncDeclMatcher>
1290   void ExpectDiagnosticsFor(std::string SourceCode,
1291                             FuncDeclMatcher FuncMatcher) {
1292     ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName);
1293     ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName);
1294 
1295     std::vector<std::pair<std::string, std::string>> Headers;
1296     Headers.emplace_back("cstddef.h", CSDtdDefHeader);
1297     Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader);
1298     Headers.emplace_back("std_string.h", StdStringHeader);
1299     Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader);
1300     Headers.emplace_back("std_utility.h", StdUtilityHeader);
1301     Headers.emplace_back("std_optional.h", StdOptionalHeader);
1302     Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader);
1303     Headers.emplace_back("absl_optional.h", AbslOptionalHeader);
1304     Headers.emplace_back("base_optional.h", BaseOptionalHeader);
1305     Headers.emplace_back("unchecked_optional_access_test.h", R"(
1306       #include "absl_optional.h"
1307       #include "base_optional.h"
1308       #include "std_initializer_list.h"
1309       #include "std_optional.h"
1310       #include "std_string.h"
1311       #include "std_utility.h"
1312 
1313       template <typename T>
1314       T Make();
1315     )");
1316     UncheckedOptionalAccessModelOptions Options{
1317         /*IgnoreSmartPointerDereference=*/true};
1318     std::vector<SourceLocation> Diagnostics;
1319     llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
1320         AnalysisInputs<UncheckedOptionalAccessModel>(
1321             SourceCode, std::move(FuncMatcher),
1322             [](ASTContext &Ctx, Environment &) {
1323               return UncheckedOptionalAccessModel(Ctx);
1324             })
1325             .withPostVisitCFG(
1326                 [&Diagnostics,
1327                  Diagnoser = UncheckedOptionalAccessDiagnoser(Options)](
1328                     ASTContext &Ctx, const CFGElement &Elt,
1329                     const TransferStateForDiagnostics<NoopLattice>
1330                         &State) mutable {
1331                   auto EltDiagnostics = Diagnoser(Elt, Ctx, State);
1332                   llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
1333                 })
1334             .withASTBuildArgs(
1335                 {"-fsyntax-only", "-std=c++17", "-Wno-undefined-inline"})
1336             .withASTBuildVirtualMappedFiles(
1337                 tooling::FileContentMappings(Headers.begin(), Headers.end())),
1338         /*VerifyResults=*/[&Diagnostics](
1339                               const llvm::DenseMap<unsigned, std::string>
1340                                   &Annotations,
1341                               const AnalysisOutputs &AO) {
1342           llvm::DenseSet<unsigned> AnnotationLines;
1343           for (const auto &[Line, _] : Annotations) {
1344             AnnotationLines.insert(Line);
1345           }
1346           auto &SrcMgr = AO.ASTCtx.getSourceManager();
1347           llvm::DenseSet<unsigned> DiagnosticLines;
1348           for (SourceLocation &Loc : Diagnostics) {
1349             unsigned Line = SrcMgr.getPresumedLineNumber(Loc);
1350             DiagnosticLines.insert(Line);
1351             if (!AnnotationLines.contains(Line)) {
1352               IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
1353                   new DiagnosticOptions());
1354               TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
1355                                 DiagOpts.get());
1356               TD.emitDiagnostic(
1357                   FullSourceLoc(Loc, SrcMgr), DiagnosticsEngine::Error,
1358                   "unexpected diagnostic", std::nullopt, std::nullopt);
1359             }
1360           }
1361 
1362           EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines));
1363         });
1364     if (Error)
1365       FAIL() << llvm::toString(std::move(Error));
1366   }
1367 };
1368 
1369 INSTANTIATE_TEST_SUITE_P(
1370     UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
1371     ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
1372                       OptionalTypeIdentifier{"absl", "optional"},
1373                       OptionalTypeIdentifier{"base", "Optional"}),
1374     [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
1375       return Info.param.NamespaceName;
1376     });
1377 
1378 // Verifies that similarly-named types are ignored.
1379 TEST_P(UncheckedOptionalAccessTest, NonTrackedOptionalType) {
1380   ExpectDiagnosticsFor(
1381       R"(
1382     namespace other {
1383     namespace $ns {
1384     template <typename T>
1385     struct $optional {
1386       T value();
1387     };
1388     }
1389 
1390     void target($ns::$optional<int> opt) {
1391       opt.value();
1392     }
1393     }
1394   )");
1395 }
1396 
1397 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
1398   ExpectDiagnosticsFor(R"(
1399     void target() {
1400       (void)0;
1401     }
1402   )");
1403 }
1404 
1405 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
1406   ExpectDiagnosticsFor(
1407       R"(
1408     #include "unchecked_optional_access_test.h"
1409 
1410     void target($ns::$optional<int> opt) {
1411       opt.value(); // [[unsafe]]
1412     }
1413   )");
1414 
1415   ExpectDiagnosticsFor(
1416       R"(
1417     #include "unchecked_optional_access_test.h"
1418 
1419     void target($ns::$optional<int> opt) {
1420       std::move(opt).value(); // [[unsafe]]
1421     }
1422   )");
1423 }
1424 
1425 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
1426   ExpectDiagnosticsFor(
1427       R"(
1428     #include "unchecked_optional_access_test.h"
1429 
1430     void target($ns::$optional<int> opt) {
1431       *opt; // [[unsafe]]
1432     }
1433   )");
1434 
1435   ExpectDiagnosticsFor(
1436       R"(
1437     #include "unchecked_optional_access_test.h"
1438 
1439     void target($ns::$optional<int> opt) {
1440       *std::move(opt); // [[unsafe]]
1441     }
1442   )");
1443 }
1444 
1445 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
1446   ExpectDiagnosticsFor(
1447       R"(
1448     #include "unchecked_optional_access_test.h"
1449 
1450     struct Foo {
1451       void foo();
1452     };
1453 
1454     void target($ns::$optional<Foo> opt) {
1455       opt->foo(); // [[unsafe]]
1456     }
1457   )");
1458 
1459   ExpectDiagnosticsFor(
1460       R"(
1461     #include "unchecked_optional_access_test.h"
1462 
1463     struct Foo {
1464       void foo();
1465     };
1466 
1467     void target($ns::$optional<Foo> opt) {
1468       std::move(opt)->foo(); // [[unsafe]]
1469     }
1470   )");
1471 }
1472 
1473 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
1474   ExpectDiagnosticsFor(R"(
1475     #include "unchecked_optional_access_test.h"
1476 
1477     void target($ns::$optional<int> opt) {
1478       if (opt.has_value()) {
1479         opt.value();
1480       }
1481     }
1482   )");
1483 }
1484 
1485 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
1486   ExpectDiagnosticsFor(R"(
1487     #include "unchecked_optional_access_test.h"
1488 
1489     void target($ns::$optional<int> opt) {
1490       if (opt) {
1491         opt.value();
1492       }
1493     }
1494   )");
1495 }
1496 
1497 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
1498   ExpectDiagnosticsFor(
1499       R"(
1500     #include "unchecked_optional_access_test.h"
1501 
1502     void target() {
1503       Make<$ns::$optional<int>>().value(); // [[unsafe]]
1504       (void)0;
1505     }
1506   )");
1507 
1508   ExpectDiagnosticsFor(
1509       R"(
1510     #include "unchecked_optional_access_test.h"
1511 
1512     void target($ns::$optional<int> opt) {
1513       std::move(opt).value(); // [[unsafe]]
1514     }
1515   )");
1516 }
1517 
1518 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
1519   ExpectDiagnosticsFor(
1520       R"(
1521     #include "unchecked_optional_access_test.h"
1522 
1523     void target() {
1524       $ns::$optional<int> opt;
1525       opt.value(); // [[unsafe]]
1526     }
1527   )");
1528 }
1529 
1530 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
1531   ExpectDiagnosticsFor(
1532       R"(
1533     #include "unchecked_optional_access_test.h"
1534 
1535     void target() {
1536       $ns::$optional<int> opt($ns::nullopt);
1537       opt.value(); // [[unsafe]]
1538     }
1539   )");
1540 }
1541 
1542 TEST_P(UncheckedOptionalAccessTest, NulloptConstructorWithSugaredType) {
1543   ExpectDiagnosticsFor(
1544       R"(
1545     #include "unchecked_optional_access_test.h"
1546     template <typename T>
1547     using wrapper = T;
1548 
1549     template <typename T>
1550     wrapper<T> wrap(T);
1551 
1552     void target() {
1553       $ns::$optional<int> opt(wrap($ns::nullopt));
1554       opt.value(); // [[unsafe]]
1555     }
1556   )");
1557 }
1558 
1559 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
1560   ExpectDiagnosticsFor(R"(
1561     #include "unchecked_optional_access_test.h"
1562 
1563     void target() {
1564       $ns::$optional<int> opt($ns::in_place, 3);
1565       opt.value();
1566     }
1567   )");
1568 
1569   ExpectDiagnosticsFor(R"(
1570     #include "unchecked_optional_access_test.h"
1571 
1572     struct Foo {};
1573 
1574     void target() {
1575       $ns::$optional<Foo> opt($ns::in_place);
1576       opt.value();
1577     }
1578   )");
1579 
1580   ExpectDiagnosticsFor(R"(
1581     #include "unchecked_optional_access_test.h"
1582 
1583     struct Foo {
1584       explicit Foo(int, bool);
1585     };
1586 
1587     void target() {
1588       $ns::$optional<Foo> opt($ns::in_place, 3, false);
1589       opt.value();
1590     }
1591   )");
1592 
1593   ExpectDiagnosticsFor(R"(
1594     #include "unchecked_optional_access_test.h"
1595 
1596     struct Foo {
1597       explicit Foo(std::initializer_list<int>);
1598     };
1599 
1600     void target() {
1601       $ns::$optional<Foo> opt($ns::in_place, {3});
1602       opt.value();
1603     }
1604   )");
1605 }
1606 
1607 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
1608   ExpectDiagnosticsFor(R"(
1609     #include "unchecked_optional_access_test.h"
1610 
1611     void target() {
1612       $ns::$optional<int> opt(21);
1613       opt.value();
1614     }
1615   )");
1616 
1617   ExpectDiagnosticsFor(R"(
1618     #include "unchecked_optional_access_test.h"
1619 
1620     void target() {
1621       $ns::$optional<int> opt = $ns::$optional<int>(21);
1622       opt.value();
1623     }
1624   )");
1625   ExpectDiagnosticsFor(R"(
1626     #include "unchecked_optional_access_test.h"
1627 
1628     void target() {
1629       $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1630       opt.value();
1631     }
1632   )");
1633 
1634   ExpectDiagnosticsFor(R"(
1635     #include "unchecked_optional_access_test.h"
1636 
1637     struct MyString {
1638       MyString(const char*);
1639     };
1640 
1641     void target() {
1642       $ns::$optional<MyString> opt("foo");
1643       opt.value();
1644     }
1645   )");
1646 
1647   ExpectDiagnosticsFor(R"(
1648     #include "unchecked_optional_access_test.h"
1649 
1650     struct Foo {};
1651 
1652     struct Bar {
1653       Bar(const Foo&);
1654     };
1655 
1656     void target() {
1657       $ns::$optional<Bar> opt(Make<Foo>());
1658       opt.value();
1659     }
1660   )");
1661 
1662   ExpectDiagnosticsFor(R"(
1663     #include "unchecked_optional_access_test.h"
1664 
1665     struct Foo {
1666       explicit Foo(int);
1667     };
1668 
1669     void target() {
1670       $ns::$optional<Foo> opt(3);
1671       opt.value();
1672     }
1673   )");
1674 }
1675 
1676 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
1677   ExpectDiagnosticsFor(
1678       R"(
1679     #include "unchecked_optional_access_test.h"
1680 
1681     struct Foo {};
1682 
1683     struct Bar {
1684       Bar(const Foo&);
1685     };
1686 
1687     void target() {
1688       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1689       opt.value(); // [[unsafe]]
1690     }
1691   )");
1692 
1693   ExpectDiagnosticsFor(
1694       R"(
1695     #include "unchecked_optional_access_test.h"
1696 
1697     struct Foo {};
1698 
1699     struct Bar {
1700       explicit Bar(const Foo&);
1701     };
1702 
1703     void target() {
1704       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1705       opt.value(); // [[unsafe]]
1706     }
1707   )");
1708 
1709   ExpectDiagnosticsFor(
1710       R"(
1711     #include "unchecked_optional_access_test.h"
1712 
1713     struct Foo {};
1714 
1715     struct Bar {
1716       Bar(const Foo&);
1717     };
1718 
1719     void target() {
1720       $ns::$optional<Foo> opt1 = $ns::nullopt;
1721       $ns::$optional<Bar> opt2(opt1);
1722       opt2.value(); // [[unsafe]]
1723     }
1724   )");
1725 
1726   ExpectDiagnosticsFor(R"(
1727     #include "unchecked_optional_access_test.h"
1728 
1729     struct Foo {};
1730 
1731     struct Bar {
1732       Bar(const Foo&);
1733     };
1734 
1735     void target() {
1736       $ns::$optional<Foo> opt1(Make<Foo>());
1737       $ns::$optional<Bar> opt2(opt1);
1738       opt2.value();
1739     }
1740   )");
1741 
1742   ExpectDiagnosticsFor(R"(
1743     #include "unchecked_optional_access_test.h"
1744 
1745     struct Foo {};
1746 
1747     struct Bar {
1748       explicit Bar(const Foo&);
1749     };
1750 
1751     void target() {
1752       $ns::$optional<Foo> opt1(Make<Foo>());
1753       $ns::$optional<Bar> opt2(opt1);
1754       opt2.value();
1755     }
1756   )");
1757 }
1758 
1759 TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
1760   ExpectDiagnosticsFor(R"(
1761     #include "unchecked_optional_access_test.h"
1762 
1763     void target() {
1764       $ns::$optional<int> opt = $ns::make_optional(0);
1765       opt.value();
1766     }
1767   )");
1768 
1769   ExpectDiagnosticsFor(R"(
1770     #include "unchecked_optional_access_test.h"
1771 
1772     struct Foo {
1773       Foo(int, int);
1774     };
1775 
1776     void target() {
1777       $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1778       opt.value();
1779     }
1780   )");
1781 
1782   ExpectDiagnosticsFor(R"(
1783     #include "unchecked_optional_access_test.h"
1784 
1785     struct Foo {
1786       constexpr Foo(std::initializer_list<char>);
1787     };
1788 
1789     void target() {
1790       char a = 'a';
1791       $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1792       opt.value();
1793     }
1794   )");
1795 }
1796 
1797 TEST_P(UncheckedOptionalAccessTest, ValueOr) {
1798   ExpectDiagnosticsFor(R"(
1799     #include "unchecked_optional_access_test.h"
1800 
1801     void target() {
1802       $ns::$optional<int> opt;
1803       opt.value_or(0);
1804       (void)0;
1805     }
1806   )");
1807 }
1808 
1809 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointers) {
1810   ExpectDiagnosticsFor(
1811       R"code(
1812     #include "unchecked_optional_access_test.h"
1813 
1814     void target($ns::$optional<int*> opt) {
1815       if (opt.value_or(nullptr) != nullptr) {
1816         opt.value();
1817       } else {
1818         opt.value(); // [[unsafe]]
1819       }
1820     }
1821   )code");
1822 }
1823 
1824 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonIntegers) {
1825   ExpectDiagnosticsFor(
1826       R"code(
1827     #include "unchecked_optional_access_test.h"
1828 
1829     void target($ns::$optional<int> opt) {
1830       if (opt.value_or(0) != 0) {
1831         opt.value();
1832       } else {
1833         opt.value(); // [[unsafe]]
1834       }
1835     }
1836   )code");
1837 }
1838 
1839 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonStrings) {
1840   ExpectDiagnosticsFor(
1841       R"code(
1842     #include "unchecked_optional_access_test.h"
1843 
1844     void target($ns::$optional<std::string> opt) {
1845       if (!opt.value_or("").empty()) {
1846         opt.value();
1847       } else {
1848         opt.value(); // [[unsafe]]
1849       }
1850     }
1851   )code");
1852 
1853   ExpectDiagnosticsFor(
1854       R"code(
1855     #include "unchecked_optional_access_test.h"
1856 
1857     void target($ns::$optional<std::string> opt) {
1858       if (opt.value_or("") != "") {
1859         opt.value();
1860       } else {
1861         opt.value(); // [[unsafe]]
1862       }
1863     }
1864   )code");
1865 }
1866 
1867 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointerToOptional) {
1868   // FIXME: make `opt` a parameter directly, once we ensure that all `optional`
1869   // values have a `has_value` property.
1870   ExpectDiagnosticsFor(
1871       R"code(
1872     #include "unchecked_optional_access_test.h"
1873 
1874     void target($ns::$optional<int> p) {
1875       $ns::$optional<int> *opt = &p;
1876       if (opt->value_or(0) != 0) {
1877         opt->value();
1878       } else {
1879         opt->value(); // [[unsafe]]
1880       }
1881     }
1882   )code");
1883 }
1884 
1885 TEST_P(UncheckedOptionalAccessTest, Emplace) {
1886   ExpectDiagnosticsFor(R"(
1887     #include "unchecked_optional_access_test.h"
1888 
1889     void target() {
1890       $ns::$optional<int> opt;
1891       opt.emplace(0);
1892       opt.value();
1893     }
1894   )");
1895 
1896   ExpectDiagnosticsFor(R"(
1897     #include "unchecked_optional_access_test.h"
1898 
1899     void target($ns::$optional<int> *opt) {
1900       opt->emplace(0);
1901       opt->value();
1902     }
1903   )");
1904 
1905   // FIXME: Add tests that call `emplace` in conditional branches:
1906   //  ExpectDiagnosticsFor(
1907   //      R"(
1908   //    #include "unchecked_optional_access_test.h"
1909   //
1910   //    void target($ns::$optional<int> opt, bool b) {
1911   //      if (b) {
1912   //        opt.emplace(0);
1913   //      }
1914   //      if (b) {
1915   //        opt.value();
1916   //      } else {
1917   //        opt.value(); // [[unsafe]]
1918   //      }
1919   //    }
1920   //  )");
1921 }
1922 
1923 TEST_P(UncheckedOptionalAccessTest, Reset) {
1924   ExpectDiagnosticsFor(
1925       R"(
1926     #include "unchecked_optional_access_test.h"
1927 
1928     void target() {
1929       $ns::$optional<int> opt = $ns::make_optional(0);
1930       opt.reset();
1931       opt.value(); // [[unsafe]]
1932     }
1933   )");
1934 
1935   ExpectDiagnosticsFor(
1936       R"(
1937     #include "unchecked_optional_access_test.h"
1938 
1939     void target($ns::$optional<int> &opt) {
1940       if (opt.has_value()) {
1941         opt.reset();
1942         opt.value(); // [[unsafe]]
1943       }
1944     }
1945   )");
1946 
1947   // FIXME: Add tests that call `reset` in conditional branches:
1948   //  ExpectDiagnosticsFor(
1949   //      R"(
1950   //    #include "unchecked_optional_access_test.h"
1951   //
1952   //    void target(bool b) {
1953   //      $ns::$optional<int> opt = $ns::make_optional(0);
1954   //      if (b) {
1955   //        opt.reset();
1956   //      }
1957   //      if (b) {
1958   //        opt.value(); // [[unsafe]]
1959   //      } else {
1960   //        opt.value();
1961   //      }
1962   //    }
1963   //  )");
1964 }
1965 
1966 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) {
1967   ExpectDiagnosticsFor(R"(
1968     #include "unchecked_optional_access_test.h"
1969 
1970     struct Foo {};
1971 
1972     void target() {
1973       $ns::$optional<Foo> opt;
1974       opt = Foo();
1975       opt.value();
1976     }
1977   )");
1978 
1979   ExpectDiagnosticsFor(R"(
1980     #include "unchecked_optional_access_test.h"
1981 
1982     struct Foo {};
1983 
1984     void target() {
1985       $ns::$optional<Foo> opt;
1986       (opt = Foo()).value();
1987       (void)0;
1988     }
1989   )");
1990 
1991   ExpectDiagnosticsFor(R"(
1992     #include "unchecked_optional_access_test.h"
1993 
1994     struct MyString {
1995       MyString(const char*);
1996     };
1997 
1998     void target() {
1999       $ns::$optional<MyString> opt;
2000       opt = "foo";
2001       opt.value();
2002     }
2003   )");
2004 
2005   ExpectDiagnosticsFor(R"(
2006     #include "unchecked_optional_access_test.h"
2007 
2008     struct MyString {
2009       MyString(const char*);
2010     };
2011 
2012     void target() {
2013       $ns::$optional<MyString> opt;
2014       (opt = "foo").value();
2015     }
2016   )");
2017 }
2018 
2019 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) {
2020   ExpectDiagnosticsFor(
2021       R"(
2022     #include "unchecked_optional_access_test.h"
2023 
2024     struct Foo {};
2025 
2026     struct Bar {
2027       Bar(const Foo&);
2028     };
2029 
2030     void target() {
2031       $ns::$optional<Foo> opt1 = Foo();
2032       $ns::$optional<Bar> opt2;
2033       opt2 = opt1;
2034       opt2.value();
2035     }
2036   )");
2037 
2038   ExpectDiagnosticsFor(
2039       R"(
2040     #include "unchecked_optional_access_test.h"
2041 
2042     struct Foo {};
2043 
2044     struct Bar {
2045       Bar(const Foo&);
2046     };
2047 
2048     void target() {
2049       $ns::$optional<Foo> opt1;
2050       $ns::$optional<Bar> opt2;
2051       if (opt2.has_value()) {
2052         opt2 = opt1;
2053         opt2.value(); // [[unsafe]]
2054       }
2055     }
2056   )");
2057 
2058   ExpectDiagnosticsFor(
2059       R"(
2060     #include "unchecked_optional_access_test.h"
2061 
2062     struct Foo {};
2063 
2064     struct Bar {
2065       Bar(const Foo&);
2066     };
2067 
2068     void target() {
2069       $ns::$optional<Foo> opt1 = Foo();
2070       $ns::$optional<Bar> opt2;
2071       (opt2 = opt1).value();
2072       (void)0;
2073     }
2074   )");
2075 }
2076 
2077 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) {
2078   ExpectDiagnosticsFor(
2079       R"(
2080     #include "unchecked_optional_access_test.h"
2081 
2082     void target() {
2083       $ns::$optional<int> opt = 3;
2084       opt = $ns::nullopt;
2085       opt.value(); // [[unsafe]]
2086     }
2087   )");
2088 
2089   ExpectDiagnosticsFor(
2090       R"(
2091     #include "unchecked_optional_access_test.h"
2092 
2093     void target() {
2094       $ns::$optional<int> opt = 3;
2095       (opt = $ns::nullopt).value(); // [[unsafe]]
2096     }
2097   )");
2098 }
2099 
2100 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) {
2101   ExpectDiagnosticsFor(
2102       R"(
2103     #include "unchecked_optional_access_test.h"
2104 
2105     void target() {
2106       $ns::$optional<int> opt1 = $ns::nullopt;
2107       $ns::$optional<int> opt2 = 3;
2108 
2109       opt1.swap(opt2);
2110 
2111       opt1.value();
2112 
2113       opt2.value(); // [[unsafe]]
2114     }
2115   )");
2116 
2117   ExpectDiagnosticsFor(
2118       R"(
2119     #include "unchecked_optional_access_test.h"
2120 
2121     void target() {
2122       $ns::$optional<int> opt1 = $ns::nullopt;
2123       $ns::$optional<int> opt2 = 3;
2124 
2125       opt2.swap(opt1);
2126 
2127       opt1.value();
2128 
2129       opt2.value(); // [[unsafe]]
2130     }
2131   )");
2132 }
2133 
2134 TEST_P(UncheckedOptionalAccessTest, OptionalReturnedFromFuntionCall) {
2135   ExpectDiagnosticsFor(
2136       R"(
2137     #include "unchecked_optional_access_test.h"
2138 
2139     struct S {
2140       $ns::$optional<float> x;
2141     } s;
2142     S getOptional() {
2143       return s;
2144     }
2145 
2146     void target() {
2147       getOptional().x = 0;
2148     }
2149   )");
2150 }
2151 
2152 TEST_P(UncheckedOptionalAccessTest, StdSwap) {
2153   ExpectDiagnosticsFor(
2154       R"(
2155     #include "unchecked_optional_access_test.h"
2156 
2157     void target() {
2158       $ns::$optional<int> opt1 = $ns::nullopt;
2159       $ns::$optional<int> opt2 = 3;
2160 
2161       std::swap(opt1, opt2);
2162 
2163       opt1.value();
2164 
2165       opt2.value(); // [[unsafe]]
2166     }
2167   )");
2168 
2169   ExpectDiagnosticsFor(
2170       R"(
2171     #include "unchecked_optional_access_test.h"
2172 
2173     void target() {
2174       $ns::$optional<int> opt1 = $ns::nullopt;
2175       $ns::$optional<int> opt2 = 3;
2176 
2177       std::swap(opt2, opt1);
2178 
2179       opt1.value();
2180 
2181       opt2.value(); // [[unsafe]]
2182     }
2183   )");
2184 }
2185 
2186 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocLeft) {
2187   ExpectDiagnosticsFor(
2188       R"(
2189     #include "unchecked_optional_access_test.h"
2190 
2191     struct L { $ns::$optional<int> hd; L* tl; };
2192 
2193     void target() {
2194       $ns::$optional<int> foo = 3;
2195       L bar;
2196 
2197       // Any `tl` beyond the first is not modeled.
2198       bar.tl->tl->hd.swap(foo);
2199 
2200       bar.tl->tl->hd.value(); // [[unsafe]]
2201       foo.value(); // [[unsafe]]
2202     }
2203   )");
2204 }
2205 
2206 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocRight) {
2207   ExpectDiagnosticsFor(
2208       R"(
2209     #include "unchecked_optional_access_test.h"
2210 
2211     struct L { $ns::$optional<int> hd; L* tl; };
2212 
2213     void target() {
2214       $ns::$optional<int> foo = 3;
2215       L bar;
2216 
2217       // Any `tl` beyond the first is not modeled.
2218       foo.swap(bar.tl->tl->hd);
2219 
2220       bar.tl->tl->hd.value(); // [[unsafe]]
2221       foo.value(); // [[unsafe]]
2222     }
2223   )");
2224 }
2225 
2226 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftSet) {
2227   ExpectDiagnosticsFor(
2228       R"(
2229     #include "unchecked_optional_access_test.h"
2230 
2231     struct S { int x; };
2232     struct A { $ns::$optional<S> late; };
2233     struct B { A f3; };
2234     struct C { B f2; };
2235     struct D { C f1; };
2236 
2237     void target() {
2238       $ns::$optional<S> foo = S{3};
2239       D bar;
2240 
2241       bar.f1.f2.f3.late.swap(foo);
2242 
2243       bar.f1.f2.f3.late.value();
2244       foo.value(); // [[unsafe]]
2245     }
2246   )");
2247 }
2248 
2249 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftUnset) {
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;
2262       D bar;
2263 
2264       bar.f1.f2.f3.late.swap(foo);
2265 
2266       bar.f1.f2.f3.late.value(); // [[unsafe]]
2267       foo.value(); // [[unsafe]]
2268     }
2269   )");
2270 }
2271 
2272 // fixme: use recursion instead of depth.
2273 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightSet) {
2274   ExpectDiagnosticsFor(
2275       R"(
2276     #include "unchecked_optional_access_test.h"
2277 
2278     struct S { int x; };
2279     struct A { $ns::$optional<S> late; };
2280     struct B { A f3; };
2281     struct C { B f2; };
2282     struct D { C f1; };
2283 
2284     void target() {
2285       $ns::$optional<S> foo = S{3};
2286       D bar;
2287 
2288       foo.swap(bar.f1.f2.f3.late);
2289 
2290       bar.f1.f2.f3.late.value();
2291       foo.value(); // [[unsafe]]
2292     }
2293   )");
2294 }
2295 
2296 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightUnset) {
2297   ExpectDiagnosticsFor(
2298       R"(
2299     #include "unchecked_optional_access_test.h"
2300 
2301     struct S { int x; };
2302     struct A { $ns::$optional<S> late; };
2303     struct B { A f3; };
2304     struct C { B f2; };
2305     struct D { C f1; };
2306 
2307     void target() {
2308       $ns::$optional<S> foo;
2309       D bar;
2310 
2311       foo.swap(bar.f1.f2.f3.late);
2312 
2313       bar.f1.f2.f3.late.value(); // [[unsafe]]
2314       foo.value(); // [[unsafe]]
2315     }
2316   )");
2317 }
2318 
2319 TEST_P(UncheckedOptionalAccessTest, UniquePtrToOptional) {
2320   // We suppress diagnostics for optionals in smart pointers (other than
2321   // `optional` itself).
2322   ExpectDiagnosticsFor(
2323       R"(
2324     #include "unchecked_optional_access_test.h"
2325 
2326     template <typename T>
2327     struct smart_ptr {
2328       T& operator*() &;
2329       T* operator->();
2330     };
2331 
2332     void target() {
2333       smart_ptr<$ns::$optional<bool>> foo;
2334       foo->value();
2335       (*foo).value();
2336     }
2337   )");
2338 }
2339 
2340 TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) {
2341   // We suppress diagnostics for optional fields reachable from smart pointers
2342   // (other than `optional` itself) through (exactly) one member access.
2343   ExpectDiagnosticsFor(
2344       R"(
2345     #include "unchecked_optional_access_test.h"
2346 
2347     template <typename T>
2348     struct smart_ptr {
2349       T& operator*() &;
2350       T* operator->();
2351     };
2352 
2353     struct Foo {
2354       $ns::$optional<int> opt;
2355     };
2356 
2357     void target() {
2358       smart_ptr<Foo> foo;
2359       *foo->opt;
2360       *(*foo).opt;
2361     }
2362   )");
2363 }
2364 
2365 TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) {
2366   ExpectDiagnosticsFor(
2367       R"(
2368     #include "unchecked_optional_access_test.h"
2369 
2370     $ns::$optional<int> MakeOpt();
2371 
2372     void target() {
2373       $ns::$optional<int> opt = 0;
2374       opt = MakeOpt();
2375       opt.value(); // [[unsafe]]
2376     }
2377   )");
2378   ExpectDiagnosticsFor(
2379       R"(
2380     #include "unchecked_optional_access_test.h"
2381 
2382     const $ns::$optional<int>& MakeOpt();
2383 
2384     void target() {
2385       $ns::$optional<int> opt = 0;
2386       opt = MakeOpt();
2387       opt.value(); // [[unsafe]]
2388     }
2389   )");
2390 
2391   ExpectDiagnosticsFor(
2392       R"(
2393     #include "unchecked_optional_access_test.h"
2394 
2395     using IntOpt = $ns::$optional<int>;
2396     IntOpt MakeOpt();
2397 
2398     void target() {
2399       IntOpt opt = 0;
2400       opt = MakeOpt();
2401       opt.value(); // [[unsafe]]
2402     }
2403   )");
2404 
2405   ExpectDiagnosticsFor(
2406       R"(
2407     #include "unchecked_optional_access_test.h"
2408 
2409     using IntOpt = $ns::$optional<int>;
2410     const IntOpt& MakeOpt();
2411 
2412     void target() {
2413       IntOpt opt = 0;
2414       opt = MakeOpt();
2415       opt.value(); // [[unsafe]]
2416     }
2417   )");
2418 }
2419 
2420 
2421 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftSet) {
2422   ExpectDiagnosticsFor(
2423       R"(
2424     #include "unchecked_optional_access_test.h"
2425 
2426     void target() {
2427       $ns::$optional<int> opt1 = 3;
2428       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2429 
2430       if (opt1 == opt2) {
2431         opt2.value();
2432       } else {
2433         opt2.value(); // [[unsafe]]
2434       }
2435     }
2436   )");
2437 }
2438 
2439 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightSet) {
2440   ExpectDiagnosticsFor(
2441       R"(
2442     #include "unchecked_optional_access_test.h"
2443 
2444     void target() {
2445       $ns::$optional<int> opt1 = 3;
2446       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2447 
2448       if (opt2 == opt1) {
2449         opt2.value();
2450       } else {
2451         opt2.value(); // [[unsafe]]
2452       }
2453     }
2454   )");
2455 }
2456 
2457 TEST_P(UncheckedOptionalAccessTest, EqualityCheckVerifySetAfterEq) {
2458   ExpectDiagnosticsFor(
2459       R"(
2460     #include "unchecked_optional_access_test.h"
2461 
2462     void target() {
2463       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2464       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2465 
2466       if (opt1 == opt2) {
2467         if (opt1.has_value())
2468           opt2.value();
2469         if (opt2.has_value())
2470           opt1.value();
2471       }
2472     }
2473   )");
2474 }
2475 
2476 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftUnset) {
2477   ExpectDiagnosticsFor(
2478       R"(
2479     #include "unchecked_optional_access_test.h"
2480 
2481     void target() {
2482       $ns::$optional<int> opt1 = $ns::nullopt;
2483       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2484 
2485       if (opt1 == opt2) {
2486         opt2.value(); // [[unsafe]]
2487       } else {
2488         opt2.value();
2489       }
2490     }
2491   )");
2492 }
2493 
2494 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightUnset) {
2495   ExpectDiagnosticsFor(
2496       R"(
2497     #include "unchecked_optional_access_test.h"
2498 
2499     void target() {
2500       $ns::$optional<int> opt1 = $ns::nullopt;
2501       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2502 
2503       if (opt2 == opt1) {
2504         opt2.value(); // [[unsafe]]
2505       } else {
2506         opt2.value();
2507       }
2508     }
2509   )");
2510 }
2511 
2512 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightNullopt) {
2513   ExpectDiagnosticsFor(
2514       R"(
2515     #include "unchecked_optional_access_test.h"
2516 
2517     void target() {
2518       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2519 
2520       if (opt == $ns::nullopt) {
2521         opt.value(); // [[unsafe]]
2522       } else {
2523         opt.value();
2524       }
2525     }
2526   )");
2527 }
2528 
2529 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftNullopt) {
2530   ExpectDiagnosticsFor(
2531       R"(
2532     #include "unchecked_optional_access_test.h"
2533 
2534     void target() {
2535       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2536 
2537       if ($ns::nullopt == opt) {
2538         opt.value(); // [[unsafe]]
2539       } else {
2540         opt.value();
2541       }
2542     }
2543   )");
2544 }
2545 
2546 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightValue) {
2547   ExpectDiagnosticsFor(
2548       R"(
2549     #include "unchecked_optional_access_test.h"
2550 
2551     void target() {
2552       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2553 
2554       if (opt == 3) {
2555         opt.value();
2556       } else {
2557         opt.value(); // [[unsafe]]
2558       }
2559     }
2560   )");
2561 }
2562 
2563 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftValue) {
2564   ExpectDiagnosticsFor(
2565       R"(
2566     #include "unchecked_optional_access_test.h"
2567 
2568     void target() {
2569       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2570 
2571       if (3 == opt) {
2572         opt.value();
2573       } else {
2574         opt.value(); // [[unsafe]]
2575       }
2576     }
2577   )");
2578 }
2579 
2580 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftSet) {
2581   ExpectDiagnosticsFor(
2582       R"(
2583     #include "unchecked_optional_access_test.h"
2584 
2585     void target() {
2586       $ns::$optional<int> opt1 = 3;
2587       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2588 
2589       if (opt1 != opt2) {
2590         opt2.value(); // [[unsafe]]
2591       } else {
2592         opt2.value();
2593       }
2594     }
2595   )");
2596 }
2597 
2598 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightSet) {
2599   ExpectDiagnosticsFor(
2600       R"(
2601     #include "unchecked_optional_access_test.h"
2602 
2603     void target() {
2604       $ns::$optional<int> opt1 = 3;
2605       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2606 
2607       if (opt2 != opt1) {
2608         opt2.value(); // [[unsafe]]
2609       } else {
2610         opt2.value();
2611       }
2612     }
2613   )");
2614 }
2615 
2616 TEST_P(UncheckedOptionalAccessTest, InequalityCheckVerifySetAfterEq) {
2617   ExpectDiagnosticsFor(
2618       R"(
2619     #include "unchecked_optional_access_test.h"
2620 
2621     void target() {
2622       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2623       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2624 
2625       if (opt1 != opt2) {
2626         if (opt1.has_value())
2627           opt2.value(); // [[unsafe]]
2628         if (opt2.has_value())
2629           opt1.value(); // [[unsafe]]
2630       }
2631     }
2632   )");
2633 }
2634 
2635 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftUnset) {
2636   ExpectDiagnosticsFor(
2637       R"(
2638     #include "unchecked_optional_access_test.h"
2639 
2640     void target() {
2641       $ns::$optional<int> opt1 = $ns::nullopt;
2642       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2643 
2644       if (opt1 != opt2) {
2645         opt2.value();
2646       } else {
2647         opt2.value(); // [[unsafe]]
2648       }
2649     }
2650   )");
2651 }
2652 
2653 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightUnset) {
2654   ExpectDiagnosticsFor(
2655       R"(
2656     #include "unchecked_optional_access_test.h"
2657 
2658     void target() {
2659       $ns::$optional<int> opt1 = $ns::nullopt;
2660       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2661 
2662       if (opt2 != opt1) {
2663         opt2.value();
2664       } else {
2665         opt2.value(); // [[unsafe]]
2666       }
2667     }
2668   )");
2669 }
2670 
2671 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightNullopt) {
2672   ExpectDiagnosticsFor(
2673       R"(
2674     #include "unchecked_optional_access_test.h"
2675 
2676     void target() {
2677       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2678 
2679       if (opt != $ns::nullopt) {
2680         opt.value();
2681       } else {
2682         opt.value(); // [[unsafe]]
2683       }
2684     }
2685   )");
2686 }
2687 
2688 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftNullopt) {
2689   ExpectDiagnosticsFor(
2690       R"(
2691     #include "unchecked_optional_access_test.h"
2692 
2693     void target() {
2694       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2695 
2696       if ($ns::nullopt != opt) {
2697         opt.value();
2698       } else {
2699         opt.value(); // [[unsafe]]
2700       }
2701     }
2702   )");
2703 }
2704 
2705 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightValue) {
2706   ExpectDiagnosticsFor(
2707       R"(
2708     #include "unchecked_optional_access_test.h"
2709 
2710     void target() {
2711       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2712 
2713       if (opt != 3) {
2714         opt.value(); // [[unsafe]]
2715       } else {
2716         opt.value();
2717       }
2718     }
2719   )");
2720 }
2721 
2722 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftValue) {
2723   ExpectDiagnosticsFor(
2724       R"(
2725     #include "unchecked_optional_access_test.h"
2726 
2727     void target() {
2728       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2729 
2730       if (3 != opt) {
2731         opt.value(); // [[unsafe]]
2732       } else {
2733         opt.value();
2734       }
2735     }
2736   )");
2737 }
2738 
2739 // Verifies that the model sees through aliases.
2740 TEST_P(UncheckedOptionalAccessTest, WithAlias) {
2741   ExpectDiagnosticsFor(
2742       R"(
2743     #include "unchecked_optional_access_test.h"
2744 
2745     template <typename T>
2746     using MyOptional = $ns::$optional<T>;
2747 
2748     void target(MyOptional<int> opt) {
2749       opt.value(); // [[unsafe]]
2750     }
2751   )");
2752 }
2753 
2754 TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) {
2755   // Basic test that nested values are populated.  We nest an optional because
2756   // its easy to use in a test, but the type of the nested value shouldn't
2757   // matter.
2758   ExpectDiagnosticsFor(
2759       R"(
2760     #include "unchecked_optional_access_test.h"
2761 
2762     using Foo = $ns::$optional<std::string>;
2763 
2764     void target($ns::$optional<Foo> foo) {
2765       if (foo && *foo) {
2766         foo->value();
2767       }
2768     }
2769   )");
2770 
2771   // Mutation is supported for nested values.
2772   ExpectDiagnosticsFor(
2773       R"(
2774     #include "unchecked_optional_access_test.h"
2775 
2776     using Foo = $ns::$optional<std::string>;
2777 
2778     void target($ns::$optional<Foo> foo) {
2779       if (foo && *foo) {
2780         foo->reset();
2781         foo->value(); // [[unsafe]]
2782       }
2783     }
2784   )");
2785 }
2786 
2787 // Tests that structs can be nested. We use an optional field because its easy
2788 // to use in a test, but the type of the field shouldn't matter.
2789 TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) {
2790   ExpectDiagnosticsFor(
2791       R"(
2792     #include "unchecked_optional_access_test.h"
2793 
2794     struct Foo {
2795       $ns::$optional<std::string> opt;
2796     };
2797 
2798     void target($ns::$optional<Foo> foo) {
2799       if (foo && foo->opt) {
2800         foo->opt.value();
2801       }
2802     }
2803   )");
2804 }
2805 
2806 TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) {
2807   ExpectDiagnosticsFor(
2808       R"(
2809     #include "unchecked_optional_access_test.h"
2810 
2811     using Foo = $ns::$optional<std::string>;
2812 
2813     void target($ns::$optional<Foo> foo, bool b) {
2814       if (!foo.has_value()) return;
2815       if (b) {
2816         if (!foo->has_value()) return;
2817         // We have created `foo.value()`.
2818         foo->value();
2819       } else {
2820         if (!foo->has_value()) return;
2821         // We have created `foo.value()` again, in a different environment.
2822         foo->value();
2823       }
2824       // Now we merge the two values. UncheckedOptionalAccessModel::merge() will
2825       // throw away the "value" property.
2826       foo->value();
2827     }
2828   )");
2829 }
2830 
2831 // This test is aimed at the core model, not the diagnostic. It is a regression
2832 // test against a crash when using non-trivial smart pointers, like
2833 // `std::unique_ptr`. As such, it doesn't test the access itself, which would be
2834 // ignored regardless because of `IgnoreSmartPointerDereference = true`, above.
2835 TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) {
2836   ExpectDiagnosticsFor(
2837       R"(
2838     #include "unchecked_optional_access_test.h"
2839 
2840     template <typename T>
2841     struct smart_ptr {
2842       typename std::add_lvalue_reference<T>::type operator*() &;
2843     };
2844 
2845     void target() {
2846       smart_ptr<$ns::$optional<int>> x;
2847       // Verify that this assignment does not crash.
2848       *x = 3;
2849     }
2850   )");
2851 }
2852 
2853 TEST_P(UncheckedOptionalAccessTest, CorrelatedBranches) {
2854   ExpectDiagnosticsFor(R"code(
2855     #include "unchecked_optional_access_test.h"
2856 
2857     void target(bool b, $ns::$optional<int> opt) {
2858       if (b || opt.has_value()) {
2859         if (!b) {
2860           opt.value();
2861         }
2862       }
2863     }
2864   )code");
2865 
2866   ExpectDiagnosticsFor(R"code(
2867     #include "unchecked_optional_access_test.h"
2868 
2869     void target(bool b, $ns::$optional<int> opt) {
2870       if (b && !opt.has_value()) return;
2871       if (b) {
2872         opt.value();
2873       }
2874     }
2875   )code");
2876 
2877   ExpectDiagnosticsFor(
2878       R"code(
2879     #include "unchecked_optional_access_test.h"
2880 
2881     void target(bool b, $ns::$optional<int> opt) {
2882       if (opt.has_value()) b = true;
2883       if (b) {
2884         opt.value(); // [[unsafe]]
2885       }
2886     }
2887   )code");
2888 
2889   ExpectDiagnosticsFor(R"code(
2890     #include "unchecked_optional_access_test.h"
2891 
2892     void target(bool b, $ns::$optional<int> opt) {
2893       if (b) return;
2894       if (opt.has_value()) b = true;
2895       if (b) {
2896         opt.value();
2897       }
2898     }
2899   )code");
2900 
2901   ExpectDiagnosticsFor(R"(
2902     #include "unchecked_optional_access_test.h"
2903 
2904     void target(bool b, $ns::$optional<int> opt) {
2905       if (opt.has_value() == b) {
2906         if (b) {
2907           opt.value();
2908         }
2909       }
2910     }
2911   )");
2912 
2913   ExpectDiagnosticsFor(R"(
2914     #include "unchecked_optional_access_test.h"
2915 
2916     void target(bool b, $ns::$optional<int> opt) {
2917       if (opt.has_value() != b) {
2918         if (!b) {
2919           opt.value();
2920         }
2921       }
2922     }
2923   )");
2924 
2925   ExpectDiagnosticsFor(R"(
2926     #include "unchecked_optional_access_test.h"
2927 
2928     void target(bool b) {
2929       $ns::$optional<int> opt1 = $ns::nullopt;
2930       $ns::$optional<int> opt2;
2931       if (b) {
2932         opt2 = $ns::nullopt;
2933       } else {
2934         opt2 = $ns::nullopt;
2935       }
2936       if (opt2.has_value()) {
2937         opt1.value();
2938       }
2939     }
2940   )");
2941 }
2942 
2943 TEST_P(UncheckedOptionalAccessTest, JoinDistinctValues) {
2944   ExpectDiagnosticsFor(
2945       R"code(
2946     #include "unchecked_optional_access_test.h"
2947 
2948     void target(bool b) {
2949       $ns::$optional<int> opt;
2950       if (b) {
2951         opt = Make<$ns::$optional<int>>();
2952       } else {
2953         opt = Make<$ns::$optional<int>>();
2954       }
2955       if (opt.has_value()) {
2956         opt.value();
2957       } else {
2958         opt.value(); // [[unsafe]]
2959       }
2960     }
2961   )code");
2962 
2963   ExpectDiagnosticsFor(R"code(
2964     #include "unchecked_optional_access_test.h"
2965 
2966     void target(bool b) {
2967       $ns::$optional<int> opt;
2968       if (b) {
2969         opt = Make<$ns::$optional<int>>();
2970         if (!opt.has_value()) return;
2971       } else {
2972         opt = Make<$ns::$optional<int>>();
2973         if (!opt.has_value()) return;
2974       }
2975       opt.value();
2976     }
2977   )code");
2978 
2979   ExpectDiagnosticsFor(
2980       R"code(
2981     #include "unchecked_optional_access_test.h"
2982 
2983     void target(bool b) {
2984       $ns::$optional<int> opt;
2985       if (b) {
2986         opt = Make<$ns::$optional<int>>();
2987         if (!opt.has_value()) return;
2988       } else {
2989         opt = Make<$ns::$optional<int>>();
2990       }
2991       opt.value(); // [[unsafe]]
2992     }
2993   )code");
2994 
2995   ExpectDiagnosticsFor(
2996       R"code(
2997     #include "unchecked_optional_access_test.h"
2998 
2999     void target(bool b) {
3000       $ns::$optional<int> opt;
3001       if (b) {
3002         opt = 1;
3003       } else {
3004         opt = 2;
3005       }
3006       opt.value();
3007     }
3008   )code");
3009 
3010   ExpectDiagnosticsFor(
3011       R"code(
3012     #include "unchecked_optional_access_test.h"
3013 
3014     void target(bool b) {
3015       $ns::$optional<int> opt;
3016       if (b) {
3017         opt = 1;
3018       } else {
3019         opt = Make<$ns::$optional<int>>();
3020       }
3021       opt.value(); // [[unsafe]]
3022     }
3023   )code");
3024 }
3025 
3026 TEST_P(UncheckedOptionalAccessTest, AccessValueInLoop) {
3027   ExpectDiagnosticsFor(R"(
3028     #include "unchecked_optional_access_test.h"
3029 
3030     void target() {
3031       $ns::$optional<int> opt = 3;
3032       while (Make<bool>()) {
3033         opt.value();
3034       }
3035     }
3036   )");
3037 }
3038 
3039 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopWithCheckSafe) {
3040   ExpectDiagnosticsFor(R"(
3041     #include "unchecked_optional_access_test.h"
3042 
3043     void target() {
3044       $ns::$optional<int> opt = 3;
3045       while (Make<bool>()) {
3046         opt.value();
3047 
3048         opt = Make<$ns::$optional<int>>();
3049         if (!opt.has_value()) return;
3050       }
3051     }
3052   )");
3053 }
3054 
3055 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopNoCheckUnsafe) {
3056   ExpectDiagnosticsFor(
3057       R"(
3058     #include "unchecked_optional_access_test.h"
3059 
3060     void target() {
3061       $ns::$optional<int> opt = 3;
3062       while (Make<bool>()) {
3063         opt.value(); // [[unsafe]]
3064 
3065         opt = Make<$ns::$optional<int>>();
3066       }
3067     }
3068   )");
3069 }
3070 
3071 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnsetUnsafe) {
3072   ExpectDiagnosticsFor(
3073       R"(
3074     #include "unchecked_optional_access_test.h"
3075 
3076     void target() {
3077       $ns::$optional<int> opt = 3;
3078       while (Make<bool>())
3079         opt = $ns::nullopt;
3080       $ns::$optional<int> opt2 = $ns::nullopt;
3081       if (opt.has_value())
3082         opt2 = $ns::$optional<int>(3);
3083       opt2.value(); // [[unsafe]]
3084     }
3085   )");
3086 }
3087 
3088 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToSetUnsafe) {
3089   ExpectDiagnosticsFor(
3090       R"(
3091     #include "unchecked_optional_access_test.h"
3092 
3093     void target() {
3094       $ns::$optional<int> opt = $ns::nullopt;
3095       while (Make<bool>())
3096         opt = $ns::$optional<int>(3);
3097       $ns::$optional<int> opt2 = $ns::nullopt;
3098       if (!opt.has_value())
3099         opt2 = $ns::$optional<int>(3);
3100       opt2.value(); // [[unsafe]]
3101     }
3102   )");
3103 }
3104 
3105 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnknownUnsafe) {
3106   ExpectDiagnosticsFor(
3107       R"(
3108     #include "unchecked_optional_access_test.h"
3109 
3110     void target() {
3111       $ns::$optional<int> opt = $ns::nullopt;
3112       while (Make<bool>())
3113         opt = Make<$ns::$optional<int>>();
3114       $ns::$optional<int> opt2 = $ns::nullopt;
3115       if (!opt.has_value())
3116         opt2 = $ns::$optional<int>(3);
3117       opt2.value(); // [[unsafe]]
3118     }
3119   )");
3120 }
3121 
3122 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopBadConditionUnsafe) {
3123   ExpectDiagnosticsFor(
3124       R"(
3125     #include "unchecked_optional_access_test.h"
3126 
3127     void target() {
3128       $ns::$optional<int> opt = 3;
3129       while (Make<bool>()) {
3130         opt.value(); // [[unsafe]]
3131 
3132         opt = Make<$ns::$optional<int>>();
3133         if (!opt.has_value()) continue;
3134       }
3135     }
3136   )");
3137 }
3138 
3139 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromStruct) {
3140   ExpectDiagnosticsFor(R"(
3141     #include "unchecked_optional_access_test.h"
3142 
3143     struct kv { $ns::$optional<int> opt; int x; };
3144     int target() {
3145       auto [contents, x] = Make<kv>();
3146       return contents ? *contents : x;
3147     }
3148   )");
3149 
3150   ExpectDiagnosticsFor(R"(
3151     #include "unchecked_optional_access_test.h"
3152 
3153     template <typename T1, typename T2>
3154     struct pair { T1 fst;  T2 snd; };
3155     int target() {
3156       auto [contents, x] = Make<pair<$ns::$optional<int>, int>>();
3157       return contents ? *contents : x;
3158     }
3159   )");
3160 }
3161 
3162 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromTupleLikeType) {
3163   ExpectDiagnosticsFor(R"(
3164     #include "unchecked_optional_access_test.h"
3165 
3166     namespace std {
3167     template <class> struct tuple_size;
3168     template <size_t, class> struct tuple_element;
3169     template <class...> class tuple;
3170 
3171     template <class... T>
3172     struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {};
3173 
3174     template <size_t I, class... T>
3175     struct tuple_element<I, tuple<T...>> {
3176       using type =  __type_pack_element<I, T...>;
3177     };
3178 
3179     template <class...> class tuple {};
3180     template <size_t I, class... T>
3181     typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
3182     } // namespace std
3183 
3184     std::tuple<$ns::$optional<const char *>, int> get_opt();
3185     void target() {
3186       auto [content, ck] = get_opt();
3187       content ? *content : "";
3188     }
3189   )");
3190 }
3191 
3192 TEST_P(UncheckedOptionalAccessTest, CtorInitializerNullopt) {
3193   using namespace ast_matchers;
3194   ExpectDiagnosticsFor(
3195       R"(
3196     #include "unchecked_optional_access_test.h"
3197 
3198     struct Target {
3199       Target(): opt($ns::nullopt) {
3200         opt.value(); // [[unsafe]]
3201       }
3202       $ns::$optional<int> opt;
3203     };
3204   )",
3205       cxxConstructorDecl(ofClass(hasName("Target"))));
3206 }
3207 
3208 TEST_P(UncheckedOptionalAccessTest, CtorInitializerValue) {
3209   using namespace ast_matchers;
3210   ExpectDiagnosticsFor(
3211       R"(
3212     #include "unchecked_optional_access_test.h"
3213 
3214     struct Target {
3215       Target(): opt(3) {
3216         opt.value();
3217       }
3218       $ns::$optional<int> opt;
3219     };
3220   )",
3221       cxxConstructorDecl(ofClass(hasName("Target"))));
3222 }
3223 
3224 // This is regression test, it shouldn't crash.
3225 TEST_P(UncheckedOptionalAccessTest, Bitfield) {
3226   using namespace ast_matchers;
3227   ExpectDiagnosticsFor(
3228       R"(
3229     #include "unchecked_optional_access_test.h"
3230     struct Dst {
3231       unsigned int n : 1;
3232     };
3233     void target() {
3234       $ns::$optional<bool> v;
3235       Dst d;
3236       if (v.has_value())
3237         d.n = v.value();
3238     }
3239   )");
3240 }
3241 
3242 TEST_P(UncheckedOptionalAccessTest, LambdaParam) {
3243   ExpectDiagnosticsForLambda(R"(
3244     #include "unchecked_optional_access_test.h"
3245 
3246     void target() {
3247       []($ns::$optional<int> opt) {
3248         if (opt.has_value()) {
3249           opt.value();
3250         } else {
3251           opt.value(); // [[unsafe]]
3252         }
3253       }(Make<$ns::$optional<int>>());
3254     }
3255   )");
3256 }
3257 
3258 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopy) {
3259   ExpectDiagnosticsForLambda(R"(
3260     #include "unchecked_optional_access_test.h"
3261 
3262     void target($ns::$optional<int> opt) {
3263       [opt]() {
3264         if (opt.has_value()) {
3265           opt.value();
3266         } else {
3267           opt.value(); // [[unsafe]]
3268         }
3269       }();
3270     }
3271   )");
3272 }
3273 
3274 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReference) {
3275   ExpectDiagnosticsForLambda(R"(
3276     #include "unchecked_optional_access_test.h"
3277 
3278     void target($ns::$optional<int> opt) {
3279       [&opt]() {
3280         if (opt.has_value()) {
3281           opt.value();
3282         } else {
3283           opt.value(); // [[unsafe]]
3284         }
3285       }();
3286     }
3287   )");
3288 }
3289 
3290 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureWithInitializer) {
3291   ExpectDiagnosticsForLambda(R"(
3292     #include "unchecked_optional_access_test.h"
3293 
3294     void target($ns::$optional<int> opt) {
3295       [opt2=opt]() {
3296         if (opt2.has_value()) {
3297           opt2.value();
3298         } else {
3299           opt2.value(); // [[unsafe]]
3300         }
3301       }();
3302     }
3303   )");
3304 }
3305 
3306 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopyImplicit) {
3307   ExpectDiagnosticsForLambda(R"(
3308     #include "unchecked_optional_access_test.h"
3309 
3310     void target($ns::$optional<int> opt) {
3311       [=]() {
3312         if (opt.has_value()) {
3313           opt.value();
3314         } else {
3315           opt.value(); // [[unsafe]]
3316         }
3317       }();
3318     }
3319   )");
3320 }
3321 
3322 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReferenceImplicit) {
3323   ExpectDiagnosticsForLambda(R"(
3324     #include "unchecked_optional_access_test.h"
3325 
3326     void target($ns::$optional<int> opt) {
3327       [&]() {
3328         if (opt.has_value()) {
3329           opt.value();
3330         } else {
3331           opt.value(); // [[unsafe]]
3332         }
3333       }();
3334     }
3335   )");
3336 }
3337 
3338 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureThis) {
3339   ExpectDiagnosticsForLambda(R"(
3340     #include "unchecked_optional_access_test.h"
3341 
3342     struct Foo {
3343       $ns::$optional<int> opt;
3344 
3345       void target() {
3346         [this]() {
3347           if (opt.has_value()) {
3348             opt.value();
3349           } else {
3350             opt.value(); // [[unsafe]]
3351           }
3352         }();
3353       }
3354     };
3355   )");
3356 }
3357 
3358 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureStateNotPropagated) {
3359   // We can't propagate information from the surrounding context.
3360   ExpectDiagnosticsForLambda(R"(
3361     #include "unchecked_optional_access_test.h"
3362 
3363     void target($ns::$optional<int> opt) {
3364       if (opt.has_value()) {
3365         [&opt]() {
3366           opt.value(); // [[unsafe]]
3367         }();
3368       }
3369     }
3370   )");
3371 }
3372 // FIXME: Add support for:
3373 // - constructors (copy, move)
3374 // - assignment operators (default, copy, move)
3375 // - invalidation (passing optional by non-const reference/pointer)
3376