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