1 //===- UncheckedOptionalAccessModelTest.cpp -------------------------------===//
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
7 //===----------------------------------------------------------------------===//
8 // FIXME: Move this to clang/unittests/Analysis/FlowSensitive/Models.
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"
27 using namespace clang
;
28 using namespace dataflow
;
31 using ::testing::ContainerEq
;
33 // FIXME: Move header definitions in separate file(s).
34 static constexpr char CSDtdDefHeader
[] = R
"(
40 typedef decltype(sizeof(char)) size_t;
42 using nullptr_t = decltype(nullptr);
49 static constexpr char StdTypeTraitsHeader
[] = R
"(
50 #ifndef STD_TYPE_TRAITS_H
51 #define STD_TYPE_TRAITS_H
57 template <typename T, T V>
58 struct integral_constant {
59 static constexpr T value = V;
62 using true_type = integral_constant<bool, true>;
63 using false_type = integral_constant<bool, false>;
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;};
70 using remove_reference_t = typename remove_reference<T>::type;
73 struct remove_extent {
78 struct remove_extent<T[]> {
82 template <class T, size_t N>
83 struct remove_extent<T[N]> {
88 struct is_array : false_type {};
91 struct is_array<T[]> : true_type {};
93 template <class T, size_t N>
94 struct is_array<T[N]> : true_type {};
97 struct is_function : false_type {};
99 template <class Ret, class... Args>
100 struct is_function<Ret(Args...)> : true_type {};
105 struct type_identity {
107 }; // or use type_identity (since C++20)
110 auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>;
112 auto try_add_pointer(...) -> type_identity<T>;
114 } // namespace detail
117 struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
119 template <bool B, class T, class F>
124 template <class T, class F>
125 struct conditional<false, T, F> {
134 struct remove_cv<const T> {
138 struct remove_cv<volatile T> {
142 struct remove_cv<const volatile T> {
147 using remove_cv_t = typename remove_cv<T>::type;
152 typedef typename remove_reference<T>::type U;
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;
161 template <bool B, class T = void>
165 struct enable_if<true, T> {
169 template <bool B, class T = void>
170 using enable_if_t = typename enable_if<B, T>::type;
172 template <class T, class U>
173 struct is_same : false_type {};
176 struct is_same<T, T> : true_type {};
179 struct is_void : is_same<void, typename remove_cv<T>::type> {};
184 auto try_add_lvalue_reference(int) -> type_identity<T&>;
186 auto try_add_lvalue_reference(...) -> type_identity<T>;
189 auto try_add_rvalue_reference(int) -> type_identity<T&&>;
191 auto try_add_rvalue_reference(...) -> type_identity<T>;
193 } // namespace detail
196 struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {
200 struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {
204 typename add_rvalue_reference<T>::type declval() noexcept;
209 auto test_returnable(int)
210 -> decltype(void(static_cast<T (*)()>(nullptr)), true_type{});
212 auto test_returnable(...) -> false_type;
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;
220 } // namespace detail
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>(
228 (is_void<From>::value && is_void<To>::value)> {};
230 template <class From, class To>
231 inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
236 template <class, class T, class... Args>
237 struct is_constructible_ : false_type {};
239 template <class T, class... Args>
240 struct is_constructible_<void_t<decltype(T(declval<Args>()...))>, T, Args...>
243 template <class T, class... Args>
244 using is_constructible = is_constructible_<void_t<>, T, Args...>;
246 template <class T, class... Args>
247 inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
251 typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type;
255 using __uncvref_t = typename __uncvref<_Tp>::type;
258 using _BoolConstant = integral_constant<bool, _Val>;
260 template <class _Tp, class _Up>
261 using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>;
263 template <class _Tp, class _Up>
264 using _IsNotSame = _BoolConstant<!__is_same(_Tp, _Up)>;
269 struct _MetaBase<true> {
270 template <class _Tp, class _Up>
271 using _SelectImpl = _Tp;
272 template <template <class...> class _FirstFn, template <class...> class,
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>
281 typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>::
282 template _OrImpl<_First, _Rest...>;
286 struct _MetaBase<false> {
287 template <class _Tp, class _Up>
288 using _SelectImpl = _Up;
289 template <template <class...> class, template <class...> class _SecondFn,
291 using _SelectApplyImpl = _SecondFn<_Args...>;
292 template <class _Result, class...>
293 using _OrImpl = _Result;
296 template <bool _Cond, class _IfRes, class _ElseRes>
297 using _If = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;
299 template <class... _Rest>
300 using _Or = typename _MetaBase<sizeof...(_Rest) !=
301 0>::template _OrImpl<false_type, _Rest...>;
303 template <bool _Bp, class _Tp = void>
304 using __enable_if_t = typename enable_if<_Bp, _Tp>::type;
307 using __expand_to_true = true_type;
308 template <class... _Pred>
309 __expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int);
311 false_type __and_helper(...);
312 template <class... _Pred>
313 using _And = decltype(__and_helper<_Pred...>(0));
315 template <class _Pred>
316 struct _Not : _BoolConstant<!_Pred::value> {};
318 struct __check_tuple_constructor_fail {
319 static constexpr bool __enable_explicit_default() { return false; }
320 static constexpr bool __enable_implicit_default() { return false; }
322 static constexpr bool __enable_explicit() {
326 static constexpr bool __enable_implicit() {
331 template <typename, typename _Tp>
332 struct __select_2nd {
335 template <class _Tp, class _Arg>
336 typename __select_2nd<decltype((declval<_Tp>() = declval<_Arg>())),
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> {};
351 struct __libcpp_is_integral : public false_type {};
353 struct __libcpp_is_integral<bool> : public true_type {};
355 struct __libcpp_is_integral<char> : public true_type {};
357 struct __libcpp_is_integral<signed char> : public true_type {};
359 struct __libcpp_is_integral<unsigned char> : public true_type {};
361 struct __libcpp_is_integral<wchar_t> : public true_type {};
363 struct __libcpp_is_integral<short> : public true_type {}; // NOLINT
365 struct __libcpp_is_integral<unsigned short> : public true_type {}; // NOLINT
367 struct __libcpp_is_integral<int> : public true_type {};
369 struct __libcpp_is_integral<unsigned int> : public true_type {};
371 struct __libcpp_is_integral<long> : public true_type {}; // NOLINT
373 struct __libcpp_is_integral<unsigned long> : public true_type {}; // NOLINT
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 {};
380 : public __libcpp_is_integral<typename remove_cv<_Tp>::type> {};
383 struct __libcpp_is_floating_point : public false_type {};
385 struct __libcpp_is_floating_point<float> : public true_type {};
387 struct __libcpp_is_floating_point<double> : public true_type {};
389 struct __libcpp_is_floating_point<long double> : public true_type {};
391 struct is_floating_point
392 : public __libcpp_is_floating_point<typename remove_cv<_Tp>::type> {};
396 : public integral_constant<bool, is_integral<_Tp>::value ||
397 is_floating_point<_Tp>::value> {};
400 struct __libcpp_is_pointer : public false_type {};
402 struct __libcpp_is_pointer<_Tp*> : public true_type {};
404 struct is_pointer : public __libcpp_is_pointer<typename remove_cv<_Tp>::type> {
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 {};
412 struct is_member_pointer
413 : public __libcpp_is_member_pointer<typename remove_cv<_Tp>::type> {};
416 struct __libcpp_union : public false_type {};
418 struct is_union : public __libcpp_union<typename remove_cv<_Tp>::type> {};
421 struct is_reference : false_type {};
423 struct is_reference<T&> : true_type {};
425 struct is_reference<T&&> : true_type {};
428 inline constexpr bool is_reference_v = is_reference<T>::value;
434 namespace __is_class_imp {
436 char __test(int _Tp::*);
439 } // namespace __is_class_imp
442 : public integral_constant<bool,
443 sizeof(__is_class_imp::__test<_Tp>(0)) == 1 &&
444 !is_union<_Tp>::value> {};
447 struct __is_nullptr_t_impl : public false_type {};
449 struct __is_nullptr_t_impl<nullptr_t> : public true_type {};
451 struct __is_nullptr_t
452 : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
454 struct is_null_pointer
455 : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
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> {};
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> {};
473 struct is_scalar<nullptr_t> : public true_type {};
477 #endif // STD_TYPE_TRAITS_H
480 static constexpr char AbslTypeTraitsHeader
[] = R
"(
481 #ifndef ABSL_TYPE_TRAITS_H
482 #define ABSL_TYPE_TRAITS_H
484 #include "std_type_traits
.h
"
488 template <typename... Ts>
489 struct conjunction : std::true_type {};
491 template <typename T, typename... Ts>
492 struct conjunction<T, Ts...>
493 : std::conditional<T::value, conjunction<Ts...>, T>::type {};
495 template <typename T>
496 struct conjunction<T> : T {};
498 template <typename T>
499 struct negation : std::integral_constant<bool, !T::value> {};
501 template <bool B, typename T = void>
502 using enable_if_t = typename std::enable_if<B, T>::type;
506 #endif // ABSL_TYPE_TRAITS_H
509 static constexpr char StdStringHeader
[] = R
"(
520 bool operator!=(const string &LHS, const char *RHS);
527 static constexpr char StdUtilityHeader
[] = R
"(
531 #include "std_type_traits
.h
"
535 template <typename T>
536 constexpr remove_reference_t<T>&& move(T&& x);
538 template <typename T>
539 void swap(T& a, T& b) noexcept;
546 static constexpr char StdInitializerListHeader
[] = R
"(
547 #ifndef INITIALIZER_LIST_H
548 #define INITIALIZER_LIST_H
552 template <typename T>
553 class initializer_list {
555 initializer_list() noexcept;
560 #endif // INITIALIZER_LIST_H
563 static constexpr char StdOptionalHeader
[] = R
"(
564 #include "std_initializer_list
.h
"
565 #include "std_type_traits
.h
"
566 #include "std_utility
.h
"
570 struct in_place_t {};
571 constexpr in_place_t in_place;
574 constexpr explicit nullopt_t() {}
576 constexpr nullopt_t nullopt;
579 struct __optional_destruct_base {
580 constexpr void reset() noexcept;
584 struct __optional_storage_base : __optional_destruct_base<_Tp> {
585 constexpr bool has_value() const noexcept;
588 template <typename _Tp>
589 class optional : private __optional_storage_base<_Tp> {
590 using __base = __optional_storage_base<_Tp>;
593 using value_type = _Tp;
596 struct _CheckOptionalArgsConstructor {
598 static constexpr bool __enable_implicit() {
599 return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
603 static constexpr bool __enable_explicit() {
604 return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
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;
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;
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>;
639 template <class _Up, class _QualUp>
640 using _CheckOptionalLikeAssign = _If<
642 _IsNotSame<_Up, _Tp>,
643 is_constructible<_Tp, _QualUp>,
644 is_assignable<_Tp&, _QualUp>
646 _CheckOptionalLikeConstructor<_QualUp>,
647 __check_tuple_constructor_fail
651 constexpr optional() noexcept {}
652 constexpr optional(const optional&) = default;
653 constexpr optional(optional&&) = default;
654 constexpr optional(nullopt_t) noexcept {}
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);
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,
669 class _Up = value_type,
670 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(),
672 constexpr optional(_Up&& __v);
676 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(),
678 constexpr explicit optional(_Up&& __v);
680 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
681 template __enable_implicit<_Up>(),
683 constexpr optional(const optional<_Up>& __v);
685 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
686 template __enable_explicit<_Up>(),
688 constexpr explicit optional(const optional<_Up>& __v);
690 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
691 template __enable_implicit<_Up>(),
693 constexpr optional(optional<_Up>&& __v);
695 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
696 template __enable_explicit<_Up>(),
698 constexpr explicit optional(optional<_Up>&& __v);
700 constexpr optional& operator=(nullopt_t) noexcept;
702 optional& operator=(const optional&);
704 optional& operator=(optional&&);
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);
714 template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>::
715 template __enable_assign<_Up>(),
717 constexpr optional& operator=(const optional<_Up>& __v);
719 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
720 template __enable_assign<_Up>(),
722 constexpr optional& operator=(optional<_Up>&& __v);
724 const _Tp& operator*() const&;
726 const _Tp&& operator*() const&&;
727 _Tp&& operator*() &&;
729 const _Tp* operator->() const;
732 const _Tp& value() const&;
734 const _Tp&& value() const&&;
737 template <typename U>
738 constexpr _Tp value_or(U&& v) const&;
739 template <typename U>
740 _Tp value_or(U&& v) &&;
742 template <typename... Args>
743 _Tp& emplace(Args&&... args);
745 template <typename U, typename... Args>
746 _Tp& emplace(std::initializer_list<U> ilist, Args&&... args);
750 constexpr explicit operator bool() const noexcept;
751 using __base::has_value;
753 constexpr void swap(optional& __opt) noexcept;
756 template <typename T>
757 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
759 template <typename T, typename... Args>
760 constexpr optional<T> make_optional(Args&&... args);
762 template <typename T, typename U, typename... Args>
763 constexpr optional<T> make_optional(std::initializer_list<U> il,
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);
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);
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);
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
"
801 constexpr explicit nullopt_t() {}
803 constexpr nullopt_t nullopt;
805 struct in_place_t {};
806 constexpr in_place_t in_place;
808 template <typename T>
811 namespace optional_internal {
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> {};
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> {};
834 } // namespace optional_internal
836 template <typename T>
839 constexpr optional() noexcept;
841 constexpr optional(nullopt_t) noexcept;
843 optional(const optional&) = default;
845 optional(optional&&) = default;
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);
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,
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,
869 constexpr optional(U&& v);
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,
881 explicit constexpr optional(U&& v);
883 template <typename U,
884 typename std::enable_if<
886 absl::negation<std::is_same<T, U>>,
887 std::is_constructible<T, const U&>,
890 is_constructible_convertible_from_optional<T, U>>,
891 std::is_convertible<const U&, T>>::value,
893 optional(const optional<U>& rhs);
895 template <typename U,
896 typename std::enable_if<
898 absl::negation<std::is_same<T, U>>,
899 std::is_constructible<T, const U&>,
902 is_constructible_convertible_from_optional<T, U>>,
903 absl::negation<std::is_convertible<const U&, T>>>::value,
905 explicit optional(const optional<U>& rhs);
909 typename std::enable_if<
911 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
913 optional_internal::is_constructible_convertible_from_optional<
915 std::is_convertible<U&&, T>>::value,
917 optional(optional<U>&& rhs);
921 typename std::enable_if<
923 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
925 optional_internal::is_constructible_convertible_from_optional<
927 absl::negation<std::is_convertible<U&&, T>>>::value,
929 explicit optional(optional<U>&& rhs);
931 optional& operator=(nullopt_t) noexcept;
933 optional& operator=(const optional& src);
935 optional& operator=(optional&& src);
939 typename = typename std::enable_if<absl::conjunction<
941 std::is_same<optional<T>, typename std::decay<U>::type>>,
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);
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&>,
955 is_constructible_convertible_assignable_from_optional<
956 T, U>>>::value>::type>
957 optional& operator=(const optional<U>& rhs);
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>,
965 is_constructible_convertible_assignable_from_optional<
966 T, U>>>::value>::type>
967 optional& operator=(optional<U>&& rhs);
969 const T& operator*() const&;
971 const T&& operator*() const&&;
974 const T* operator->() const;
977 const T& value() const&;
979 const T&& value() const&&;
982 template <typename U>
983 constexpr T value_or(U&& v) const&;
984 template <typename U>
985 T value_or(U&& v) &&;
987 template <typename... Args>
988 T& emplace(Args&&... args);
990 template <typename U, typename... Args>
991 T& emplace(std::initializer_list<U> ilist, Args&&... args);
993 void reset() noexcept;
995 constexpr explicit operator bool() const noexcept;
996 constexpr bool has_value() const noexcept;
998 void swap(optional& rhs) noexcept;
1001 template <typename T>
1002 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
1004 template <typename T, typename... Args>
1005 constexpr optional<T> make_optional(Args&&... args);
1007 template <typename T, typename U, typename... Args>
1008 constexpr optional<T> make_optional(std::initializer_list<U> il,
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);
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);
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);
1037 static constexpr char BaseOptionalHeader
[] = R
"(
1038 #include "std_initializer_list
.h
"
1039 #include "std_type_traits
.h
"
1040 #include "std_utility
.h
"
1044 struct in_place_t {};
1045 constexpr in_place_t in_place;
1048 constexpr explicit nullopt_t() {}
1050 constexpr nullopt_t nullopt;
1052 template <typename T>
1055 namespace internal {
1057 template <typename T>
1058 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
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> {};
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> {};
1081 } // namespace internal
1083 template <typename T>
1086 using value_type = T;
1088 constexpr Optional() = default;
1089 constexpr Optional(const Optional& other) noexcept = default;
1090 constexpr Optional(Optional&& other) noexcept = default;
1092 constexpr Optional(nullopt_t);
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;
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;
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;
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;
1126 template <class... Args>
1127 constexpr explicit Optional(in_place_t, Args&&... args);
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,
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);
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);
1155 Optional& operator=(const Optional& other) noexcept;
1157 Optional& operator=(Optional&& other) noexcept;
1159 Optional& operator=(nullopt_t);
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),
1169 operator=(U&& value) noexcept;
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,
1176 operator=(const Optional<U>& other) noexcept;
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,
1183 operator=(Optional<U>&& other) noexcept;
1185 const T& operator*() const&;
1187 const T&& operator*() const&&;
1190 const T* operator->() const;
1193 const T& value() const&;
1195 const T&& value() const&&;
1198 template <typename U>
1199 constexpr T value_or(U&& v) const&;
1200 template <typename U>
1201 T value_or(U&& v) &&;
1203 template <typename... Args>
1204 T& emplace(Args&&... args);
1206 template <typename U, typename... Args>
1207 T& emplace(std::initializer_list<U> ilist, Args&&... args);
1209 void reset() noexcept;
1211 constexpr explicit operator bool() const noexcept;
1212 constexpr bool has_value() const noexcept;
1214 void swap(Optional& other);
1217 template <typename T>
1218 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v);
1220 template <typename T, typename... Args>
1221 constexpr Optional<T> make_optional(Args&&... args);
1223 template <typename T, typename U, typename... Args>
1224 constexpr Optional<T> make_optional(std::initializer_list<U> il,
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);
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);
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);
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
) {
1258 Pos
= S
.find(Pattern
, Pos
);
1259 if (Pos
== std::string::npos
)
1261 S
.replace(Pos
, Pattern
.size(), Replacement
);
1265 struct OptionalTypeIdentifier
{
1266 std::string NamespaceName
;
1267 std::string TypeName
;
1270 static raw_ostream
&operator<<(raw_ostream
&OS
,
1271 const OptionalTypeIdentifier
&TypeId
) {
1272 OS
<< TypeId
.NamespaceName
<< "::" << TypeId
.TypeName
;
1276 class UncheckedOptionalAccessTest
1277 : public ::testing::TestWithParam
<OptionalTypeIdentifier
> {
1279 void ExpectDiagnosticsFor(std::string SourceCode
) {
1280 ExpectDiagnosticsFor(SourceCode
, ast_matchers::hasName("target"));
1283 void ExpectDiagnosticsForLambda(std::string SourceCode
) {
1284 ExpectDiagnosticsFor(
1285 SourceCode
, ast_matchers::hasDeclContext(
1286 ast_matchers::cxxRecordDecl(ast_matchers::isLambda())));
1289 template <typename FuncDeclMatcher
>
1290 void ExpectDiagnosticsFor(std::string SourceCode
,
1291 FuncDeclMatcher FuncMatcher
) {
1292 ReplaceAllOccurrences(SourceCode
, "$ns", GetParam().NamespaceName
);
1293 ReplaceAllOccurrences(SourceCode
, "$optional", GetParam().TypeName
);
1295 std::vector
<std::pair
<std::string
, std::string
>> Headers
;
1296 Headers
.emplace_back("cstddef.h", CSDtdDefHeader
);
1297 Headers
.emplace_back("std_initializer_list.h", StdInitializerListHeader
);
1298 Headers
.emplace_back("std_string.h", StdStringHeader
);
1299 Headers
.emplace_back("std_type_traits.h", StdTypeTraitsHeader
);
1300 Headers
.emplace_back("std_utility.h", StdUtilityHeader
);
1301 Headers
.emplace_back("std_optional.h", StdOptionalHeader
);
1302 Headers
.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader
);
1303 Headers
.emplace_back("absl_optional.h", AbslOptionalHeader
);
1304 Headers
.emplace_back("base_optional.h", BaseOptionalHeader
);
1305 Headers
.emplace_back("unchecked_optional_access_test.h", R
"(
1306 #include "absl_optional
.h
"
1307 #include "base_optional
.h
"
1308 #include "std_initializer_list
.h
"
1309 #include "std_optional
.h
"
1310 #include "std_string
.h
"
1311 #include "std_utility
.h
"
1313 template <typename T>
1316 UncheckedOptionalAccessModelOptions Options
{
1317 /*IgnoreSmartPointerDereference=*/true};
1318 std::vector
<SourceLocation
> Diagnostics
;
1319 llvm::Error Error
= checkDataflow
<UncheckedOptionalAccessModel
>(
1320 AnalysisInputs
<UncheckedOptionalAccessModel
>(
1321 SourceCode
, std::move(FuncMatcher
),
1322 [](ASTContext
&Ctx
, Environment
&) {
1323 return UncheckedOptionalAccessModel(Ctx
);
1327 Diagnoser
= UncheckedOptionalAccessDiagnoser(Options
)](
1328 ASTContext
&Ctx
, const CFGElement
&Elt
,
1329 const TransferStateForDiagnostics
<NoopLattice
>
1331 auto EltDiagnostics
= Diagnoser(Elt
, Ctx
, State
);
1332 llvm::move(EltDiagnostics
, std::back_inserter(Diagnostics
));
1335 {"-fsyntax-only", "-std=c++17", "-Wno-undefined-inline"})
1336 .withASTBuildVirtualMappedFiles(
1337 tooling::FileContentMappings(Headers
.begin(), Headers
.end())),
1338 /*VerifyResults=*/[&Diagnostics
](
1339 const llvm::DenseMap
<unsigned, std::string
>
1341 const AnalysisOutputs
&AO
) {
1342 llvm::DenseSet
<unsigned> AnnotationLines
;
1343 for (const auto &[Line
, _
] : Annotations
) {
1344 AnnotationLines
.insert(Line
);
1346 auto &SrcMgr
= AO
.ASTCtx
.getSourceManager();
1347 llvm::DenseSet
<unsigned> DiagnosticLines
;
1348 for (SourceLocation
&Loc
: Diagnostics
) {
1349 unsigned Line
= SrcMgr
.getPresumedLineNumber(Loc
);
1350 DiagnosticLines
.insert(Line
);
1351 if (!AnnotationLines
.contains(Line
)) {
1352 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts(
1353 new DiagnosticOptions());
1354 TextDiagnostic
TD(llvm::errs(), AO
.ASTCtx
.getLangOpts(),
1357 FullSourceLoc(Loc
, SrcMgr
), DiagnosticsEngine::Error
,
1358 "unexpected diagnostic", std::nullopt
, std::nullopt
);
1362 EXPECT_THAT(DiagnosticLines
, ContainerEq(AnnotationLines
));
1365 FAIL() << llvm::toString(std::move(Error
));
1369 INSTANTIATE_TEST_SUITE_P(
1370 UncheckedOptionalUseTestInst
, UncheckedOptionalAccessTest
,
1371 ::testing::Values(OptionalTypeIdentifier
{"std", "optional"},
1372 OptionalTypeIdentifier
{"absl", "optional"},
1373 OptionalTypeIdentifier
{"base", "Optional"}),
1374 [](const ::testing::TestParamInfo
<OptionalTypeIdentifier
> &Info
) {
1375 return Info
.param
.NamespaceName
;
1378 // Verifies that similarly-named types are ignored.
1379 TEST_P(UncheckedOptionalAccessTest
, NonTrackedOptionalType
) {
1380 ExpectDiagnosticsFor(
1384 template <typename T>
1390 void target($ns::$optional<int> opt) {
1397 TEST_P(UncheckedOptionalAccessTest
, EmptyFunctionBody
) {
1398 ExpectDiagnosticsFor(R
"(
1405 TEST_P(UncheckedOptionalAccessTest
, UnwrapUsingValueNoCheck
) {
1406 ExpectDiagnosticsFor(
1408 #include "unchecked_optional_access_test
.h
"
1410 void target($ns::$optional<int> opt) {
1411 opt.value(); // [[unsafe]]
1415 ExpectDiagnosticsFor(
1417 #include "unchecked_optional_access_test
.h
"
1419 void target($ns::$optional<int> opt) {
1420 std::move(opt).value(); // [[unsafe]]
1425 TEST_P(UncheckedOptionalAccessTest
, UnwrapUsingOperatorStarNoCheck
) {
1426 ExpectDiagnosticsFor(
1428 #include "unchecked_optional_access_test
.h
"
1430 void target($ns::$optional<int> opt) {
1435 ExpectDiagnosticsFor(
1437 #include "unchecked_optional_access_test
.h
"
1439 void target($ns::$optional<int> opt) {
1440 *std::move(opt); // [[unsafe]]
1445 TEST_P(UncheckedOptionalAccessTest
, UnwrapUsingOperatorArrowNoCheck
) {
1446 ExpectDiagnosticsFor(
1448 #include "unchecked_optional_access_test
.h
"
1454 void target($ns::$optional<Foo> opt) {
1455 opt->foo(); // [[unsafe]]
1459 ExpectDiagnosticsFor(
1461 #include "unchecked_optional_access_test
.h
"
1467 void target($ns::$optional<Foo> opt) {
1468 std::move(opt)->foo(); // [[unsafe]]
1473 TEST_P(UncheckedOptionalAccessTest
, HasValueCheck
) {
1474 ExpectDiagnosticsFor(R
"(
1475 #include "unchecked_optional_access_test
.h
"
1477 void target($ns::$optional<int> opt) {
1478 if (opt.has_value()) {
1485 TEST_P(UncheckedOptionalAccessTest
, OperatorBoolCheck
) {
1486 ExpectDiagnosticsFor(R
"(
1487 #include "unchecked_optional_access_test
.h
"
1489 void target($ns::$optional<int> opt) {
1497 TEST_P(UncheckedOptionalAccessTest
, UnwrapFunctionCallResultNoCheck
) {
1498 ExpectDiagnosticsFor(
1500 #include "unchecked_optional_access_test
.h
"
1503 Make<$ns::$optional<int>>().value(); // [[unsafe]]
1508 ExpectDiagnosticsFor(
1510 #include "unchecked_optional_access_test
.h
"
1512 void target($ns::$optional<int> opt) {
1513 std::move(opt).value(); // [[unsafe]]
1518 TEST_P(UncheckedOptionalAccessTest
, DefaultConstructor
) {
1519 ExpectDiagnosticsFor(
1521 #include "unchecked_optional_access_test
.h
"
1524 $ns::$optional<int> opt;
1525 opt.value(); // [[unsafe]]
1530 TEST_P(UncheckedOptionalAccessTest
, NulloptConstructor
) {
1531 ExpectDiagnosticsFor(
1533 #include "unchecked_optional_access_test
.h
"
1536 $ns::$optional<int> opt($ns::nullopt);
1537 opt.value(); // [[unsafe]]
1542 TEST_P(UncheckedOptionalAccessTest
, NulloptConstructorWithSugaredType
) {
1543 ExpectDiagnosticsFor(
1545 #include "unchecked_optional_access_test
.h
"
1546 template <typename T>
1549 template <typename T>
1553 $ns::$optional<int> opt(wrap($ns::nullopt));
1554 opt.value(); // [[unsafe]]
1559 TEST_P(UncheckedOptionalAccessTest
, InPlaceConstructor
) {
1560 ExpectDiagnosticsFor(R
"(
1561 #include "unchecked_optional_access_test
.h
"
1564 $ns::$optional<int> opt($ns::in_place, 3);
1569 ExpectDiagnosticsFor(R
"(
1570 #include "unchecked_optional_access_test
.h
"
1575 $ns::$optional<Foo> opt($ns::in_place);
1580 ExpectDiagnosticsFor(R
"(
1581 #include "unchecked_optional_access_test
.h
"
1584 explicit Foo(int, bool);
1588 $ns::$optional<Foo> opt($ns::in_place, 3, false);
1593 ExpectDiagnosticsFor(R
"(
1594 #include "unchecked_optional_access_test
.h
"
1597 explicit Foo(std::initializer_list<int>);
1601 $ns::$optional<Foo> opt($ns::in_place, {3});
1607 TEST_P(UncheckedOptionalAccessTest
, ValueConstructor
) {
1608 ExpectDiagnosticsFor(R
"(
1609 #include "unchecked_optional_access_test
.h
"
1612 $ns::$optional<int> opt(21);
1617 ExpectDiagnosticsFor(R
"(
1618 #include "unchecked_optional_access_test
.h
"
1621 $ns::$optional<int> opt = $ns::$optional<int>(21);
1625 ExpectDiagnosticsFor(R
"(
1626 #include "unchecked_optional_access_test
.h
"
1629 $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1634 ExpectDiagnosticsFor(R
"(
1635 #include "unchecked_optional_access_test
.h
"
1638 MyString(const char*);
1642 $ns::$optional<MyString> opt("foo
");
1647 ExpectDiagnosticsFor(R
"(
1648 #include "unchecked_optional_access_test
.h
"
1657 $ns::$optional<Bar> opt(Make<Foo>());
1662 ExpectDiagnosticsFor(R
"(
1663 #include "unchecked_optional_access_test
.h
"
1670 $ns::$optional<Foo> opt(3);
1676 TEST_P(UncheckedOptionalAccessTest
, ConvertibleOptionalConstructor
) {
1677 ExpectDiagnosticsFor(
1679 #include "unchecked_optional_access_test
.h
"
1688 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1689 opt.value(); // [[unsafe]]
1693 ExpectDiagnosticsFor(
1695 #include "unchecked_optional_access_test
.h
"
1700 explicit Bar(const Foo&);
1704 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1705 opt.value(); // [[unsafe]]
1709 ExpectDiagnosticsFor(
1711 #include "unchecked_optional_access_test
.h
"
1720 $ns::$optional<Foo> opt1 = $ns::nullopt;
1721 $ns::$optional<Bar> opt2(opt1);
1722 opt2.value(); // [[unsafe]]
1726 ExpectDiagnosticsFor(R
"(
1727 #include "unchecked_optional_access_test
.h
"
1736 $ns::$optional<Foo> opt1(Make<Foo>());
1737 $ns::$optional<Bar> opt2(opt1);
1742 ExpectDiagnosticsFor(R
"(
1743 #include "unchecked_optional_access_test
.h
"
1748 explicit Bar(const Foo&);
1752 $ns::$optional<Foo> opt1(Make<Foo>());
1753 $ns::$optional<Bar> opt2(opt1);
1759 TEST_P(UncheckedOptionalAccessTest
, MakeOptional
) {
1760 ExpectDiagnosticsFor(R
"(
1761 #include "unchecked_optional_access_test
.h
"
1764 $ns::$optional<int> opt = $ns::make_optional(0);
1769 ExpectDiagnosticsFor(R
"(
1770 #include "unchecked_optional_access_test
.h
"
1777 $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1782 ExpectDiagnosticsFor(R
"(
1783 #include "unchecked_optional_access_test
.h
"
1786 constexpr Foo(std::initializer_list<char>);
1791 $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1797 TEST_P(UncheckedOptionalAccessTest
, ValueOr
) {
1798 ExpectDiagnosticsFor(R
"(
1799 #include "unchecked_optional_access_test
.h
"
1802 $ns::$optional<int> opt;
1809 TEST_P(UncheckedOptionalAccessTest
, ValueOrComparisonPointers
) {
1810 ExpectDiagnosticsFor(
1812 #include "unchecked_optional_access_test
.h
"
1814 void target($ns::$optional<int*> opt) {
1815 if (opt.value_or(nullptr) != nullptr) {
1818 opt.value(); // [[unsafe]]
1824 TEST_P(UncheckedOptionalAccessTest
, ValueOrComparisonIntegers
) {
1825 ExpectDiagnosticsFor(
1827 #include "unchecked_optional_access_test
.h
"
1829 void target($ns::$optional<int> opt) {
1830 if (opt.value_or(0) != 0) {
1833 opt.value(); // [[unsafe]]
1839 TEST_P(UncheckedOptionalAccessTest
, ValueOrComparisonStrings
) {
1840 ExpectDiagnosticsFor(
1842 #include "unchecked_optional_access_test
.h
"
1844 void target($ns::$optional<std::string> opt) {
1845 if (!opt.value_or("").empty()) {
1848 opt.value(); // [[unsafe]]
1853 ExpectDiagnosticsFor(
1855 #include "unchecked_optional_access_test
.h
"
1857 void target($ns::$optional<std::string> opt) {
1858 if (opt.value_or("") != "") {
1861 opt.value(); // [[unsafe]]
1867 TEST_P(UncheckedOptionalAccessTest
, ValueOrComparisonPointerToOptional
) {
1868 // FIXME: make `opt` a parameter directly, once we ensure that all `optional`
1869 // values have a `has_value` property.
1870 ExpectDiagnosticsFor(
1872 #include "unchecked_optional_access_test
.h
"
1874 void target($ns::$optional<int> p) {
1875 $ns::$optional<int> *opt = &p;
1876 if (opt->value_or(0) != 0) {
1879 opt->value(); // [[unsafe]]
1885 TEST_P(UncheckedOptionalAccessTest
, Emplace
) {
1886 ExpectDiagnosticsFor(R
"(
1887 #include "unchecked_optional_access_test
.h
"
1890 $ns::$optional<int> opt;
1896 ExpectDiagnosticsFor(R
"(
1897 #include "unchecked_optional_access_test
.h
"
1899 void target($ns::$optional<int> *opt) {
1905 // FIXME: Add tests that call `emplace` in conditional branches:
1906 // ExpectDiagnosticsFor(
1908 // #include "unchecked_optional_access_test.h"
1910 // void target($ns::$optional<int> opt, bool b) {
1917 // opt.value(); // [[unsafe]]
1923 TEST_P(UncheckedOptionalAccessTest
, Reset
) {
1924 ExpectDiagnosticsFor(
1926 #include "unchecked_optional_access_test
.h
"
1929 $ns::$optional<int> opt = $ns::make_optional(0);
1931 opt.value(); // [[unsafe]]
1935 ExpectDiagnosticsFor(
1937 #include "unchecked_optional_access_test
.h
"
1939 void target($ns::$optional<int> &opt) {
1940 if (opt.has_value()) {
1942 opt.value(); // [[unsafe]]
1947 // FIXME: Add tests that call `reset` in conditional branches:
1948 // ExpectDiagnosticsFor(
1950 // #include "unchecked_optional_access_test.h"
1952 // void target(bool b) {
1953 // $ns::$optional<int> opt = $ns::make_optional(0);
1958 // opt.value(); // [[unsafe]]
1966 TEST_P(UncheckedOptionalAccessTest
, ValueAssignment
) {
1967 ExpectDiagnosticsFor(R
"(
1968 #include "unchecked_optional_access_test
.h
"
1973 $ns::$optional<Foo> opt;
1979 ExpectDiagnosticsFor(R
"(
1980 #include "unchecked_optional_access_test
.h
"
1985 $ns::$optional<Foo> opt;
1986 (opt = Foo()).value();
1991 ExpectDiagnosticsFor(R
"(
1992 #include "unchecked_optional_access_test
.h
"
1995 MyString(const char*);
1999 $ns::$optional<MyString> opt;
2005 ExpectDiagnosticsFor(R
"(
2006 #include "unchecked_optional_access_test
.h
"
2009 MyString(const char*);
2013 $ns::$optional<MyString> opt;
2014 (opt = "foo
").value();
2019 TEST_P(UncheckedOptionalAccessTest
, OptionalConversionAssignment
) {
2020 ExpectDiagnosticsFor(
2022 #include "unchecked_optional_access_test
.h
"
2031 $ns::$optional<Foo> opt1 = Foo();
2032 $ns::$optional<Bar> opt2;
2038 ExpectDiagnosticsFor(
2040 #include "unchecked_optional_access_test
.h
"
2049 $ns::$optional<Foo> opt1;
2050 $ns::$optional<Bar> opt2;
2051 if (opt2.has_value()) {
2053 opt2.value(); // [[unsafe]]
2058 ExpectDiagnosticsFor(
2060 #include "unchecked_optional_access_test
.h
"
2069 $ns::$optional<Foo> opt1 = Foo();
2070 $ns::$optional<Bar> opt2;
2071 (opt2 = opt1).value();
2077 TEST_P(UncheckedOptionalAccessTest
, NulloptAssignment
) {
2078 ExpectDiagnosticsFor(
2080 #include "unchecked_optional_access_test
.h
"
2083 $ns::$optional<int> opt = 3;
2085 opt.value(); // [[unsafe]]
2089 ExpectDiagnosticsFor(
2091 #include "unchecked_optional_access_test
.h
"
2094 $ns::$optional<int> opt = 3;
2095 (opt = $ns::nullopt).value(); // [[unsafe]]
2100 TEST_P(UncheckedOptionalAccessTest
, OptionalSwap
) {
2101 ExpectDiagnosticsFor(
2103 #include "unchecked_optional_access_test
.h
"
2106 $ns::$optional<int> opt1 = $ns::nullopt;
2107 $ns::$optional<int> opt2 = 3;
2113 opt2.value(); // [[unsafe]]
2117 ExpectDiagnosticsFor(
2119 #include "unchecked_optional_access_test
.h
"
2122 $ns::$optional<int> opt1 = $ns::nullopt;
2123 $ns::$optional<int> opt2 = 3;
2129 opt2.value(); // [[unsafe]]
2134 TEST_P(UncheckedOptionalAccessTest
, OptionalReturnedFromFuntionCall
) {
2135 ExpectDiagnosticsFor(
2137 #include "unchecked_optional_access_test
.h
"
2140 $ns::$optional<float> x;
2147 getOptional().x = 0;
2152 TEST_P(UncheckedOptionalAccessTest
, StdSwap
) {
2153 ExpectDiagnosticsFor(
2155 #include "unchecked_optional_access_test
.h
"
2158 $ns::$optional<int> opt1 = $ns::nullopt;
2159 $ns::$optional<int> opt2 = 3;
2161 std::swap(opt1, opt2);
2165 opt2.value(); // [[unsafe]]
2169 ExpectDiagnosticsFor(
2171 #include "unchecked_optional_access_test
.h
"
2174 $ns::$optional<int> opt1 = $ns::nullopt;
2175 $ns::$optional<int> opt2 = 3;
2177 std::swap(opt2, opt1);
2181 opt2.value(); // [[unsafe]]
2186 TEST_P(UncheckedOptionalAccessTest
, SwapUnmodeledLocLeft
) {
2187 ExpectDiagnosticsFor(
2189 #include "unchecked_optional_access_test
.h
"
2191 struct L { $ns::$optional<int> hd; L* tl; };
2194 $ns::$optional<int> foo = 3;
2197 // Any `tl` beyond the first is not modeled.
2198 bar.tl->tl->hd.swap(foo);
2200 bar.tl->tl->hd.value(); // [[unsafe]]
2201 foo.value(); // [[unsafe]]
2206 TEST_P(UncheckedOptionalAccessTest
, SwapUnmodeledLocRight
) {
2207 ExpectDiagnosticsFor(
2209 #include "unchecked_optional_access_test
.h
"
2211 struct L { $ns::$optional<int> hd; L* tl; };
2214 $ns::$optional<int> foo = 3;
2217 // Any `tl` beyond the first is not modeled.
2218 foo.swap(bar.tl->tl->hd);
2220 bar.tl->tl->hd.value(); // [[unsafe]]
2221 foo.value(); // [[unsafe]]
2226 TEST_P(UncheckedOptionalAccessTest
, SwapUnmodeledValueLeftSet
) {
2227 ExpectDiagnosticsFor(
2229 #include "unchecked_optional_access_test
.h
"
2231 struct S { int x; };
2232 struct A { $ns::$optional<S> late; };
2238 $ns::$optional<S> foo = S{3};
2241 bar.f1.f2.f3.late.swap(foo);
2243 bar.f1.f2.f3.late.value();
2244 foo.value(); // [[unsafe]]
2249 TEST_P(UncheckedOptionalAccessTest
, SwapUnmodeledValueLeftUnset
) {
2250 ExpectDiagnosticsFor(
2252 #include "unchecked_optional_access_test
.h
"
2254 struct S { int x; };
2255 struct A { $ns::$optional<S> late; };
2261 $ns::$optional<S> foo;
2264 bar.f1.f2.f3.late.swap(foo);
2266 bar.f1.f2.f3.late.value(); // [[unsafe]]
2267 foo.value(); // [[unsafe]]
2272 // fixme: use recursion instead of depth.
2273 TEST_P(UncheckedOptionalAccessTest
, SwapUnmodeledValueRightSet
) {
2274 ExpectDiagnosticsFor(
2276 #include "unchecked_optional_access_test
.h
"
2278 struct S { int x; };
2279 struct A { $ns::$optional<S> late; };
2285 $ns::$optional<S> foo = S{3};
2288 foo.swap(bar.f1.f2.f3.late);
2290 bar.f1.f2.f3.late.value();
2291 foo.value(); // [[unsafe]]
2296 TEST_P(UncheckedOptionalAccessTest
, SwapUnmodeledValueRightUnset
) {
2297 ExpectDiagnosticsFor(
2299 #include "unchecked_optional_access_test
.h
"
2301 struct S { int x; };
2302 struct A { $ns::$optional<S> late; };
2308 $ns::$optional<S> foo;
2311 foo.swap(bar.f1.f2.f3.late);
2313 bar.f1.f2.f3.late.value(); // [[unsafe]]
2314 foo.value(); // [[unsafe]]
2319 TEST_P(UncheckedOptionalAccessTest
, UniquePtrToOptional
) {
2320 // We suppress diagnostics for optionals in smart pointers (other than
2321 // `optional` itself).
2322 ExpectDiagnosticsFor(
2324 #include "unchecked_optional_access_test
.h
"
2326 template <typename T>
2333 smart_ptr<$ns::$optional<bool>> foo;
2340 TEST_P(UncheckedOptionalAccessTest
, UniquePtrToStructWithOptionalField
) {
2341 // We suppress diagnostics for optional fields reachable from smart pointers
2342 // (other than `optional` itself) through (exactly) one member access.
2343 ExpectDiagnosticsFor(
2345 #include "unchecked_optional_access_test
.h
"
2347 template <typename T>
2354 $ns::$optional<int> opt;
2365 TEST_P(UncheckedOptionalAccessTest
, CallReturningOptional
) {
2366 ExpectDiagnosticsFor(
2368 #include "unchecked_optional_access_test
.h
"
2370 $ns::$optional<int> MakeOpt();
2373 $ns::$optional<int> opt = 0;
2375 opt.value(); // [[unsafe]]
2378 ExpectDiagnosticsFor(
2380 #include "unchecked_optional_access_test
.h
"
2382 const $ns::$optional<int>& MakeOpt();
2385 $ns::$optional<int> opt = 0;
2387 opt.value(); // [[unsafe]]
2391 ExpectDiagnosticsFor(
2393 #include "unchecked_optional_access_test
.h
"
2395 using IntOpt = $ns::$optional<int>;
2401 opt.value(); // [[unsafe]]
2405 ExpectDiagnosticsFor(
2407 #include "unchecked_optional_access_test
.h
"
2409 using IntOpt = $ns::$optional<int>;
2410 const IntOpt& MakeOpt();
2415 opt.value(); // [[unsafe]]
2421 TEST_P(UncheckedOptionalAccessTest
, EqualityCheckLeftSet
) {
2422 ExpectDiagnosticsFor(
2424 #include "unchecked_optional_access_test
.h
"
2427 $ns::$optional<int> opt1 = 3;
2428 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2433 opt2.value(); // [[unsafe]]
2439 TEST_P(UncheckedOptionalAccessTest
, EqualityCheckRightSet
) {
2440 ExpectDiagnosticsFor(
2442 #include "unchecked_optional_access_test
.h
"
2445 $ns::$optional<int> opt1 = 3;
2446 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2451 opt2.value(); // [[unsafe]]
2457 TEST_P(UncheckedOptionalAccessTest
, EqualityCheckVerifySetAfterEq
) {
2458 ExpectDiagnosticsFor(
2460 #include "unchecked_optional_access_test
.h
"
2463 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2464 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2467 if (opt1.has_value())
2469 if (opt2.has_value())
2476 TEST_P(UncheckedOptionalAccessTest
, EqualityCheckLeftUnset
) {
2477 ExpectDiagnosticsFor(
2479 #include "unchecked_optional_access_test
.h
"
2482 $ns::$optional<int> opt1 = $ns::nullopt;
2483 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2486 opt2.value(); // [[unsafe]]
2494 TEST_P(UncheckedOptionalAccessTest
, EqualityCheckRightUnset
) {
2495 ExpectDiagnosticsFor(
2497 #include "unchecked_optional_access_test
.h
"
2500 $ns::$optional<int> opt1 = $ns::nullopt;
2501 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2504 opt2.value(); // [[unsafe]]
2512 TEST_P(UncheckedOptionalAccessTest
, EqualityCheckRightNullopt
) {
2513 ExpectDiagnosticsFor(
2515 #include "unchecked_optional_access_test
.h
"
2518 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2520 if (opt == $ns::nullopt) {
2521 opt.value(); // [[unsafe]]
2529 TEST_P(UncheckedOptionalAccessTest
, EqualityCheckLeftNullopt
) {
2530 ExpectDiagnosticsFor(
2532 #include "unchecked_optional_access_test
.h
"
2535 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2537 if ($ns::nullopt == opt) {
2538 opt.value(); // [[unsafe]]
2546 TEST_P(UncheckedOptionalAccessTest
, EqualityCheckRightValue
) {
2547 ExpectDiagnosticsFor(
2549 #include "unchecked_optional_access_test
.h
"
2552 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2557 opt.value(); // [[unsafe]]
2563 TEST_P(UncheckedOptionalAccessTest
, EqualityCheckLeftValue
) {
2564 ExpectDiagnosticsFor(
2566 #include "unchecked_optional_access_test
.h
"
2569 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2574 opt.value(); // [[unsafe]]
2580 TEST_P(UncheckedOptionalAccessTest
, InequalityCheckLeftSet
) {
2581 ExpectDiagnosticsFor(
2583 #include "unchecked_optional_access_test
.h
"
2586 $ns::$optional<int> opt1 = 3;
2587 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2590 opt2.value(); // [[unsafe]]
2598 TEST_P(UncheckedOptionalAccessTest
, InequalityCheckRightSet
) {
2599 ExpectDiagnosticsFor(
2601 #include "unchecked_optional_access_test
.h
"
2604 $ns::$optional<int> opt1 = 3;
2605 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2608 opt2.value(); // [[unsafe]]
2616 TEST_P(UncheckedOptionalAccessTest
, InequalityCheckVerifySetAfterEq
) {
2617 ExpectDiagnosticsFor(
2619 #include "unchecked_optional_access_test
.h
"
2622 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2623 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2626 if (opt1.has_value())
2627 opt2.value(); // [[unsafe]]
2628 if (opt2.has_value())
2629 opt1.value(); // [[unsafe]]
2635 TEST_P(UncheckedOptionalAccessTest
, InequalityCheckLeftUnset
) {
2636 ExpectDiagnosticsFor(
2638 #include "unchecked_optional_access_test
.h
"
2641 $ns::$optional<int> opt1 = $ns::nullopt;
2642 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2647 opt2.value(); // [[unsafe]]
2653 TEST_P(UncheckedOptionalAccessTest
, InequalityCheckRightUnset
) {
2654 ExpectDiagnosticsFor(
2656 #include "unchecked_optional_access_test
.h
"
2659 $ns::$optional<int> opt1 = $ns::nullopt;
2660 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2665 opt2.value(); // [[unsafe]]
2671 TEST_P(UncheckedOptionalAccessTest
, InequalityCheckRightNullopt
) {
2672 ExpectDiagnosticsFor(
2674 #include "unchecked_optional_access_test
.h
"
2677 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2679 if (opt != $ns::nullopt) {
2682 opt.value(); // [[unsafe]]
2688 TEST_P(UncheckedOptionalAccessTest
, InequalityCheckLeftNullopt
) {
2689 ExpectDiagnosticsFor(
2691 #include "unchecked_optional_access_test
.h
"
2694 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2696 if ($ns::nullopt != opt) {
2699 opt.value(); // [[unsafe]]
2705 TEST_P(UncheckedOptionalAccessTest
, InequalityCheckRightValue
) {
2706 ExpectDiagnosticsFor(
2708 #include "unchecked_optional_access_test
.h
"
2711 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2714 opt.value(); // [[unsafe]]
2722 TEST_P(UncheckedOptionalAccessTest
, InequalityCheckLeftValue
) {
2723 ExpectDiagnosticsFor(
2725 #include "unchecked_optional_access_test
.h
"
2728 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2731 opt.value(); // [[unsafe]]
2739 // Verifies that the model sees through aliases.
2740 TEST_P(UncheckedOptionalAccessTest
, WithAlias
) {
2741 ExpectDiagnosticsFor(
2743 #include "unchecked_optional_access_test
.h
"
2745 template <typename T>
2746 using MyOptional = $ns::$optional<T>;
2748 void target(MyOptional<int> opt) {
2749 opt.value(); // [[unsafe]]
2754 TEST_P(UncheckedOptionalAccessTest
, OptionalValueOptional
) {
2755 // Basic test that nested values are populated. We nest an optional because
2756 // its easy to use in a test, but the type of the nested value shouldn't
2758 ExpectDiagnosticsFor(
2760 #include "unchecked_optional_access_test
.h
"
2762 using Foo = $ns::$optional<std::string>;
2764 void target($ns::$optional<Foo> foo) {
2771 // Mutation is supported for nested values.
2772 ExpectDiagnosticsFor(
2774 #include "unchecked_optional_access_test
.h
"
2776 using Foo = $ns::$optional<std::string>;
2778 void target($ns::$optional<Foo> foo) {
2781 foo->value(); // [[unsafe]]
2787 // Tests that structs can be nested. We use an optional field because its easy
2788 // to use in a test, but the type of the field shouldn't matter.
2789 TEST_P(UncheckedOptionalAccessTest
, OptionalValueStruct
) {
2790 ExpectDiagnosticsFor(
2792 #include "unchecked_optional_access_test
.h
"
2795 $ns::$optional<std::string> opt;
2798 void target($ns::$optional<Foo> foo) {
2799 if (foo && foo->opt) {
2806 TEST_P(UncheckedOptionalAccessTest
, OptionalValueInitialization
) {
2807 ExpectDiagnosticsFor(
2809 #include "unchecked_optional_access_test
.h
"
2811 using Foo = $ns::$optional<std::string>;
2813 void target($ns::$optional<Foo> foo, bool b) {
2814 if (!foo.has_value()) return;
2816 if (!foo->has_value()) return;
2817 // We have created `foo.value()`.
2820 if (!foo->has_value()) return;
2821 // We have created `foo.value()` again, in a different environment.
2824 // Now we merge the two values. UncheckedOptionalAccessModel::merge() will
2825 // throw away the "value
" property.
2831 // This test is aimed at the core model, not the diagnostic. It is a regression
2832 // test against a crash when using non-trivial smart pointers, like
2833 // `std::unique_ptr`. As such, it doesn't test the access itself, which would be
2834 // ignored regardless because of `IgnoreSmartPointerDereference = true`, above.
2835 TEST_P(UncheckedOptionalAccessTest
, AssignThroughLvalueReferencePtr
) {
2836 ExpectDiagnosticsFor(
2838 #include "unchecked_optional_access_test
.h
"
2840 template <typename T>
2842 typename std::add_lvalue_reference<T>::type operator*() &;
2846 smart_ptr<$ns::$optional<int>> x;
2847 // Verify that this assignment does not crash.
2853 TEST_P(UncheckedOptionalAccessTest
, CorrelatedBranches
) {
2854 ExpectDiagnosticsFor(R
"code(
2855 #include "unchecked_optional_access_test
.h
"
2857 void target(bool b, $ns::$optional<int> opt) {
2858 if (b || opt.has_value()) {
2866 ExpectDiagnosticsFor(R
"code(
2867 #include "unchecked_optional_access_test
.h
"
2869 void target(bool b, $ns::$optional<int> opt) {
2870 if (b && !opt.has_value()) return;
2877 ExpectDiagnosticsFor(
2879 #include "unchecked_optional_access_test
.h
"
2881 void target(bool b, $ns::$optional<int> opt) {
2882 if (opt.has_value()) b = true;
2884 opt.value(); // [[unsafe]]
2889 ExpectDiagnosticsFor(R
"code(
2890 #include "unchecked_optional_access_test
.h
"
2892 void target(bool b, $ns::$optional<int> opt) {
2894 if (opt.has_value()) b = true;
2901 ExpectDiagnosticsFor(R
"(
2902 #include "unchecked_optional_access_test
.h
"
2904 void target(bool b, $ns::$optional<int> opt) {
2905 if (opt.has_value() == b) {
2913 ExpectDiagnosticsFor(R
"(
2914 #include "unchecked_optional_access_test
.h
"
2916 void target(bool b, $ns::$optional<int> opt) {
2917 if (opt.has_value() != b) {
2925 ExpectDiagnosticsFor(R
"(
2926 #include "unchecked_optional_access_test
.h
"
2928 void target(bool b) {
2929 $ns::$optional<int> opt1 = $ns::nullopt;
2930 $ns::$optional<int> opt2;
2932 opt2 = $ns::nullopt;
2934 opt2 = $ns::nullopt;
2936 if (opt2.has_value()) {
2943 TEST_P(UncheckedOptionalAccessTest
, JoinDistinctValues
) {
2944 ExpectDiagnosticsFor(
2946 #include "unchecked_optional_access_test
.h
"
2948 void target(bool b) {
2949 $ns::$optional<int> opt;
2951 opt = Make<$ns::$optional<int>>();
2953 opt = Make<$ns::$optional<int>>();
2955 if (opt.has_value()) {
2958 opt.value(); // [[unsafe]]
2963 ExpectDiagnosticsFor(R
"code(
2964 #include "unchecked_optional_access_test
.h
"
2966 void target(bool b) {
2967 $ns::$optional<int> opt;
2969 opt = Make<$ns::$optional<int>>();
2970 if (!opt.has_value()) return;
2972 opt = Make<$ns::$optional<int>>();
2973 if (!opt.has_value()) return;
2979 ExpectDiagnosticsFor(
2981 #include "unchecked_optional_access_test
.h
"
2983 void target(bool b) {
2984 $ns::$optional<int> opt;
2986 opt = Make<$ns::$optional<int>>();
2987 if (!opt.has_value()) return;
2989 opt = Make<$ns::$optional<int>>();
2991 opt.value(); // [[unsafe]]
2995 ExpectDiagnosticsFor(
2997 #include "unchecked_optional_access_test
.h
"
2999 void target(bool b) {
3000 $ns::$optional<int> opt;
3010 ExpectDiagnosticsFor(
3012 #include "unchecked_optional_access_test
.h
"
3014 void target(bool b) {
3015 $ns::$optional<int> opt;
3019 opt = Make<$ns::$optional<int>>();
3021 opt.value(); // [[unsafe]]
3026 TEST_P(UncheckedOptionalAccessTest
, AccessValueInLoop
) {
3027 ExpectDiagnosticsFor(R
"(
3028 #include "unchecked_optional_access_test
.h
"
3031 $ns::$optional<int> opt = 3;
3032 while (Make<bool>()) {
3039 TEST_P(UncheckedOptionalAccessTest
, ReassignValueInLoopWithCheckSafe
) {
3040 ExpectDiagnosticsFor(R
"(
3041 #include "unchecked_optional_access_test
.h
"
3044 $ns::$optional<int> opt = 3;
3045 while (Make<bool>()) {
3048 opt = Make<$ns::$optional<int>>();
3049 if (!opt.has_value()) return;
3055 TEST_P(UncheckedOptionalAccessTest
, ReassignValueInLoopNoCheckUnsafe
) {
3056 ExpectDiagnosticsFor(
3058 #include "unchecked_optional_access_test
.h
"
3061 $ns::$optional<int> opt = 3;
3062 while (Make<bool>()) {
3063 opt.value(); // [[unsafe]]
3065 opt = Make<$ns::$optional<int>>();
3071 TEST_P(UncheckedOptionalAccessTest
, ReassignValueInLoopToUnsetUnsafe
) {
3072 ExpectDiagnosticsFor(
3074 #include "unchecked_optional_access_test
.h
"
3077 $ns::$optional<int> opt = 3;
3078 while (Make<bool>())
3080 $ns::$optional<int> opt2 = $ns::nullopt;
3081 if (opt.has_value())
3082 opt2 = $ns::$optional<int>(3);
3083 opt2.value(); // [[unsafe]]
3088 TEST_P(UncheckedOptionalAccessTest
, ReassignValueInLoopToSetUnsafe
) {
3089 ExpectDiagnosticsFor(
3091 #include "unchecked_optional_access_test
.h
"
3094 $ns::$optional<int> opt = $ns::nullopt;
3095 while (Make<bool>())
3096 opt = $ns::$optional<int>(3);
3097 $ns::$optional<int> opt2 = $ns::nullopt;
3098 if (!opt.has_value())
3099 opt2 = $ns::$optional<int>(3);
3100 opt2.value(); // [[unsafe]]
3105 TEST_P(UncheckedOptionalAccessTest
, ReassignValueInLoopToUnknownUnsafe
) {
3106 ExpectDiagnosticsFor(
3108 #include "unchecked_optional_access_test
.h
"
3111 $ns::$optional<int> opt = $ns::nullopt;
3112 while (Make<bool>())
3113 opt = Make<$ns::$optional<int>>();
3114 $ns::$optional<int> opt2 = $ns::nullopt;
3115 if (!opt.has_value())
3116 opt2 = $ns::$optional<int>(3);
3117 opt2.value(); // [[unsafe]]
3122 TEST_P(UncheckedOptionalAccessTest
, ReassignValueInLoopBadConditionUnsafe
) {
3123 ExpectDiagnosticsFor(
3125 #include "unchecked_optional_access_test
.h
"
3128 $ns::$optional<int> opt = 3;
3129 while (Make<bool>()) {
3130 opt.value(); // [[unsafe]]
3132 opt = Make<$ns::$optional<int>>();
3133 if (!opt.has_value()) continue;
3139 TEST_P(UncheckedOptionalAccessTest
, StructuredBindingsFromStruct
) {
3140 ExpectDiagnosticsFor(R
"(
3141 #include "unchecked_optional_access_test
.h
"
3143 struct kv { $ns::$optional<int> opt; int x; };
3145 auto [contents, x] = Make<kv>();
3146 return contents ? *contents : x;
3150 ExpectDiagnosticsFor(R
"(
3151 #include "unchecked_optional_access_test
.h
"
3153 template <typename T1, typename T2>
3154 struct pair { T1 fst; T2 snd; };
3156 auto [contents, x] = Make<pair<$ns::$optional<int>, int>>();
3157 return contents ? *contents : x;
3162 TEST_P(UncheckedOptionalAccessTest
, StructuredBindingsFromTupleLikeType
) {
3163 ExpectDiagnosticsFor(R
"(
3164 #include "unchecked_optional_access_test
.h
"
3167 template <class> struct tuple_size;
3168 template <size_t, class> struct tuple_element;
3169 template <class...> class tuple;
3171 template <class... T>
3172 struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {};
3174 template <size_t I, class... T>
3175 struct tuple_element<I, tuple<T...>> {
3176 using type = __type_pack_element<I, T...>;
3179 template <class...> class tuple {};
3180 template <size_t I, class... T>
3181 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
3184 std::tuple<$ns::$optional<const char *>, int> get_opt();
3186 auto [content, ck] = get_opt();
3187 content ? *content : "";
3192 TEST_P(UncheckedOptionalAccessTest
, CtorInitializerNullopt
) {
3193 using namespace ast_matchers
;
3194 ExpectDiagnosticsFor(
3196 #include "unchecked_optional_access_test
.h
"
3199 Target(): opt($ns::nullopt) {
3200 opt.value(); // [[unsafe]]
3202 $ns::$optional<int> opt;
3205 cxxConstructorDecl(ofClass(hasName("Target"))));
3208 TEST_P(UncheckedOptionalAccessTest
, CtorInitializerValue
) {
3209 using namespace ast_matchers
;
3210 ExpectDiagnosticsFor(
3212 #include "unchecked_optional_access_test
.h
"
3218 $ns::$optional<int> opt;
3221 cxxConstructorDecl(ofClass(hasName("Target"))));
3224 // This is regression test, it shouldn't crash.
3225 TEST_P(UncheckedOptionalAccessTest
, Bitfield
) {
3226 using namespace ast_matchers
;
3227 ExpectDiagnosticsFor(
3229 #include "unchecked_optional_access_test
.h
"
3234 $ns::$optional<bool> v;
3242 TEST_P(UncheckedOptionalAccessTest
, LambdaParam
) {
3243 ExpectDiagnosticsForLambda(R
"(
3244 #include "unchecked_optional_access_test
.h
"
3247 []($ns::$optional<int> opt) {
3248 if (opt.has_value()) {
3251 opt.value(); // [[unsafe]]
3253 }(Make<$ns::$optional<int>>());
3258 TEST_P(UncheckedOptionalAccessTest
, LambdaCaptureByCopy
) {
3259 ExpectDiagnosticsForLambda(R
"(
3260 #include "unchecked_optional_access_test
.h
"
3262 void target($ns::$optional<int> opt) {
3264 if (opt.has_value()) {
3267 opt.value(); // [[unsafe]]
3274 TEST_P(UncheckedOptionalAccessTest
, LambdaCaptureByReference
) {
3275 ExpectDiagnosticsForLambda(R
"(
3276 #include "unchecked_optional_access_test
.h
"
3278 void target($ns::$optional<int> opt) {
3280 if (opt.has_value()) {
3283 opt.value(); // [[unsafe]]
3290 TEST_P(UncheckedOptionalAccessTest
, LambdaCaptureWithInitializer
) {
3291 ExpectDiagnosticsForLambda(R
"(
3292 #include "unchecked_optional_access_test
.h
"
3294 void target($ns::$optional<int> opt) {
3296 if (opt2.has_value()) {
3299 opt2.value(); // [[unsafe]]
3306 TEST_P(UncheckedOptionalAccessTest
, LambdaCaptureByCopyImplicit
) {
3307 ExpectDiagnosticsForLambda(R
"(
3308 #include "unchecked_optional_access_test
.h
"
3310 void target($ns::$optional<int> opt) {
3312 if (opt.has_value()) {
3315 opt.value(); // [[unsafe]]
3322 TEST_P(UncheckedOptionalAccessTest
, LambdaCaptureByReferenceImplicit
) {
3323 ExpectDiagnosticsForLambda(R
"(
3324 #include "unchecked_optional_access_test
.h
"
3326 void target($ns::$optional<int> opt) {
3328 if (opt.has_value()) {
3331 opt.value(); // [[unsafe]]
3338 TEST_P(UncheckedOptionalAccessTest
, LambdaCaptureThis
) {
3339 ExpectDiagnosticsForLambda(R
"(
3340 #include "unchecked_optional_access_test
.h
"
3343 $ns::$optional<int> opt;
3347 if (opt.has_value()) {
3350 opt.value(); // [[unsafe]]
3358 TEST_P(UncheckedOptionalAccessTest
, LambdaCaptureStateNotPropagated
) {
3359 // We can't propagate information from the surrounding context.
3360 ExpectDiagnosticsForLambda(R
"(
3361 #include "unchecked_optional_access_test
.h
"
3363 void target($ns::$optional<int> opt) {
3364 if (opt.has_value()) {
3366 opt.value(); // [[unsafe]]
3372 // FIXME: Add support for:
3373 // - constructors (copy, move)
3374 // - assignment operators (default, copy, move)
3375 // - invalidation (passing optional by non-const reference/pointer)