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