[ELF] Replace inExpr with lexState. NFC
[llvm-project.git] / clang / unittests / Analysis / FlowSensitive / UncheckedOptionalAccessModelTest.cpp
blob19c3ff49eab27e2be766699467f8f5ea93292d5a
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.
10 #include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h"
11 #include "TestingSupport.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Frontend/TextDiagnostic.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "llvm/ADT/DenseSet.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/Support/Error.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include <optional>
23 #include <string>
24 #include <utility>
25 #include <vector>
27 using namespace clang;
28 using namespace dataflow;
29 using namespace test;
31 using ::testing::ContainerEq;
33 // FIXME: Move header definitions in separate file(s).
34 static constexpr char CSDtdDefHeader[] = R"(
35 #ifndef CSTDDEF_H
36 #define CSTDDEF_H
38 namespace std {
40 typedef decltype(sizeof(char)) size_t;
42 using nullptr_t = decltype(nullptr);
44 } // namespace std
46 #endif // CSTDDEF_H
47 )";
49 static constexpr char StdTypeTraitsHeader[] = R"(
50 #ifndef STD_TYPE_TRAITS_H
51 #define STD_TYPE_TRAITS_H
53 #include "cstddef.h"
55 namespace std {
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;};
69 template <class T>
70 using remove_reference_t = typename remove_reference<T>::type;
72 template <class T>
73 struct remove_extent {
74 typedef T type;
77 template <class T>
78 struct remove_extent<T[]> {
79 typedef T type;
82 template <class T, size_t N>
83 struct remove_extent<T[N]> {
84 typedef T type;
87 template <class T>
88 struct is_array : false_type {};
90 template <class T>
91 struct is_array<T[]> : true_type {};
93 template <class T, size_t N>
94 struct is_array<T[N]> : true_type {};
96 template <class>
97 struct is_function : false_type {};
99 template <class Ret, class... Args>
100 struct is_function<Ret(Args...)> : true_type {};
102 namespace detail {
104 template <class T>
105 struct type_identity {
106 using type = T;
107 }; // or use type_identity (since C++20)
109 template <class T>
110 auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>;
111 template <class T>
112 auto try_add_pointer(...) -> type_identity<T>;
114 } // namespace detail
116 template <class T>
117 struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
119 template <bool B, class T, class F>
120 struct conditional {
121 typedef T type;
124 template <class T, class F>
125 struct conditional<false, T, F> {
126 typedef F type;
129 template <class T>
130 struct remove_cv {
131 typedef T type;
133 template <class T>
134 struct remove_cv<const T> {
135 typedef T type;
137 template <class T>
138 struct remove_cv<volatile T> {
139 typedef T type;
141 template <class T>
142 struct remove_cv<const volatile T> {
143 typedef T type;
146 template <class T>
147 using remove_cv_t = typename remove_cv<T>::type;
149 template <class T>
150 struct decay {
151 private:
152 typedef typename remove_reference<T>::type U;
154 public:
155 typedef typename conditional<
156 is_array<U>::value, typename remove_extent<U>::type*,
157 typename conditional<is_function<U>::value, typename add_pointer<U>::type,
158 typename remove_cv<U>::type>::type>::type type;
161 template <bool B, class T = void>
162 struct enable_if {};
164 template <class T>
165 struct enable_if<true, T> {
166 typedef T type;
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 {};
175 template <class T>
176 struct is_same<T, T> : true_type {};
178 template <class T>
179 struct is_void : is_same<void, typename remove_cv<T>::type> {};
181 namespace detail {
183 template <class T>
184 auto try_add_lvalue_reference(int) -> type_identity<T&>;
185 template <class T>
186 auto try_add_lvalue_reference(...) -> type_identity<T>;
188 template <class T>
189 auto try_add_rvalue_reference(int) -> type_identity<T&&>;
190 template <class T>
191 auto try_add_rvalue_reference(...) -> type_identity<T>;
193 } // namespace detail
195 template <class T>
196 struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {
199 template <class T>
200 struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {
203 template <class T>
204 typename add_rvalue_reference<T>::type declval() noexcept;
206 namespace detail {
208 template <class T>
209 auto test_returnable(int)
210 -> decltype(void(static_cast<T (*)()>(nullptr)), true_type{});
211 template <class>
212 auto test_returnable(...) -> false_type;
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>(
227 0))::value) ||
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;
233 template <class...>
234 using void_t = void;
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...>
241 : true_type {};
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;
249 template <class _Tp>
250 struct __uncvref {
251 typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type;
254 template <class _Tp>
255 using __uncvref_t = typename __uncvref<_Tp>::type;
257 template <bool _Val>
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)>;
266 template <bool>
267 struct _MetaBase;
268 template <>
269 struct _MetaBase<true> {
270 template <class _Tp, class _Up>
271 using _SelectImpl = _Tp;
272 template <template <class...> class _FirstFn, template <class...> class,
273 class... _Args>
274 using _SelectApplyImpl = _FirstFn<_Args...>;
275 template <class _First, class...>
276 using _FirstImpl = _First;
277 template <class, class _Second, class...>
278 using _SecondImpl = _Second;
279 template <class _Result, class _First, class... _Rest>
280 using _OrImpl =
281 typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>::
282 template _OrImpl<_First, _Rest...>;
285 template <>
286 struct _MetaBase<false> {
287 template <class _Tp, class _Up>
288 using _SelectImpl = _Up;
289 template <template <class...> class, template <class...> class _SecondFn,
290 class... _Args>
291 using _SelectApplyImpl = _SecondFn<_Args...>;
292 template <class _Result, class...>
293 using _OrImpl = _Result;
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;
306 template <class...>
307 using __expand_to_true = true_type;
308 template <class... _Pred>
309 __expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int);
310 template <class...>
311 false_type __and_helper(...);
312 template <class... _Pred>
313 using _And = decltype(__and_helper<_Pred...>(0));
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; }
321 template <class...>
322 static constexpr bool __enable_explicit() {
323 return false;
325 template <class...>
326 static constexpr bool __enable_implicit() {
327 return false;
331 template <typename, typename _Tp>
332 struct __select_2nd {
333 typedef _Tp type;
335 template <class _Tp, class _Arg>
336 typename __select_2nd<decltype((declval<_Tp>() = declval<_Arg>())),
337 true_type>::type
338 __is_assignable_test(int);
339 template <class, class>
340 false_type __is_assignable_test(...);
341 template <class _Tp, class _Arg,
342 bool = is_void<_Tp>::value || is_void<_Arg>::value>
343 struct __is_assignable_imp
344 : public decltype((__is_assignable_test<_Tp, _Arg>(0))) {};
345 template <class _Tp, class _Arg>
346 struct __is_assignable_imp<_Tp, _Arg, true> : public false_type {};
347 template <class _Tp, class _Arg>
348 struct is_assignable : public __is_assignable_imp<_Tp, _Arg> {};
350 template <class _Tp>
351 struct __libcpp_is_integral : public false_type {};
352 template <>
353 struct __libcpp_is_integral<bool> : public true_type {};
354 template <>
355 struct __libcpp_is_integral<char> : public true_type {};
356 template <>
357 struct __libcpp_is_integral<signed char> : public true_type {};
358 template <>
359 struct __libcpp_is_integral<unsigned char> : public true_type {};
360 template <>
361 struct __libcpp_is_integral<wchar_t> : public true_type {};
362 template <>
363 struct __libcpp_is_integral<short> : public true_type {}; // NOLINT
364 template <>
365 struct __libcpp_is_integral<unsigned short> : public true_type {}; // NOLINT
366 template <>
367 struct __libcpp_is_integral<int> : public true_type {};
368 template <>
369 struct __libcpp_is_integral<unsigned int> : public true_type {};
370 template <>
371 struct __libcpp_is_integral<long> : public true_type {}; // NOLINT
372 template <>
373 struct __libcpp_is_integral<unsigned long> : public true_type {}; // NOLINT
374 template <>
375 struct __libcpp_is_integral<long long> : public true_type {}; // NOLINT
376 template <> // NOLINTNEXTLINE
377 struct __libcpp_is_integral<unsigned long long> : public true_type {};
378 template <class _Tp>
379 struct is_integral
380 : public __libcpp_is_integral<typename remove_cv<_Tp>::type> {};
382 template <class _Tp>
383 struct __libcpp_is_floating_point : public false_type {};
384 template <>
385 struct __libcpp_is_floating_point<float> : public true_type {};
386 template <>
387 struct __libcpp_is_floating_point<double> : public true_type {};
388 template <>
389 struct __libcpp_is_floating_point<long double> : public true_type {};
390 template <class _Tp>
391 struct is_floating_point
392 : public __libcpp_is_floating_point<typename remove_cv<_Tp>::type> {};
394 template <class _Tp>
395 struct is_arithmetic
396 : public integral_constant<bool, is_integral<_Tp>::value ||
397 is_floating_point<_Tp>::value> {};
399 template <class _Tp>
400 struct __libcpp_is_pointer : public false_type {};
401 template <class _Tp>
402 struct __libcpp_is_pointer<_Tp*> : public true_type {};
403 template <class _Tp>
404 struct is_pointer : public __libcpp_is_pointer<typename remove_cv<_Tp>::type> {
407 template <class _Tp>
408 struct __libcpp_is_member_pointer : public false_type {};
409 template <class _Tp, class _Up>
410 struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type {};
411 template <class _Tp>
412 struct is_member_pointer
413 : public __libcpp_is_member_pointer<typename remove_cv<_Tp>::type> {};
415 template <class _Tp>
416 struct __libcpp_union : public false_type {};
417 template <class _Tp>
418 struct is_union : public __libcpp_union<typename remove_cv<_Tp>::type> {};
420 template <class T>
421 struct is_reference : false_type {};
422 template <class T>
423 struct is_reference<T&> : true_type {};
424 template <class T>
425 struct is_reference<T&&> : true_type {};
427 template <class T>
428 inline constexpr bool is_reference_v = is_reference<T>::value;
430 struct __two {
431 char __lx[2];
434 namespace __is_class_imp {
435 template <class _Tp>
436 char __test(int _Tp::*);
437 template <class _Tp>
438 __two __test(...);
439 } // namespace __is_class_imp
440 template <class _Tp>
441 struct is_class
442 : public integral_constant<bool,
443 sizeof(__is_class_imp::__test<_Tp>(0)) == 1 &&
444 !is_union<_Tp>::value> {};
446 template <class _Tp>
447 struct __is_nullptr_t_impl : public false_type {};
448 template <>
449 struct __is_nullptr_t_impl<nullptr_t> : public true_type {};
450 template <class _Tp>
451 struct __is_nullptr_t
452 : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
453 template <class _Tp>
454 struct is_null_pointer
455 : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
457 template <class _Tp>
458 struct is_enum
459 : public integral_constant<
460 bool, !is_void<_Tp>::value && !is_integral<_Tp>::value &&
461 !is_floating_point<_Tp>::value && !is_array<_Tp>::value &&
462 !is_pointer<_Tp>::value && !is_reference<_Tp>::value &&
463 !is_member_pointer<_Tp>::value && !is_union<_Tp>::value &&
464 !is_class<_Tp>::value && !is_function<_Tp>::value> {};
466 template <class _Tp>
467 struct is_scalar
468 : public integral_constant<
469 bool, is_arithmetic<_Tp>::value || is_member_pointer<_Tp>::value ||
470 is_pointer<_Tp>::value || __is_nullptr_t<_Tp>::value ||
471 is_enum<_Tp>::value> {};
472 template <>
473 struct is_scalar<nullptr_t> : public true_type {};
475 } // namespace std
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"
486 namespace absl {
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;
504 } // namespace absl
506 #endif // ABSL_TYPE_TRAITS_H
509 static constexpr char StdStringHeader[] = R"(
510 #ifndef STRING_H
511 #define STRING_H
513 namespace std {
515 struct string {
516 string(const char*);
517 ~string();
518 bool empty();
520 bool operator!=(const string &LHS, const char *RHS);
522 } // namespace std
524 #endif // STRING_H
527 static constexpr char StdUtilityHeader[] = R"(
528 #ifndef UTILITY_H
529 #define UTILITY_H
531 #include "std_type_traits.h"
533 namespace std {
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;
541 } // namespace std
543 #endif // UTILITY_H
546 static constexpr char StdInitializerListHeader[] = R"(
547 #ifndef INITIALIZER_LIST_H
548 #define INITIALIZER_LIST_H
550 namespace std {
552 template <typename T>
553 class initializer_list {
554 public:
555 const T *a, *b;
556 initializer_list() noexcept;
559 } // namespace std
561 #endif // INITIALIZER_LIST_H
564 static constexpr char StdOptionalHeader[] = R"(
565 #include "std_initializer_list.h"
566 #include "std_type_traits.h"
567 #include "std_utility.h"
569 namespace std {
571 struct in_place_t {};
572 constexpr in_place_t in_place;
574 struct nullopt_t {
575 constexpr explicit nullopt_t() {}
577 constexpr nullopt_t nullopt;
579 template <class _Tp>
580 struct __optional_destruct_base {
581 constexpr void reset() noexcept;
584 template <class _Tp>
585 struct __optional_storage_base : __optional_destruct_base<_Tp> {
586 constexpr bool has_value() const noexcept;
589 template <typename _Tp>
590 class optional : private __optional_storage_base<_Tp> {
591 using __base = __optional_storage_base<_Tp>;
593 public:
594 using value_type = _Tp;
596 private:
597 struct _CheckOptionalArgsConstructor {
598 template <class _Up>
599 static constexpr bool __enable_implicit() {
600 return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
603 template <class _Up>
604 static constexpr bool __enable_explicit() {
605 return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
608 template <class _Up>
609 using _CheckOptionalArgsCtor =
610 _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value &&
611 _IsNotSame<__uncvref_t<_Up>, optional>::value,
612 _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>;
613 template <class _QualUp>
614 struct _CheckOptionalLikeConstructor {
615 template <class _Up, class _Opt = optional<_Up>>
616 using __check_constructible_from_opt =
617 _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>,
618 is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>,
619 is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>,
620 is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>;
621 template <class _Up, class _QUp = _QualUp>
622 static constexpr bool __enable_implicit() {
623 return is_convertible<_QUp, _Tp>::value &&
624 !__check_constructible_from_opt<_Up>::value;
626 template <class _Up, class _QUp = _QualUp>
627 static constexpr bool __enable_explicit() {
628 return !is_convertible<_QUp, _Tp>::value &&
629 !__check_constructible_from_opt<_Up>::value;
633 template <class _Up, class _QualUp>
634 using _CheckOptionalLikeCtor =
635 _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value,
636 _CheckOptionalLikeConstructor<_QualUp>,
637 __check_tuple_constructor_fail>;
640 template <class _Up, class _QualUp>
641 using _CheckOptionalLikeAssign = _If<
642 _And<
643 _IsNotSame<_Up, _Tp>,
644 is_constructible<_Tp, _QualUp>,
645 is_assignable<_Tp&, _QualUp>
646 >::value,
647 _CheckOptionalLikeConstructor<_QualUp>,
648 __check_tuple_constructor_fail
651 public:
652 constexpr optional() noexcept {}
653 constexpr optional(const optional&) = default;
654 constexpr optional(optional&&) = default;
655 constexpr optional(nullopt_t) noexcept {}
657 template <
658 class _InPlaceT, class... _Args,
659 class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>,
660 is_constructible<value_type, _Args...>>::value>>
661 constexpr explicit optional(_InPlaceT, _Args&&... __args);
663 template <class _Up, class... _Args,
664 class = enable_if_t<is_constructible_v<
665 value_type, initializer_list<_Up>&, _Args...>>>
666 constexpr explicit optional(in_place_t, initializer_list<_Up> __il,
667 _Args&&... __args);
669 template <
670 class _Up = value_type,
671 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(),
672 int> = 0>
673 constexpr optional(_Up&& __v);
675 template <
676 class _Up,
677 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(),
678 int> = 0>
679 constexpr explicit optional(_Up&& __v);
681 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
682 template __enable_implicit<_Up>(),
683 int> = 0>
684 constexpr optional(const optional<_Up>& __v);
686 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
687 template __enable_explicit<_Up>(),
688 int> = 0>
689 constexpr explicit optional(const optional<_Up>& __v);
691 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
692 template __enable_implicit<_Up>(),
693 int> = 0>
694 constexpr optional(optional<_Up>&& __v);
696 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
697 template __enable_explicit<_Up>(),
698 int> = 0>
699 constexpr explicit optional(optional<_Up>&& __v);
701 constexpr optional& operator=(nullopt_t) noexcept;
703 optional& operator=(const optional&);
705 optional& operator=(optional&&);
707 template <class _Up = value_type,
708 class = enable_if_t<_And<_IsNotSame<__uncvref_t<_Up>, optional>,
709 _Or<_IsNotSame<__uncvref_t<_Up>, value_type>,
710 _Not<is_scalar<value_type>>>,
711 is_constructible<value_type, _Up>,
712 is_assignable<value_type&, _Up>>::value>>
713 constexpr optional& operator=(_Up&& __v);
715 template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>::
716 template __enable_assign<_Up>(),
717 int> = 0>
718 constexpr optional& operator=(const optional<_Up>& __v);
720 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
721 template __enable_assign<_Up>(),
722 int> = 0>
723 constexpr optional& operator=(optional<_Up>&& __v);
725 const _Tp& operator*() const&;
726 _Tp& operator*() &;
727 const _Tp&& operator*() const&&;
728 _Tp&& operator*() &&;
730 const _Tp* operator->() const;
731 _Tp* operator->();
733 const _Tp& value() const&;
734 _Tp& value() &;
735 const _Tp&& value() const&&;
736 _Tp&& value() &&;
738 template <typename U>
739 constexpr _Tp value_or(U&& v) const&;
740 template <typename U>
741 _Tp value_or(U&& v) &&;
743 template <typename... Args>
744 _Tp& emplace(Args&&... args);
746 template <typename U, typename... Args>
747 _Tp& emplace(std::initializer_list<U> ilist, Args&&... args);
749 using __base::reset;
751 constexpr explicit operator bool() const noexcept;
752 using __base::has_value;
754 constexpr void swap(optional& __opt) noexcept;
757 template <typename T>
758 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
760 template <typename T, typename... Args>
761 constexpr optional<T> make_optional(Args&&... args);
763 template <typename T, typename U, typename... Args>
764 constexpr optional<T> make_optional(std::initializer_list<U> il,
765 Args&&... args);
767 template <typename T, typename U>
768 constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs);
769 template <typename T, typename U>
770 constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs);
772 template <typename T>
773 constexpr bool operator==(const optional<T> &opt, nullopt_t);
775 // C++20 and later do not define the following overloads because they are
776 // provided by rewritten candidates instead.
777 #if __cplusplus < 202002L
778 template <typename T>
779 constexpr bool operator==(nullopt_t, const optional<T> &opt);
780 template <typename T>
781 constexpr bool operator!=(const optional<T> &opt, nullopt_t);
782 template <typename T>
783 constexpr bool operator!=(nullopt_t, const optional<T> &opt);
784 #endif // __cplusplus < 202002L
786 template <typename T, typename U>
787 constexpr bool operator==(const optional<T> &opt, const U &value);
788 template <typename T, typename U>
789 constexpr bool operator==(const T &value, const optional<U> &opt);
790 template <typename T, typename U>
791 constexpr bool operator!=(const optional<T> &opt, const U &value);
792 template <typename T, typename U>
793 constexpr bool operator!=(const T &value, const optional<U> &opt);
795 } // namespace std
798 static constexpr char AbslOptionalHeader[] = R"(
799 #include "absl_type_traits.h"
800 #include "std_initializer_list.h"
801 #include "std_type_traits.h"
802 #include "std_utility.h"
804 namespace absl {
806 struct nullopt_t {
807 constexpr explicit nullopt_t() {}
809 constexpr nullopt_t nullopt;
811 struct in_place_t {};
812 constexpr in_place_t in_place;
814 template <typename T>
815 class optional;
817 namespace optional_internal {
819 template <typename T, typename U>
820 struct is_constructible_convertible_from_optional
821 : std::integral_constant<
822 bool, std::is_constructible<T, optional<U>&>::value ||
823 std::is_constructible<T, optional<U>&&>::value ||
824 std::is_constructible<T, const optional<U>&>::value ||
825 std::is_constructible<T, const optional<U>&&>::value ||
826 std::is_convertible<optional<U>&, T>::value ||
827 std::is_convertible<optional<U>&&, T>::value ||
828 std::is_convertible<const optional<U>&, T>::value ||
829 std::is_convertible<const optional<U>&&, T>::value> {};
831 template <typename T, typename U>
832 struct is_constructible_convertible_assignable_from_optional
833 : std::integral_constant<
834 bool, is_constructible_convertible_from_optional<T, U>::value ||
835 std::is_assignable<T&, optional<U>&>::value ||
836 std::is_assignable<T&, optional<U>&&>::value ||
837 std::is_assignable<T&, const optional<U>&>::value ||
838 std::is_assignable<T&, const optional<U>&&>::value> {};
840 } // namespace optional_internal
842 template <typename T>
843 class optional {
844 public:
845 constexpr optional() noexcept;
847 constexpr optional(nullopt_t) noexcept;
849 optional(const optional&) = default;
851 optional(optional&&) = default;
853 template <typename InPlaceT, typename... Args,
854 absl::enable_if_t<absl::conjunction<
855 std::is_same<InPlaceT, in_place_t>,
856 std::is_constructible<T, Args&&...>>::value>* = nullptr>
857 constexpr explicit optional(InPlaceT, Args&&... args);
859 template <typename U, typename... Args,
860 typename = typename std::enable_if<std::is_constructible<
861 T, std::initializer_list<U>&, Args&&...>::value>::type>
862 constexpr explicit optional(in_place_t, std::initializer_list<U> il,
863 Args&&... args);
865 template <
866 typename U = T,
867 typename std::enable_if<
868 absl::conjunction<absl::negation<std::is_same<
869 in_place_t, typename std::decay<U>::type>>,
870 absl::negation<std::is_same<
871 optional<T>, typename std::decay<U>::type>>,
872 std::is_convertible<U&&, T>,
873 std::is_constructible<T, U&&>>::value,
874 bool>::type = false>
875 constexpr optional(U&& v);
877 template <
878 typename U = T,
879 typename std::enable_if<
880 absl::conjunction<absl::negation<std::is_same<
881 in_place_t, typename std::decay<U>::type>>,
882 absl::negation<std::is_same<
883 optional<T>, typename std::decay<U>::type>>,
884 absl::negation<std::is_convertible<U&&, T>>,
885 std::is_constructible<T, U&&>>::value,
886 bool>::type = false>
887 explicit constexpr optional(U&& v);
889 template <typename U,
890 typename std::enable_if<
891 absl::conjunction<
892 absl::negation<std::is_same<T, U>>,
893 std::is_constructible<T, const U&>,
894 absl::negation<
895 optional_internal::
896 is_constructible_convertible_from_optional<T, U>>,
897 std::is_convertible<const U&, T>>::value,
898 bool>::type = false>
899 optional(const optional<U>& rhs);
901 template <typename U,
902 typename std::enable_if<
903 absl::conjunction<
904 absl::negation<std::is_same<T, U>>,
905 std::is_constructible<T, const U&>,
906 absl::negation<
907 optional_internal::
908 is_constructible_convertible_from_optional<T, U>>,
909 absl::negation<std::is_convertible<const U&, T>>>::value,
910 bool>::type = false>
911 explicit optional(const optional<U>& rhs);
913 template <
914 typename U,
915 typename std::enable_if<
916 absl::conjunction<
917 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
918 absl::negation<
919 optional_internal::is_constructible_convertible_from_optional<
920 T, U>>,
921 std::is_convertible<U&&, T>>::value,
922 bool>::type = false>
923 optional(optional<U>&& rhs);
925 template <
926 typename U,
927 typename std::enable_if<
928 absl::conjunction<
929 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
930 absl::negation<
931 optional_internal::is_constructible_convertible_from_optional<
932 T, U>>,
933 absl::negation<std::is_convertible<U&&, T>>>::value,
934 bool>::type = false>
935 explicit optional(optional<U>&& rhs);
937 optional& operator=(nullopt_t) noexcept;
939 optional& operator=(const optional& src);
941 optional& operator=(optional&& src);
943 template <
944 typename U = T,
945 typename = typename std::enable_if<absl::conjunction<
946 absl::negation<
947 std::is_same<optional<T>, typename std::decay<U>::type>>,
948 absl::negation<
949 absl::conjunction<std::is_scalar<T>,
950 std::is_same<T, typename std::decay<U>::type>>>,
951 std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
952 optional& operator=(U&& v);
954 template <
955 typename U,
956 typename = typename std::enable_if<absl::conjunction<
957 absl::negation<std::is_same<T, U>>,
958 std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
959 absl::negation<
960 optional_internal::
961 is_constructible_convertible_assignable_from_optional<
962 T, U>>>::value>::type>
963 optional& operator=(const optional<U>& rhs);
965 template <typename U,
966 typename = typename std::enable_if<absl::conjunction<
967 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
968 std::is_assignable<T&, U>,
969 absl::negation<
970 optional_internal::
971 is_constructible_convertible_assignable_from_optional<
972 T, U>>>::value>::type>
973 optional& operator=(optional<U>&& rhs);
975 const T& operator*() const&;
976 T& operator*() &;
977 const T&& operator*() const&&;
978 T&& operator*() &&;
980 const T* operator->() const;
981 T* operator->();
983 const T& value() const&;
984 T& value() &;
985 const T&& value() const&&;
986 T&& value() &&;
988 template <typename U>
989 constexpr T value_or(U&& v) const&;
990 template <typename U>
991 T value_or(U&& v) &&;
993 template <typename... Args>
994 T& emplace(Args&&... args);
996 template <typename U, typename... Args>
997 T& emplace(std::initializer_list<U> ilist, Args&&... args);
999 void reset() noexcept;
1001 constexpr explicit operator bool() const noexcept;
1002 constexpr bool has_value() const noexcept;
1004 void swap(optional& rhs) noexcept;
1007 template <typename T>
1008 constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
1010 template <typename T, typename... Args>
1011 constexpr optional<T> make_optional(Args&&... args);
1013 template <typename T, typename U, typename... Args>
1014 constexpr optional<T> make_optional(std::initializer_list<U> il,
1015 Args&&... args);
1017 template <typename T, typename U>
1018 constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs);
1019 template <typename T, typename U>
1020 constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs);
1022 template <typename T>
1023 constexpr bool operator==(const optional<T> &opt, nullopt_t);
1024 template <typename T>
1025 constexpr bool operator==(nullopt_t, const optional<T> &opt);
1026 template <typename T>
1027 constexpr bool operator!=(const optional<T> &opt, nullopt_t);
1028 template <typename T>
1029 constexpr bool operator!=(nullopt_t, const optional<T> &opt);
1031 template <typename T, typename U>
1032 constexpr bool operator==(const optional<T> &opt, const U &value);
1033 template <typename T, typename U>
1034 constexpr bool operator==(const T &value, const optional<U> &opt);
1035 template <typename T, typename U>
1036 constexpr bool operator!=(const optional<T> &opt, const U &value);
1037 template <typename T, typename U>
1038 constexpr bool operator!=(const T &value, const optional<U> &opt);
1040 } // namespace absl
1043 static constexpr char BaseOptionalHeader[] = R"(
1044 #include "std_initializer_list.h"
1045 #include "std_type_traits.h"
1046 #include "std_utility.h"
1048 namespace base {
1050 struct in_place_t {};
1051 constexpr in_place_t in_place;
1053 struct nullopt_t {
1054 constexpr explicit nullopt_t() {}
1056 constexpr nullopt_t nullopt;
1058 template <typename T>
1059 class Optional;
1061 namespace internal {
1063 template <typename T>
1064 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
1066 template <typename T, typename U>
1067 struct IsConvertibleFromOptional
1068 : std::integral_constant<
1069 bool, std::is_constructible<T, Optional<U>&>::value ||
1070 std::is_constructible<T, const Optional<U>&>::value ||
1071 std::is_constructible<T, Optional<U>&&>::value ||
1072 std::is_constructible<T, const Optional<U>&&>::value ||
1073 std::is_convertible<Optional<U>&, T>::value ||
1074 std::is_convertible<const Optional<U>&, T>::value ||
1075 std::is_convertible<Optional<U>&&, T>::value ||
1076 std::is_convertible<const Optional<U>&&, T>::value> {};
1078 template <typename T, typename U>
1079 struct IsAssignableFromOptional
1080 : std::integral_constant<
1081 bool, IsConvertibleFromOptional<T, U>::value ||
1082 std::is_assignable<T&, Optional<U>&>::value ||
1083 std::is_assignable<T&, const Optional<U>&>::value ||
1084 std::is_assignable<T&, Optional<U>&&>::value ||
1085 std::is_assignable<T&, const Optional<U>&&>::value> {};
1087 } // namespace internal
1089 template <typename T>
1090 class Optional {
1091 public:
1092 using value_type = T;
1094 constexpr Optional() = default;
1095 constexpr Optional(const Optional& other) noexcept = default;
1096 constexpr Optional(Optional&& other) noexcept = default;
1098 constexpr Optional(nullopt_t);
1100 template <typename U,
1101 typename std::enable_if<
1102 std::is_constructible<T, const U&>::value &&
1103 !internal::IsConvertibleFromOptional<T, U>::value &&
1104 std::is_convertible<const U&, T>::value,
1105 bool>::type = false>
1106 Optional(const Optional<U>& other) noexcept;
1108 template <typename U,
1109 typename std::enable_if<
1110 std::is_constructible<T, const U&>::value &&
1111 !internal::IsConvertibleFromOptional<T, U>::value &&
1112 !std::is_convertible<const U&, T>::value,
1113 bool>::type = false>
1114 explicit Optional(const Optional<U>& other) noexcept;
1116 template <typename U,
1117 typename std::enable_if<
1118 std::is_constructible<T, U&&>::value &&
1119 !internal::IsConvertibleFromOptional<T, U>::value &&
1120 std::is_convertible<U&&, T>::value,
1121 bool>::type = false>
1122 Optional(Optional<U>&& other) noexcept;
1124 template <typename U,
1125 typename std::enable_if<
1126 std::is_constructible<T, U&&>::value &&
1127 !internal::IsConvertibleFromOptional<T, U>::value &&
1128 !std::is_convertible<U&&, T>::value,
1129 bool>::type = false>
1130 explicit Optional(Optional<U>&& other) noexcept;
1132 template <class... Args>
1133 constexpr explicit Optional(in_place_t, Args&&... args);
1135 template <class U, class... Args,
1136 class = typename std::enable_if<std::is_constructible<
1137 value_type, std::initializer_list<U>&, Args...>::value>::type>
1138 constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
1139 Args&&... args);
1141 template <
1142 typename U = value_type,
1143 typename std::enable_if<
1144 std::is_constructible<T, U&&>::value &&
1145 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1146 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1147 std::is_convertible<U&&, T>::value,
1148 bool>::type = false>
1149 constexpr Optional(U&& value);
1151 template <
1152 typename U = value_type,
1153 typename std::enable_if<
1154 std::is_constructible<T, U&&>::value &&
1155 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1156 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1157 !std::is_convertible<U&&, T>::value,
1158 bool>::type = false>
1159 constexpr explicit Optional(U&& value);
1161 Optional& operator=(const Optional& other) noexcept;
1163 Optional& operator=(Optional&& other) noexcept;
1165 Optional& operator=(nullopt_t);
1167 template <typename U>
1168 typename std::enable_if<
1169 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1170 std::is_constructible<T, U>::value &&
1171 std::is_assignable<T&, U>::value &&
1172 (!std::is_scalar<T>::value ||
1173 !std::is_same<typename std::decay<U>::type, T>::value),
1174 Optional&>::type
1175 operator=(U&& value) noexcept;
1177 template <typename U>
1178 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1179 std::is_constructible<T, const U&>::value &&
1180 std::is_assignable<T&, const U&>::value,
1181 Optional&>::type
1182 operator=(const Optional<U>& other) noexcept;
1184 template <typename U>
1185 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1186 std::is_constructible<T, U>::value &&
1187 std::is_assignable<T&, U>::value,
1188 Optional&>::type
1189 operator=(Optional<U>&& other) noexcept;
1191 const T& operator*() const&;
1192 T& operator*() &;
1193 const T&& operator*() const&&;
1194 T&& operator*() &&;
1196 const T* operator->() const;
1197 T* operator->();
1199 const T& value() const&;
1200 T& value() &;
1201 const T&& value() const&&;
1202 T&& value() &&;
1204 template <typename U>
1205 constexpr T value_or(U&& v) const&;
1206 template <typename U>
1207 T value_or(U&& v) &&;
1209 template <typename... Args>
1210 T& emplace(Args&&... args);
1212 template <typename U, typename... Args>
1213 T& emplace(std::initializer_list<U> ilist, Args&&... args);
1215 void reset() noexcept;
1217 constexpr explicit operator bool() const noexcept;
1218 constexpr bool has_value() const noexcept;
1220 void swap(Optional& other);
1223 template <typename T>
1224 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v);
1226 template <typename T, typename... Args>
1227 constexpr Optional<T> make_optional(Args&&... args);
1229 template <typename T, typename U, typename... Args>
1230 constexpr Optional<T> make_optional(std::initializer_list<U> il,
1231 Args&&... args);
1233 template <typename T, typename U>
1234 constexpr bool operator==(const Optional<T> &lhs, const Optional<U> &rhs);
1235 template <typename T, typename U>
1236 constexpr bool operator!=(const Optional<T> &lhs, const Optional<U> &rhs);
1238 template <typename T>
1239 constexpr bool operator==(const Optional<T> &opt, nullopt_t);
1240 template <typename T>
1241 constexpr bool operator==(nullopt_t, const Optional<T> &opt);
1242 template <typename T>
1243 constexpr bool operator!=(const Optional<T> &opt, nullopt_t);
1244 template <typename T>
1245 constexpr bool operator!=(nullopt_t, const Optional<T> &opt);
1247 template <typename T, typename U>
1248 constexpr bool operator==(const Optional<T> &opt, const U &value);
1249 template <typename T, typename U>
1250 constexpr bool operator==(const T &value, const Optional<U> &opt);
1251 template <typename T, typename U>
1252 constexpr bool operator!=(const Optional<T> &opt, const U &value);
1253 template <typename T, typename U>
1254 constexpr bool operator!=(const T &value, const Optional<U> &opt);
1256 } // namespace base
1259 /// Replaces all occurrences of `Pattern` in `S` with `Replacement`.
1260 static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern,
1261 const std::string &Replacement) {
1262 size_t Pos = 0;
1263 while (true) {
1264 Pos = S.find(Pattern, Pos);
1265 if (Pos == std::string::npos)
1266 break;
1267 S.replace(Pos, Pattern.size(), Replacement);
1271 struct OptionalTypeIdentifier {
1272 std::string NamespaceName;
1273 std::string TypeName;
1276 static raw_ostream &operator<<(raw_ostream &OS,
1277 const OptionalTypeIdentifier &TypeId) {
1278 OS << TypeId.NamespaceName << "::" << TypeId.TypeName;
1279 return OS;
1282 class UncheckedOptionalAccessTest
1283 : public ::testing::TestWithParam<OptionalTypeIdentifier> {
1284 protected:
1285 void ExpectDiagnosticsFor(std::string SourceCode,
1286 bool IgnoreSmartPointerDereference = true) {
1287 ExpectDiagnosticsFor(SourceCode, ast_matchers::hasName("target"),
1288 IgnoreSmartPointerDereference);
1291 void ExpectDiagnosticsForLambda(std::string SourceCode,
1292 bool IgnoreSmartPointerDereference = true) {
1293 ExpectDiagnosticsFor(
1294 SourceCode,
1295 ast_matchers::hasDeclContext(
1296 ast_matchers::cxxRecordDecl(ast_matchers::isLambda())),
1297 IgnoreSmartPointerDereference);
1300 template <typename FuncDeclMatcher>
1301 void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher,
1302 bool IgnoreSmartPointerDereference = true) {
1303 // Run in C++17 and C++20 mode to cover differences in the AST between modes
1304 // (e.g. C++20 can contain `CXXRewrittenBinaryOperator`).
1305 for (const char *CxxMode : {"-std=c++17", "-std=c++20"})
1306 ExpectDiagnosticsFor(SourceCode, FuncMatcher, CxxMode,
1307 IgnoreSmartPointerDereference);
1310 template <typename FuncDeclMatcher>
1311 void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher,
1312 const char *CxxMode,
1313 bool IgnoreSmartPointerDereference) {
1314 ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName);
1315 ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName);
1317 std::vector<std::pair<std::string, std::string>> Headers;
1318 Headers.emplace_back("cstddef.h", CSDtdDefHeader);
1319 Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader);
1320 Headers.emplace_back("std_string.h", StdStringHeader);
1321 Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader);
1322 Headers.emplace_back("std_utility.h", StdUtilityHeader);
1323 Headers.emplace_back("std_optional.h", StdOptionalHeader);
1324 Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader);
1325 Headers.emplace_back("absl_optional.h", AbslOptionalHeader);
1326 Headers.emplace_back("base_optional.h", BaseOptionalHeader);
1327 Headers.emplace_back("unchecked_optional_access_test.h", R"(
1328 #include "absl_optional.h"
1329 #include "base_optional.h"
1330 #include "std_initializer_list.h"
1331 #include "std_optional.h"
1332 #include "std_string.h"
1333 #include "std_utility.h"
1335 template <typename T>
1336 T Make();
1337 )");
1338 UncheckedOptionalAccessModelOptions Options{IgnoreSmartPointerDereference};
1339 std::vector<SourceLocation> Diagnostics;
1340 llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
1341 AnalysisInputs<UncheckedOptionalAccessModel>(
1342 SourceCode, std::move(FuncMatcher),
1343 [](ASTContext &Ctx, Environment &Env) {
1344 return UncheckedOptionalAccessModel(Ctx, Env);
1346 .withDiagnosisCallbacks(
1347 {/*Before=*/[&Diagnostics,
1348 Diagnoser =
1349 UncheckedOptionalAccessDiagnoser(Options)](
1350 ASTContext &Ctx, const CFGElement &Elt,
1351 const TransferStateForDiagnostics<
1352 UncheckedOptionalAccessLattice>
1353 &State) mutable {
1354 auto EltDiagnostics = Diagnoser(Elt, Ctx, State);
1355 llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
1357 /*After=*/nullptr})
1358 .withASTBuildArgs(
1359 {"-fsyntax-only", CxxMode, "-Wno-undefined-inline"})
1360 .withASTBuildVirtualMappedFiles(
1361 tooling::FileContentMappings(Headers.begin(), Headers.end())),
1362 /*VerifyResults=*/[&Diagnostics](
1363 const llvm::DenseMap<unsigned, std::string>
1364 &Annotations,
1365 const AnalysisOutputs &AO) {
1366 llvm::DenseSet<unsigned> AnnotationLines;
1367 for (const auto &[Line, _] : Annotations) {
1368 AnnotationLines.insert(Line);
1370 auto &SrcMgr = AO.ASTCtx.getSourceManager();
1371 llvm::DenseSet<unsigned> DiagnosticLines;
1372 for (SourceLocation &Loc : Diagnostics) {
1373 unsigned Line = SrcMgr.getPresumedLineNumber(Loc);
1374 DiagnosticLines.insert(Line);
1375 if (!AnnotationLines.contains(Line)) {
1376 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
1377 new DiagnosticOptions());
1378 TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
1379 DiagOpts.get());
1380 TD.emitDiagnostic(FullSourceLoc(Loc, SrcMgr),
1381 DiagnosticsEngine::Error,
1382 "unexpected diagnostic", {}, {});
1386 EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines));
1388 if (Error)
1389 FAIL() << llvm::toString(std::move(Error));
1393 INSTANTIATE_TEST_SUITE_P(
1394 UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
1395 ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
1396 OptionalTypeIdentifier{"absl", "optional"},
1397 OptionalTypeIdentifier{"base", "Optional"}),
1398 [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
1399 return Info.param.NamespaceName;
1402 // Verifies that similarly-named types are ignored.
1403 TEST_P(UncheckedOptionalAccessTest, NonTrackedOptionalType) {
1404 ExpectDiagnosticsFor(
1406 namespace other {
1407 namespace $ns {
1408 template <typename T>
1409 struct $optional {
1410 T value();
1414 void target($ns::$optional<int> opt) {
1415 opt.value();
1418 )");
1421 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
1422 ExpectDiagnosticsFor(R"(
1423 void target() {
1424 (void)0;
1426 )");
1429 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
1430 ExpectDiagnosticsFor(
1432 #include "unchecked_optional_access_test.h"
1434 void target($ns::$optional<int> opt) {
1435 opt.value(); // [[unsafe]]
1437 )");
1439 ExpectDiagnosticsFor(
1441 #include "unchecked_optional_access_test.h"
1443 void target($ns::$optional<int> opt) {
1444 std::move(opt).value(); // [[unsafe]]
1446 )");
1449 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
1450 ExpectDiagnosticsFor(
1452 #include "unchecked_optional_access_test.h"
1454 void target($ns::$optional<int> opt) {
1455 *opt; // [[unsafe]]
1457 )");
1459 ExpectDiagnosticsFor(
1461 #include "unchecked_optional_access_test.h"
1463 void target($ns::$optional<int> opt) {
1464 *std::move(opt); // [[unsafe]]
1466 )");
1469 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
1470 ExpectDiagnosticsFor(
1472 #include "unchecked_optional_access_test.h"
1474 struct Foo {
1475 void foo();
1478 void target($ns::$optional<Foo> opt) {
1479 opt->foo(); // [[unsafe]]
1481 )");
1483 ExpectDiagnosticsFor(
1485 #include "unchecked_optional_access_test.h"
1487 struct Foo {
1488 void foo();
1491 void target($ns::$optional<Foo> opt) {
1492 std::move(opt)->foo(); // [[unsafe]]
1494 )");
1497 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
1498 ExpectDiagnosticsFor(R"(
1499 #include "unchecked_optional_access_test.h"
1501 void target($ns::$optional<int> opt) {
1502 if (opt.has_value()) {
1503 opt.value();
1506 )");
1509 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
1510 ExpectDiagnosticsFor(R"(
1511 #include "unchecked_optional_access_test.h"
1513 void target($ns::$optional<int> opt) {
1514 if (opt) {
1515 opt.value();
1518 )");
1521 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
1522 ExpectDiagnosticsFor(
1524 #include "unchecked_optional_access_test.h"
1526 void target() {
1527 Make<$ns::$optional<int>>().value(); // [[unsafe]]
1528 (void)0;
1530 )");
1532 ExpectDiagnosticsFor(
1534 #include "unchecked_optional_access_test.h"
1536 void target($ns::$optional<int> opt) {
1537 std::move(opt).value(); // [[unsafe]]
1539 )");
1542 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
1543 ExpectDiagnosticsFor(
1545 #include "unchecked_optional_access_test.h"
1547 void target() {
1548 $ns::$optional<int> opt;
1549 opt.value(); // [[unsafe]]
1551 )");
1554 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
1555 ExpectDiagnosticsFor(
1557 #include "unchecked_optional_access_test.h"
1559 void target() {
1560 $ns::$optional<int> opt($ns::nullopt);
1561 opt.value(); // [[unsafe]]
1563 )");
1566 TEST_P(UncheckedOptionalAccessTest, NulloptConstructorWithSugaredType) {
1567 ExpectDiagnosticsFor(
1569 #include "unchecked_optional_access_test.h"
1570 template <typename T>
1571 using wrapper = T;
1573 template <typename T>
1574 wrapper<T> wrap(T);
1576 void target() {
1577 $ns::$optional<int> opt(wrap($ns::nullopt));
1578 opt.value(); // [[unsafe]]
1580 )");
1583 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
1584 ExpectDiagnosticsFor(R"(
1585 #include "unchecked_optional_access_test.h"
1587 void target() {
1588 $ns::$optional<int> opt($ns::in_place, 3);
1589 opt.value();
1591 )");
1593 ExpectDiagnosticsFor(R"(
1594 #include "unchecked_optional_access_test.h"
1596 struct Foo {};
1598 void target() {
1599 $ns::$optional<Foo> opt($ns::in_place);
1600 opt.value();
1602 )");
1604 ExpectDiagnosticsFor(R"(
1605 #include "unchecked_optional_access_test.h"
1607 struct Foo {
1608 explicit Foo(int, bool);
1611 void target() {
1612 $ns::$optional<Foo> opt($ns::in_place, 3, false);
1613 opt.value();
1615 )");
1617 ExpectDiagnosticsFor(R"(
1618 #include "unchecked_optional_access_test.h"
1620 struct Foo {
1621 explicit Foo(std::initializer_list<int>);
1624 void target() {
1625 $ns::$optional<Foo> opt($ns::in_place, {3});
1626 opt.value();
1628 )");
1631 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
1632 ExpectDiagnosticsFor(R"(
1633 #include "unchecked_optional_access_test.h"
1635 void target() {
1636 $ns::$optional<int> opt(21);
1637 opt.value();
1639 )");
1641 ExpectDiagnosticsFor(R"(
1642 #include "unchecked_optional_access_test.h"
1644 void target() {
1645 $ns::$optional<int> opt = $ns::$optional<int>(21);
1646 opt.value();
1648 )");
1649 ExpectDiagnosticsFor(R"(
1650 #include "unchecked_optional_access_test.h"
1652 void target() {
1653 $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1654 opt.value();
1656 )");
1658 ExpectDiagnosticsFor(R"(
1659 #include "unchecked_optional_access_test.h"
1661 struct MyString {
1662 MyString(const char*);
1665 void target() {
1666 $ns::$optional<MyString> opt("foo");
1667 opt.value();
1669 )");
1671 ExpectDiagnosticsFor(R"(
1672 #include "unchecked_optional_access_test.h"
1674 struct Foo {};
1676 struct Bar {
1677 Bar(const Foo&);
1680 void target() {
1681 $ns::$optional<Bar> opt(Make<Foo>());
1682 opt.value();
1684 )");
1686 ExpectDiagnosticsFor(R"(
1687 #include "unchecked_optional_access_test.h"
1689 struct Foo {
1690 explicit Foo(int);
1693 void target() {
1694 $ns::$optional<Foo> opt(3);
1695 opt.value();
1697 )");
1700 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
1701 ExpectDiagnosticsFor(
1703 #include "unchecked_optional_access_test.h"
1705 struct Foo {};
1707 struct Bar {
1708 Bar(const Foo&);
1711 void target() {
1712 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1713 opt.value(); // [[unsafe]]
1715 )");
1717 ExpectDiagnosticsFor(
1719 #include "unchecked_optional_access_test.h"
1721 struct Foo {};
1723 struct Bar {
1724 explicit Bar(const Foo&);
1727 void target() {
1728 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
1729 opt.value(); // [[unsafe]]
1731 )");
1733 ExpectDiagnosticsFor(
1735 #include "unchecked_optional_access_test.h"
1737 struct Foo {};
1739 struct Bar {
1740 Bar(const Foo&);
1743 void target() {
1744 $ns::$optional<Foo> opt1 = $ns::nullopt;
1745 $ns::$optional<Bar> opt2(opt1);
1746 opt2.value(); // [[unsafe]]
1748 )");
1750 ExpectDiagnosticsFor(R"(
1751 #include "unchecked_optional_access_test.h"
1753 struct Foo {};
1755 struct Bar {
1756 Bar(const Foo&);
1759 void target() {
1760 $ns::$optional<Foo> opt1(Make<Foo>());
1761 $ns::$optional<Bar> opt2(opt1);
1762 opt2.value();
1764 )");
1766 ExpectDiagnosticsFor(R"(
1767 #include "unchecked_optional_access_test.h"
1769 struct Foo {};
1771 struct Bar {
1772 explicit Bar(const Foo&);
1775 void target() {
1776 $ns::$optional<Foo> opt1(Make<Foo>());
1777 $ns::$optional<Bar> opt2(opt1);
1778 opt2.value();
1780 )");
1783 TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
1784 ExpectDiagnosticsFor(R"(
1785 #include "unchecked_optional_access_test.h"
1787 void target() {
1788 $ns::$optional<int> opt = $ns::make_optional(0);
1789 opt.value();
1791 )");
1793 ExpectDiagnosticsFor(R"(
1794 #include "unchecked_optional_access_test.h"
1796 struct Foo {
1797 Foo(int, int);
1800 void target() {
1801 $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
1802 opt.value();
1804 )");
1806 ExpectDiagnosticsFor(R"(
1807 #include "unchecked_optional_access_test.h"
1809 struct Foo {
1810 constexpr Foo(std::initializer_list<char>);
1813 void target() {
1814 char a = 'a';
1815 $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
1816 opt.value();
1818 )");
1821 TEST_P(UncheckedOptionalAccessTest, ValueOr) {
1822 ExpectDiagnosticsFor(R"(
1823 #include "unchecked_optional_access_test.h"
1825 void target() {
1826 $ns::$optional<int> opt;
1827 opt.value_or(0);
1828 (void)0;
1830 )");
1833 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointers) {
1834 ExpectDiagnosticsFor(
1835 R"code(
1836 #include "unchecked_optional_access_test.h"
1838 void target($ns::$optional<int*> opt) {
1839 if (opt.value_or(nullptr) != nullptr) {
1840 opt.value();
1841 } else {
1842 opt.value(); // [[unsafe]]
1845 )code");
1848 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonIntegers) {
1849 ExpectDiagnosticsFor(
1850 R"code(
1851 #include "unchecked_optional_access_test.h"
1853 void target($ns::$optional<int> opt) {
1854 if (opt.value_or(0) != 0) {
1855 opt.value();
1856 } else {
1857 opt.value(); // [[unsafe]]
1860 )code");
1863 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonStrings) {
1864 ExpectDiagnosticsFor(
1865 R"code(
1866 #include "unchecked_optional_access_test.h"
1868 void target($ns::$optional<std::string> opt) {
1869 if (!opt.value_or("").empty()) {
1870 opt.value();
1871 } else {
1872 opt.value(); // [[unsafe]]
1875 )code");
1877 ExpectDiagnosticsFor(
1878 R"code(
1879 #include "unchecked_optional_access_test.h"
1881 void target($ns::$optional<std::string> opt) {
1882 if (opt.value_or("") != "") {
1883 opt.value();
1884 } else {
1885 opt.value(); // [[unsafe]]
1888 )code");
1891 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointerToOptional) {
1892 // FIXME: make `opt` a parameter directly, once we ensure that all `optional`
1893 // values have a `has_value` property.
1894 ExpectDiagnosticsFor(
1895 R"code(
1896 #include "unchecked_optional_access_test.h"
1898 void target($ns::$optional<int> p) {
1899 $ns::$optional<int> *opt = &p;
1900 if (opt->value_or(0) != 0) {
1901 opt->value();
1902 } else {
1903 opt->value(); // [[unsafe]]
1906 )code");
1909 TEST_P(UncheckedOptionalAccessTest, Emplace) {
1910 ExpectDiagnosticsFor(R"(
1911 #include "unchecked_optional_access_test.h"
1913 void target() {
1914 $ns::$optional<int> opt;
1915 opt.emplace(0);
1916 opt.value();
1918 )");
1920 ExpectDiagnosticsFor(R"(
1921 #include "unchecked_optional_access_test.h"
1923 void target($ns::$optional<int> *opt) {
1924 opt->emplace(0);
1925 opt->value();
1927 )");
1929 // FIXME: Add tests that call `emplace` in conditional branches:
1930 // ExpectDiagnosticsFor(
1931 // R"(
1932 // #include "unchecked_optional_access_test.h"
1934 // void target($ns::$optional<int> opt, bool b) {
1935 // if (b) {
1936 // opt.emplace(0);
1937 // }
1938 // if (b) {
1939 // opt.value();
1940 // } else {
1941 // opt.value(); // [[unsafe]]
1942 // }
1943 // }
1944 // )");
1947 TEST_P(UncheckedOptionalAccessTest, Reset) {
1948 ExpectDiagnosticsFor(
1950 #include "unchecked_optional_access_test.h"
1952 void target() {
1953 $ns::$optional<int> opt = $ns::make_optional(0);
1954 opt.reset();
1955 opt.value(); // [[unsafe]]
1957 )");
1959 ExpectDiagnosticsFor(
1961 #include "unchecked_optional_access_test.h"
1963 void target($ns::$optional<int> &opt) {
1964 if (opt.has_value()) {
1965 opt.reset();
1966 opt.value(); // [[unsafe]]
1969 )");
1971 // FIXME: Add tests that call `reset` in conditional branches:
1972 // ExpectDiagnosticsFor(
1973 // R"(
1974 // #include "unchecked_optional_access_test.h"
1976 // void target(bool b) {
1977 // $ns::$optional<int> opt = $ns::make_optional(0);
1978 // if (b) {
1979 // opt.reset();
1980 // }
1981 // if (b) {
1982 // opt.value(); // [[unsafe]]
1983 // } else {
1984 // opt.value();
1985 // }
1986 // }
1987 // )");
1990 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) {
1991 ExpectDiagnosticsFor(R"(
1992 #include "unchecked_optional_access_test.h"
1994 struct Foo {};
1996 void target() {
1997 $ns::$optional<Foo> opt;
1998 opt = Foo();
1999 opt.value();
2001 )");
2003 ExpectDiagnosticsFor(R"(
2004 #include "unchecked_optional_access_test.h"
2006 struct Foo {};
2008 void target() {
2009 $ns::$optional<Foo> opt;
2010 (opt = Foo()).value();
2011 (void)0;
2013 )");
2015 ExpectDiagnosticsFor(R"(
2016 #include "unchecked_optional_access_test.h"
2018 struct MyString {
2019 MyString(const char*);
2022 void target() {
2023 $ns::$optional<MyString> opt;
2024 opt = "foo";
2025 opt.value();
2027 )");
2029 ExpectDiagnosticsFor(R"(
2030 #include "unchecked_optional_access_test.h"
2032 struct MyString {
2033 MyString(const char*);
2036 void target() {
2037 $ns::$optional<MyString> opt;
2038 (opt = "foo").value();
2040 )");
2043 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) {
2044 ExpectDiagnosticsFor(
2046 #include "unchecked_optional_access_test.h"
2048 struct Foo {};
2050 struct Bar {
2051 Bar(const Foo&);
2054 void target() {
2055 $ns::$optional<Foo> opt1 = Foo();
2056 $ns::$optional<Bar> opt2;
2057 opt2 = opt1;
2058 opt2.value();
2060 )");
2062 ExpectDiagnosticsFor(
2064 #include "unchecked_optional_access_test.h"
2066 struct Foo {};
2068 struct Bar {
2069 Bar(const Foo&);
2072 void target() {
2073 $ns::$optional<Foo> opt1;
2074 $ns::$optional<Bar> opt2;
2075 if (opt2.has_value()) {
2076 opt2 = opt1;
2077 opt2.value(); // [[unsafe]]
2080 )");
2082 ExpectDiagnosticsFor(
2084 #include "unchecked_optional_access_test.h"
2086 struct Foo {};
2088 struct Bar {
2089 Bar(const Foo&);
2092 void target() {
2093 $ns::$optional<Foo> opt1 = Foo();
2094 $ns::$optional<Bar> opt2;
2095 (opt2 = opt1).value();
2096 (void)0;
2098 )");
2101 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) {
2102 ExpectDiagnosticsFor(
2104 #include "unchecked_optional_access_test.h"
2106 void target() {
2107 $ns::$optional<int> opt = 3;
2108 opt = $ns::nullopt;
2109 opt.value(); // [[unsafe]]
2111 )");
2113 ExpectDiagnosticsFor(
2115 #include "unchecked_optional_access_test.h"
2117 void target() {
2118 $ns::$optional<int> opt = 3;
2119 (opt = $ns::nullopt).value(); // [[unsafe]]
2121 )");
2124 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) {
2125 ExpectDiagnosticsFor(
2127 #include "unchecked_optional_access_test.h"
2129 void target() {
2130 $ns::$optional<int> opt1 = $ns::nullopt;
2131 $ns::$optional<int> opt2 = 3;
2133 opt1.swap(opt2);
2135 opt1.value();
2137 opt2.value(); // [[unsafe]]
2139 )");
2141 ExpectDiagnosticsFor(
2143 #include "unchecked_optional_access_test.h"
2145 void target() {
2146 $ns::$optional<int> opt1 = $ns::nullopt;
2147 $ns::$optional<int> opt2 = 3;
2149 opt2.swap(opt1);
2151 opt1.value();
2153 opt2.value(); // [[unsafe]]
2155 )");
2158 TEST_P(UncheckedOptionalAccessTest, OptionalReturnedFromFuntionCall) {
2159 ExpectDiagnosticsFor(
2161 #include "unchecked_optional_access_test.h"
2163 struct S {
2164 $ns::$optional<float> x;
2165 } s;
2166 S getOptional() {
2167 return s;
2170 void target() {
2171 getOptional().x = 0;
2173 )");
2176 TEST_P(UncheckedOptionalAccessTest, NonConstMethodMayClearOptionalField) {
2177 ExpectDiagnosticsFor(
2179 #include "unchecked_optional_access_test.h"
2181 struct Foo {
2182 $ns::$optional<std::string> opt;
2183 void clear(); // assume this may modify the opt field's state
2186 void target(Foo& foo) {
2187 if (foo.opt) {
2188 foo.opt.value();
2189 foo.clear();
2190 foo.opt.value(); // [[unsafe]]
2193 )");
2196 TEST_P(UncheckedOptionalAccessTest,
2197 NonConstMethodMayNotClearConstOptionalField) {
2198 ExpectDiagnosticsFor(
2200 #include "unchecked_optional_access_test.h"
2202 struct Foo {
2203 const $ns::$optional<std::string> opt;
2204 void clear();
2207 void target(Foo& foo) {
2208 if (foo.opt) {
2209 foo.opt.value();
2210 foo.clear();
2211 foo.opt.value();
2214 )");
2217 TEST_P(UncheckedOptionalAccessTest, StdSwap) {
2218 ExpectDiagnosticsFor(
2220 #include "unchecked_optional_access_test.h"
2222 void target() {
2223 $ns::$optional<int> opt1 = $ns::nullopt;
2224 $ns::$optional<int> opt2 = 3;
2226 std::swap(opt1, opt2);
2228 opt1.value();
2230 opt2.value(); // [[unsafe]]
2232 )");
2234 ExpectDiagnosticsFor(
2236 #include "unchecked_optional_access_test.h"
2238 void target() {
2239 $ns::$optional<int> opt1 = $ns::nullopt;
2240 $ns::$optional<int> opt2 = 3;
2242 std::swap(opt2, opt1);
2244 opt1.value();
2246 opt2.value(); // [[unsafe]]
2248 )");
2251 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocLeft) {
2252 ExpectDiagnosticsFor(
2254 #include "unchecked_optional_access_test.h"
2256 struct L { $ns::$optional<int> hd; L* tl; };
2258 void target() {
2259 $ns::$optional<int> foo = 3;
2260 L bar;
2262 // Any `tl` beyond the first is not modeled.
2263 bar.tl->tl->hd.swap(foo);
2265 bar.tl->tl->hd.value(); // [[unsafe]]
2266 foo.value(); // [[unsafe]]
2268 )");
2271 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocRight) {
2272 ExpectDiagnosticsFor(
2274 #include "unchecked_optional_access_test.h"
2276 struct L { $ns::$optional<int> hd; L* tl; };
2278 void target() {
2279 $ns::$optional<int> foo = 3;
2280 L bar;
2282 // Any `tl` beyond the first is not modeled.
2283 foo.swap(bar.tl->tl->hd);
2285 bar.tl->tl->hd.value(); // [[unsafe]]
2286 foo.value(); // [[unsafe]]
2288 )");
2291 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftSet) {
2292 ExpectDiagnosticsFor(
2294 #include "unchecked_optional_access_test.h"
2296 struct S { int x; };
2297 struct A { $ns::$optional<S> late; };
2298 struct B { A f3; };
2299 struct C { B f2; };
2300 struct D { C f1; };
2302 void target() {
2303 $ns::$optional<S> foo = S{3};
2304 D bar;
2306 bar.f1.f2.f3.late.swap(foo);
2308 bar.f1.f2.f3.late.value();
2309 foo.value(); // [[unsafe]]
2311 )");
2314 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftUnset) {
2315 ExpectDiagnosticsFor(
2317 #include "unchecked_optional_access_test.h"
2319 struct S { int x; };
2320 struct A { $ns::$optional<S> late; };
2321 struct B { A f3; };
2322 struct C { B f2; };
2323 struct D { C f1; };
2325 void target() {
2326 $ns::$optional<S> foo;
2327 D bar;
2329 bar.f1.f2.f3.late.swap(foo);
2331 bar.f1.f2.f3.late.value(); // [[unsafe]]
2332 foo.value(); // [[unsafe]]
2334 )");
2337 // fixme: use recursion instead of depth.
2338 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightSet) {
2339 ExpectDiagnosticsFor(
2341 #include "unchecked_optional_access_test.h"
2343 struct S { int x; };
2344 struct A { $ns::$optional<S> late; };
2345 struct B { A f3; };
2346 struct C { B f2; };
2347 struct D { C f1; };
2349 void target() {
2350 $ns::$optional<S> foo = S{3};
2351 D bar;
2353 foo.swap(bar.f1.f2.f3.late);
2355 bar.f1.f2.f3.late.value();
2356 foo.value(); // [[unsafe]]
2358 )");
2361 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightUnset) {
2362 ExpectDiagnosticsFor(
2364 #include "unchecked_optional_access_test.h"
2366 struct S { int x; };
2367 struct A { $ns::$optional<S> late; };
2368 struct B { A f3; };
2369 struct C { B f2; };
2370 struct D { C f1; };
2372 void target() {
2373 $ns::$optional<S> foo;
2374 D bar;
2376 foo.swap(bar.f1.f2.f3.late);
2378 bar.f1.f2.f3.late.value(); // [[unsafe]]
2379 foo.value(); // [[unsafe]]
2381 )");
2384 TEST_P(UncheckedOptionalAccessTest, UniquePtrToOptional) {
2385 // We suppress diagnostics for optionals in smart pointers (other than
2386 // `optional` itself).
2387 ExpectDiagnosticsFor(
2389 #include "unchecked_optional_access_test.h"
2391 template <typename T>
2392 struct smart_ptr {
2393 T& operator*() &;
2394 T* operator->();
2397 void target() {
2398 smart_ptr<$ns::$optional<bool>> foo;
2399 foo->value();
2400 (*foo).value();
2402 )");
2405 TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) {
2406 // We suppress diagnostics for optional fields reachable from smart pointers
2407 // (other than `optional` itself) through (exactly) one member access.
2408 ExpectDiagnosticsFor(
2410 #include "unchecked_optional_access_test.h"
2412 template <typename T>
2413 struct smart_ptr {
2414 T& operator*() &;
2415 T* operator->();
2418 struct Foo {
2419 $ns::$optional<int> opt;
2422 void target() {
2423 smart_ptr<Foo> foo;
2424 *foo->opt;
2425 *(*foo).opt;
2427 )");
2430 TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) {
2431 ExpectDiagnosticsFor(
2433 #include "unchecked_optional_access_test.h"
2435 $ns::$optional<int> MakeOpt();
2437 void target() {
2438 $ns::$optional<int> opt = 0;
2439 opt = MakeOpt();
2440 opt.value(); // [[unsafe]]
2442 )");
2443 ExpectDiagnosticsFor(
2445 #include "unchecked_optional_access_test.h"
2447 const $ns::$optional<int>& MakeOpt();
2449 void target() {
2450 $ns::$optional<int> opt = 0;
2451 opt = MakeOpt();
2452 opt.value(); // [[unsafe]]
2454 )");
2456 ExpectDiagnosticsFor(
2458 #include "unchecked_optional_access_test.h"
2460 using IntOpt = $ns::$optional<int>;
2461 IntOpt MakeOpt();
2463 void target() {
2464 IntOpt opt = 0;
2465 opt = MakeOpt();
2466 opt.value(); // [[unsafe]]
2468 )");
2470 ExpectDiagnosticsFor(
2472 #include "unchecked_optional_access_test.h"
2474 using IntOpt = $ns::$optional<int>;
2475 const IntOpt& MakeOpt();
2477 void target() {
2478 IntOpt opt = 0;
2479 opt = MakeOpt();
2480 opt.value(); // [[unsafe]]
2482 )");
2486 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftSet) {
2487 ExpectDiagnosticsFor(
2489 #include "unchecked_optional_access_test.h"
2491 void target() {
2492 $ns::$optional<int> opt1 = 3;
2493 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2495 if (opt1 == opt2) {
2496 opt2.value();
2497 } else {
2498 opt2.value(); // [[unsafe]]
2501 )");
2504 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightSet) {
2505 ExpectDiagnosticsFor(
2507 #include "unchecked_optional_access_test.h"
2509 void target() {
2510 $ns::$optional<int> opt1 = 3;
2511 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2513 if (opt2 == opt1) {
2514 opt2.value();
2515 } else {
2516 opt2.value(); // [[unsafe]]
2519 )");
2522 TEST_P(UncheckedOptionalAccessTest, EqualityCheckVerifySetAfterEq) {
2523 ExpectDiagnosticsFor(
2525 #include "unchecked_optional_access_test.h"
2527 void target() {
2528 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2529 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2531 if (opt1 == opt2) {
2532 if (opt1.has_value())
2533 opt2.value();
2534 if (opt2.has_value())
2535 opt1.value();
2538 )");
2541 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftUnset) {
2542 ExpectDiagnosticsFor(
2544 #include "unchecked_optional_access_test.h"
2546 void target() {
2547 $ns::$optional<int> opt1 = $ns::nullopt;
2548 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2550 if (opt1 == opt2) {
2551 opt2.value(); // [[unsafe]]
2552 } else {
2553 opt2.value();
2556 )");
2559 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightUnset) {
2560 ExpectDiagnosticsFor(
2562 #include "unchecked_optional_access_test.h"
2564 void target() {
2565 $ns::$optional<int> opt1 = $ns::nullopt;
2566 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2568 if (opt2 == opt1) {
2569 opt2.value(); // [[unsafe]]
2570 } else {
2571 opt2.value();
2574 )");
2577 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightNullopt) {
2578 ExpectDiagnosticsFor(
2580 #include "unchecked_optional_access_test.h"
2582 void target() {
2583 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2585 if (opt == $ns::nullopt) {
2586 opt.value(); // [[unsafe]]
2587 } else {
2588 opt.value();
2591 )");
2594 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftNullopt) {
2595 ExpectDiagnosticsFor(
2597 #include "unchecked_optional_access_test.h"
2599 void target() {
2600 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2602 if ($ns::nullopt == opt) {
2603 opt.value(); // [[unsafe]]
2604 } else {
2605 opt.value();
2608 )");
2611 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightValue) {
2612 ExpectDiagnosticsFor(
2614 #include "unchecked_optional_access_test.h"
2616 void target() {
2617 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2619 if (opt == 3) {
2620 opt.value();
2621 } else {
2622 opt.value(); // [[unsafe]]
2625 )");
2628 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftValue) {
2629 ExpectDiagnosticsFor(
2631 #include "unchecked_optional_access_test.h"
2633 void target() {
2634 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2636 if (3 == opt) {
2637 opt.value();
2638 } else {
2639 opt.value(); // [[unsafe]]
2642 )");
2645 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftSet) {
2646 ExpectDiagnosticsFor(
2648 #include "unchecked_optional_access_test.h"
2650 void target() {
2651 $ns::$optional<int> opt1 = 3;
2652 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2654 if (opt1 != opt2) {
2655 opt2.value(); // [[unsafe]]
2656 } else {
2657 opt2.value();
2660 )");
2663 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightSet) {
2664 ExpectDiagnosticsFor(
2666 #include "unchecked_optional_access_test.h"
2668 void target() {
2669 $ns::$optional<int> opt1 = 3;
2670 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2672 if (opt2 != opt1) {
2673 opt2.value(); // [[unsafe]]
2674 } else {
2675 opt2.value();
2678 )");
2681 TEST_P(UncheckedOptionalAccessTest, InequalityCheckVerifySetAfterEq) {
2682 ExpectDiagnosticsFor(
2684 #include "unchecked_optional_access_test.h"
2686 void target() {
2687 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2688 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2690 if (opt1 != opt2) {
2691 if (opt1.has_value())
2692 opt2.value(); // [[unsafe]]
2693 if (opt2.has_value())
2694 opt1.value(); // [[unsafe]]
2697 )");
2700 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftUnset) {
2701 ExpectDiagnosticsFor(
2703 #include "unchecked_optional_access_test.h"
2705 void target() {
2706 $ns::$optional<int> opt1 = $ns::nullopt;
2707 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2709 if (opt1 != opt2) {
2710 opt2.value();
2711 } else {
2712 opt2.value(); // [[unsafe]]
2715 )");
2718 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightUnset) {
2719 ExpectDiagnosticsFor(
2721 #include "unchecked_optional_access_test.h"
2723 void target() {
2724 $ns::$optional<int> opt1 = $ns::nullopt;
2725 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2727 if (opt2 != opt1) {
2728 opt2.value();
2729 } else {
2730 opt2.value(); // [[unsafe]]
2733 )");
2736 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightNullopt) {
2737 ExpectDiagnosticsFor(
2739 #include "unchecked_optional_access_test.h"
2741 void target() {
2742 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2744 if (opt != $ns::nullopt) {
2745 opt.value();
2746 } else {
2747 opt.value(); // [[unsafe]]
2750 )");
2753 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftNullopt) {
2754 ExpectDiagnosticsFor(
2756 #include "unchecked_optional_access_test.h"
2758 void target() {
2759 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2761 if ($ns::nullopt != opt) {
2762 opt.value();
2763 } else {
2764 opt.value(); // [[unsafe]]
2767 )");
2770 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightValue) {
2771 ExpectDiagnosticsFor(
2773 #include "unchecked_optional_access_test.h"
2775 void target() {
2776 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2778 if (opt != 3) {
2779 opt.value(); // [[unsafe]]
2780 } else {
2781 opt.value();
2784 )");
2787 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftValue) {
2788 ExpectDiagnosticsFor(
2790 #include "unchecked_optional_access_test.h"
2792 void target() {
2793 $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2795 if (3 != opt) {
2796 opt.value(); // [[unsafe]]
2797 } else {
2798 opt.value();
2801 )");
2804 // Verifies that the model sees through aliases.
2805 TEST_P(UncheckedOptionalAccessTest, WithAlias) {
2806 ExpectDiagnosticsFor(
2808 #include "unchecked_optional_access_test.h"
2810 template <typename T>
2811 using MyOptional = $ns::$optional<T>;
2813 void target(MyOptional<int> opt) {
2814 opt.value(); // [[unsafe]]
2816 )");
2819 TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) {
2820 // Basic test that nested values are populated. We nest an optional because
2821 // its easy to use in a test, but the type of the nested value shouldn't
2822 // matter.
2823 ExpectDiagnosticsFor(
2825 #include "unchecked_optional_access_test.h"
2827 using Foo = $ns::$optional<std::string>;
2829 void target($ns::$optional<Foo> foo) {
2830 if (foo && *foo) {
2831 foo->value();
2834 )");
2836 // Mutation is supported for nested values.
2837 ExpectDiagnosticsFor(
2839 #include "unchecked_optional_access_test.h"
2841 using Foo = $ns::$optional<std::string>;
2843 void target($ns::$optional<Foo> foo) {
2844 if (foo && *foo) {
2845 foo->reset();
2846 foo->value(); // [[unsafe]]
2849 )");
2852 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignValue) {
2853 ExpectDiagnosticsFor(
2855 #include "unchecked_optional_access_test.h"
2857 using OptionalInt = $ns::$optional<int>;
2859 void target($ns::$optional<OptionalInt> opt) {
2860 if (!opt) return;
2862 // Accessing the outer optional is OK now.
2863 *opt;
2865 // But accessing the nested optional is still unsafe because we haven't
2866 // checked it.
2867 **opt; // [[unsafe]]
2869 *opt = 1;
2871 // Accessing the nested optional is safe after assigning a value to it.
2872 **opt;
2874 )");
2877 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignOptional) {
2878 ExpectDiagnosticsFor(
2880 #include "unchecked_optional_access_test.h"
2882 using OptionalInt = $ns::$optional<int>;
2884 void target($ns::$optional<OptionalInt> opt) {
2885 if (!opt) return;
2887 // Accessing the outer optional is OK now.
2888 *opt;
2890 // But accessing the nested optional is still unsafe because we haven't
2891 // checked it.
2892 **opt; // [[unsafe]]
2894 // Assign from `optional<short>` so that we trigger conversion assignment
2895 // instead of move assignment.
2896 *opt = $ns::$optional<short>();
2898 // Accessing the nested optional is still unsafe after assigning an empty
2899 // optional to it.
2900 **opt; // [[unsafe]]
2902 )");
2905 // Tests that structs can be nested. We use an optional field because its easy
2906 // to use in a test, but the type of the field shouldn't matter.
2907 TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) {
2908 ExpectDiagnosticsFor(
2910 #include "unchecked_optional_access_test.h"
2912 struct Foo {
2913 $ns::$optional<std::string> opt;
2916 void target($ns::$optional<Foo> foo) {
2917 if (foo && foo->opt) {
2918 foo->opt.value();
2921 )");
2924 // FIXME: A case that we should handle but currently don't.
2925 // When there is a field of type reference to non-optional, we may
2926 // stop recursively creating storage locations.
2927 // E.g., the field `second` below in `pair` should eventually lead to
2928 // the optional `x` in `A`.
2929 TEST_P(UncheckedOptionalAccessTest, NestedOptionalThroughNonOptionalRefField) {
2930 ExpectDiagnosticsFor(R"(
2931 #include "unchecked_optional_access_test.h"
2933 struct A {
2934 $ns::$optional<int> x;
2937 struct pair {
2938 int first;
2939 const A &second;
2942 struct B {
2943 $ns::$optional<pair>& nonConstGetRef();
2946 void target(B b) {
2947 const auto& maybe_pair = b.nonConstGetRef();
2948 if (!maybe_pair.has_value())
2949 return;
2951 if(!maybe_pair->second.x.has_value())
2952 return;
2953 maybe_pair->second.x.value(); // [[unsafe]]
2955 )");
2958 TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) {
2959 ExpectDiagnosticsFor(
2961 #include "unchecked_optional_access_test.h"
2963 using Foo = $ns::$optional<std::string>;
2965 void target($ns::$optional<Foo> foo, bool b) {
2966 if (!foo.has_value()) return;
2967 if (b) {
2968 if (!foo->has_value()) return;
2969 // We have created `foo.value()`.
2970 foo->value();
2971 } else {
2972 if (!foo->has_value()) return;
2973 // We have created `foo.value()` again, in a different environment.
2974 foo->value();
2976 // Now we merge the two values. UncheckedOptionalAccessModel::merge() will
2977 // throw away the "value" property.
2978 foo->value();
2980 )");
2983 // This test is aimed at the core model, not the diagnostic. It is a regression
2984 // test against a crash when using non-trivial smart pointers, like
2985 // `std::unique_ptr`. As such, it doesn't test the access itself, which would be
2986 // ignored regardless because of `IgnoreSmartPointerDereference = true`, above.
2987 TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) {
2988 ExpectDiagnosticsFor(
2990 #include "unchecked_optional_access_test.h"
2992 template <typename T>
2993 struct smart_ptr {
2994 typename std::add_lvalue_reference<T>::type operator*() &;
2997 void target() {
2998 smart_ptr<$ns::$optional<int>> x;
2999 // Verify that this assignment does not crash.
3000 *x = 3;
3002 )");
3005 TEST_P(UncheckedOptionalAccessTest, CorrelatedBranches) {
3006 ExpectDiagnosticsFor(R"code(
3007 #include "unchecked_optional_access_test.h"
3009 void target(bool b, $ns::$optional<int> opt) {
3010 if (b || opt.has_value()) {
3011 if (!b) {
3012 opt.value();
3016 )code");
3018 ExpectDiagnosticsFor(R"code(
3019 #include "unchecked_optional_access_test.h"
3021 void target(bool b, $ns::$optional<int> opt) {
3022 if (b && !opt.has_value()) return;
3023 if (b) {
3024 opt.value();
3027 )code");
3029 ExpectDiagnosticsFor(
3030 R"code(
3031 #include "unchecked_optional_access_test.h"
3033 void target(bool b, $ns::$optional<int> opt) {
3034 if (opt.has_value()) b = true;
3035 if (b) {
3036 opt.value(); // [[unsafe]]
3039 )code");
3041 ExpectDiagnosticsFor(R"code(
3042 #include "unchecked_optional_access_test.h"
3044 void target(bool b, $ns::$optional<int> opt) {
3045 if (b) return;
3046 if (opt.has_value()) b = true;
3047 if (b) {
3048 opt.value();
3051 )code");
3053 ExpectDiagnosticsFor(R"(
3054 #include "unchecked_optional_access_test.h"
3056 void target(bool b, $ns::$optional<int> opt) {
3057 if (opt.has_value() == b) {
3058 if (b) {
3059 opt.value();
3063 )");
3065 ExpectDiagnosticsFor(R"(
3066 #include "unchecked_optional_access_test.h"
3068 void target(bool b, $ns::$optional<int> opt) {
3069 if (opt.has_value() != b) {
3070 if (!b) {
3071 opt.value();
3075 )");
3077 ExpectDiagnosticsFor(R"(
3078 #include "unchecked_optional_access_test.h"
3080 void target(bool b) {
3081 $ns::$optional<int> opt1 = $ns::nullopt;
3082 $ns::$optional<int> opt2;
3083 if (b) {
3084 opt2 = $ns::nullopt;
3085 } else {
3086 opt2 = $ns::nullopt;
3088 if (opt2.has_value()) {
3089 opt1.value();
3092 )");
3095 TEST_P(UncheckedOptionalAccessTest, JoinDistinctValues) {
3096 ExpectDiagnosticsFor(
3097 R"code(
3098 #include "unchecked_optional_access_test.h"
3100 void target(bool b) {
3101 $ns::$optional<int> opt;
3102 if (b) {
3103 opt = Make<$ns::$optional<int>>();
3104 } else {
3105 opt = Make<$ns::$optional<int>>();
3107 if (opt.has_value()) {
3108 opt.value();
3109 } else {
3110 opt.value(); // [[unsafe]]
3113 )code");
3115 ExpectDiagnosticsFor(R"code(
3116 #include "unchecked_optional_access_test.h"
3118 void target(bool b) {
3119 $ns::$optional<int> opt;
3120 if (b) {
3121 opt = Make<$ns::$optional<int>>();
3122 if (!opt.has_value()) return;
3123 } else {
3124 opt = Make<$ns::$optional<int>>();
3125 if (!opt.has_value()) return;
3127 opt.value();
3129 )code");
3131 ExpectDiagnosticsFor(
3132 R"code(
3133 #include "unchecked_optional_access_test.h"
3135 void target(bool b) {
3136 $ns::$optional<int> opt;
3137 if (b) {
3138 opt = Make<$ns::$optional<int>>();
3139 if (!opt.has_value()) return;
3140 } else {
3141 opt = Make<$ns::$optional<int>>();
3143 opt.value(); // [[unsafe]]
3145 )code");
3147 ExpectDiagnosticsFor(
3148 R"code(
3149 #include "unchecked_optional_access_test.h"
3151 void target(bool b) {
3152 $ns::$optional<int> opt;
3153 if (b) {
3154 opt = 1;
3155 } else {
3156 opt = 2;
3158 opt.value();
3160 )code");
3162 ExpectDiagnosticsFor(
3163 R"code(
3164 #include "unchecked_optional_access_test.h"
3166 void target(bool b) {
3167 $ns::$optional<int> opt;
3168 if (b) {
3169 opt = 1;
3170 } else {
3171 opt = Make<$ns::$optional<int>>();
3173 opt.value(); // [[unsafe]]
3175 )code");
3178 TEST_P(UncheckedOptionalAccessTest, AccessValueInLoop) {
3179 ExpectDiagnosticsFor(R"(
3180 #include "unchecked_optional_access_test.h"
3182 void target() {
3183 $ns::$optional<int> opt = 3;
3184 while (Make<bool>()) {
3185 opt.value();
3188 )");
3191 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopWithCheckSafe) {
3192 ExpectDiagnosticsFor(R"(
3193 #include "unchecked_optional_access_test.h"
3195 void target() {
3196 $ns::$optional<int> opt = 3;
3197 while (Make<bool>()) {
3198 opt.value();
3200 opt = Make<$ns::$optional<int>>();
3201 if (!opt.has_value()) return;
3204 )");
3207 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopNoCheckUnsafe) {
3208 ExpectDiagnosticsFor(
3210 #include "unchecked_optional_access_test.h"
3212 void target() {
3213 $ns::$optional<int> opt = 3;
3214 while (Make<bool>()) {
3215 opt.value(); // [[unsafe]]
3217 opt = Make<$ns::$optional<int>>();
3220 )");
3223 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnsetUnsafe) {
3224 ExpectDiagnosticsFor(
3226 #include "unchecked_optional_access_test.h"
3228 void target() {
3229 $ns::$optional<int> opt = 3;
3230 while (Make<bool>())
3231 opt = $ns::nullopt;
3232 $ns::$optional<int> opt2 = $ns::nullopt;
3233 if (opt.has_value())
3234 opt2 = $ns::$optional<int>(3);
3235 opt2.value(); // [[unsafe]]
3237 )");
3240 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToSetUnsafe) {
3241 ExpectDiagnosticsFor(
3243 #include "unchecked_optional_access_test.h"
3245 void target() {
3246 $ns::$optional<int> opt = $ns::nullopt;
3247 while (Make<bool>())
3248 opt = $ns::$optional<int>(3);
3249 $ns::$optional<int> opt2 = $ns::nullopt;
3250 if (!opt.has_value())
3251 opt2 = $ns::$optional<int>(3);
3252 opt2.value(); // [[unsafe]]
3254 )");
3257 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnknownUnsafe) {
3258 ExpectDiagnosticsFor(
3260 #include "unchecked_optional_access_test.h"
3262 void target() {
3263 $ns::$optional<int> opt = $ns::nullopt;
3264 while (Make<bool>())
3265 opt = Make<$ns::$optional<int>>();
3266 $ns::$optional<int> opt2 = $ns::nullopt;
3267 if (!opt.has_value())
3268 opt2 = $ns::$optional<int>(3);
3269 opt2.value(); // [[unsafe]]
3271 )");
3274 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopBadConditionUnsafe) {
3275 ExpectDiagnosticsFor(
3277 #include "unchecked_optional_access_test.h"
3279 void target() {
3280 $ns::$optional<int> opt = 3;
3281 while (Make<bool>()) {
3282 opt.value(); // [[unsafe]]
3284 opt = Make<$ns::$optional<int>>();
3285 if (!opt.has_value()) continue;
3288 )");
3291 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromStruct) {
3292 ExpectDiagnosticsFor(R"(
3293 #include "unchecked_optional_access_test.h"
3295 struct kv { $ns::$optional<int> opt; int x; };
3296 int target() {
3297 auto [contents, x] = Make<kv>();
3298 return contents ? *contents : x;
3300 )");
3302 ExpectDiagnosticsFor(R"(
3303 #include "unchecked_optional_access_test.h"
3305 template <typename T1, typename T2>
3306 struct pair { T1 fst; T2 snd; };
3307 int target() {
3308 auto [contents, x] = Make<pair<$ns::$optional<int>, int>>();
3309 return contents ? *contents : x;
3311 )");
3314 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromTupleLikeType) {
3315 ExpectDiagnosticsFor(R"(
3316 #include "unchecked_optional_access_test.h"
3318 namespace std {
3319 template <class> struct tuple_size;
3320 template <size_t, class> struct tuple_element;
3321 template <class...> class tuple;
3323 template <class... T>
3324 struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {};
3326 template <size_t I, class... T>
3327 struct tuple_element<I, tuple<T...>> {
3328 using type = __type_pack_element<I, T...>;
3331 template <class...> class tuple {};
3332 template <size_t I, class... T>
3333 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
3334 } // namespace std
3336 std::tuple<$ns::$optional<const char *>, int> get_opt();
3337 void target() {
3338 auto [content, ck] = get_opt();
3339 content ? *content : "";
3341 )");
3344 TEST_P(UncheckedOptionalAccessTest, CtorInitializerNullopt) {
3345 using namespace ast_matchers;
3346 ExpectDiagnosticsFor(
3348 #include "unchecked_optional_access_test.h"
3350 struct Target {
3351 Target(): opt($ns::nullopt) {
3352 opt.value(); // [[unsafe]]
3354 $ns::$optional<int> opt;
3357 cxxConstructorDecl(ofClass(hasName("Target"))));
3360 TEST_P(UncheckedOptionalAccessTest, CtorInitializerValue) {
3361 using namespace ast_matchers;
3362 ExpectDiagnosticsFor(
3364 #include "unchecked_optional_access_test.h"
3366 struct Target {
3367 Target(): opt(3) {
3368 opt.value();
3370 $ns::$optional<int> opt;
3373 cxxConstructorDecl(ofClass(hasName("Target"))));
3376 // This is regression test, it shouldn't crash.
3377 TEST_P(UncheckedOptionalAccessTest, Bitfield) {
3378 using namespace ast_matchers;
3379 ExpectDiagnosticsFor(
3381 #include "unchecked_optional_access_test.h"
3382 struct Dst {
3383 unsigned int n : 1;
3385 void target() {
3386 $ns::$optional<bool> v;
3387 Dst d;
3388 if (v.has_value())
3389 d.n = v.value();
3391 )");
3394 TEST_P(UncheckedOptionalAccessTest, LambdaParam) {
3395 ExpectDiagnosticsForLambda(R"(
3396 #include "unchecked_optional_access_test.h"
3398 void target() {
3399 []($ns::$optional<int> opt) {
3400 if (opt.has_value()) {
3401 opt.value();
3402 } else {
3403 opt.value(); // [[unsafe]]
3405 }(Make<$ns::$optional<int>>());
3407 )");
3410 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopy) {
3411 ExpectDiagnosticsForLambda(R"(
3412 #include "unchecked_optional_access_test.h"
3414 void target($ns::$optional<int> opt) {
3415 [opt]() {
3416 if (opt.has_value()) {
3417 opt.value();
3418 } else {
3419 opt.value(); // [[unsafe]]
3421 }();
3423 )");
3426 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReference) {
3427 ExpectDiagnosticsForLambda(R"(
3428 #include "unchecked_optional_access_test.h"
3430 void target($ns::$optional<int> opt) {
3431 [&opt]() {
3432 if (opt.has_value()) {
3433 opt.value();
3434 } else {
3435 opt.value(); // [[unsafe]]
3437 }();
3439 )");
3442 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureWithInitializer) {
3443 ExpectDiagnosticsForLambda(R"(
3444 #include "unchecked_optional_access_test.h"
3446 void target($ns::$optional<int> opt) {
3447 [opt2=opt]() {
3448 if (opt2.has_value()) {
3449 opt2.value();
3450 } else {
3451 opt2.value(); // [[unsafe]]
3453 }();
3455 )");
3458 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopyImplicit) {
3459 ExpectDiagnosticsForLambda(R"(
3460 #include "unchecked_optional_access_test.h"
3462 void target($ns::$optional<int> opt) {
3463 [=]() {
3464 if (opt.has_value()) {
3465 opt.value();
3466 } else {
3467 opt.value(); // [[unsafe]]
3469 }();
3471 )");
3474 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReferenceImplicit) {
3475 ExpectDiagnosticsForLambda(R"(
3476 #include "unchecked_optional_access_test.h"
3478 void target($ns::$optional<int> opt) {
3479 [&]() {
3480 if (opt.has_value()) {
3481 opt.value();
3482 } else {
3483 opt.value(); // [[unsafe]]
3485 }();
3487 )");
3490 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureThis) {
3491 ExpectDiagnosticsForLambda(R"(
3492 #include "unchecked_optional_access_test.h"
3494 struct Foo {
3495 $ns::$optional<int> opt;
3497 void target() {
3498 [this]() {
3499 if (opt.has_value()) {
3500 opt.value();
3501 } else {
3502 opt.value(); // [[unsafe]]
3504 }();
3507 )");
3510 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureStateNotPropagated) {
3511 // We can't propagate information from the surrounding context.
3512 ExpectDiagnosticsForLambda(R"(
3513 #include "unchecked_optional_access_test.h"
3515 void target($ns::$optional<int> opt) {
3516 if (opt.has_value()) {
3517 [&opt]() {
3518 opt.value(); // [[unsafe]]
3519 }();
3522 )");
3525 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptional) {
3526 ExpectDiagnosticsFor(R"(
3527 #include "unchecked_optional_access_test.h"
3529 struct Derived : public $ns::$optional<int> {};
3531 void target(Derived opt) {
3532 *opt; // [[unsafe]]
3533 if (opt.has_value())
3534 *opt;
3536 // The same thing, but with a pointer receiver.
3537 Derived *popt = &opt;
3538 **popt; // [[unsafe]]
3539 if (popt->has_value())
3540 **popt;
3542 )");
3545 TEST_P(UncheckedOptionalAccessTest, ClassTemplateDerivedFromOptional) {
3546 ExpectDiagnosticsFor(R"(
3547 #include "unchecked_optional_access_test.h"
3549 template <class T>
3550 struct Derived : public $ns::$optional<T> {};
3552 void target(Derived<int> opt) {
3553 *opt; // [[unsafe]]
3554 if (opt.has_value())
3555 *opt;
3557 // The same thing, but with a pointer receiver.
3558 Derived<int> *popt = &opt;
3559 **popt; // [[unsafe]]
3560 if (popt->has_value())
3561 **popt;
3563 )");
3566 TEST_P(UncheckedOptionalAccessTest, ClassDerivedPrivatelyFromOptional) {
3567 // Classes that derive privately from optional can themselves still call
3568 // member functions of optional. Check that we model the optional correctly
3569 // in this situation.
3570 ExpectDiagnosticsFor(R"(
3571 #include "unchecked_optional_access_test.h"
3573 struct Derived : private $ns::$optional<int> {
3574 void Method() {
3575 **this; // [[unsafe]]
3576 if (this->has_value())
3577 **this;
3581 ast_matchers::hasName("Method"));
3584 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptionalValueConstructor) {
3585 ExpectDiagnosticsFor(R"(
3586 #include "unchecked_optional_access_test.h"
3588 struct Derived : public $ns::$optional<int> {
3589 Derived(int);
3592 void target(Derived opt) {
3593 *opt; // [[unsafe]]
3594 opt = 1;
3595 *opt;
3597 )");
3600 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessor) {
3601 ExpectDiagnosticsFor(R"cc(
3602 #include "unchecked_optional_access_test.h"
3604 struct A {
3605 const $ns::$optional<int>& get() const { return x; }
3606 $ns::$optional<int> x;
3609 void target(A& a) {
3610 if (a.get().has_value()) {
3611 a.get().value();
3614 )cc");
3617 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModInBetween) {
3618 ExpectDiagnosticsFor(R"cc(
3619 #include "unchecked_optional_access_test.h"
3621 struct A {
3622 const $ns::$optional<int>& get() const { return x; }
3623 void clear();
3624 $ns::$optional<int> x;
3627 void target(A& a) {
3628 if (a.get().has_value()) {
3629 a.clear();
3630 a.get().value(); // [[unsafe]]
3633 )cc");
3636 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModReturningOptional) {
3637 ExpectDiagnosticsFor(R"cc(
3638 #include "unchecked_optional_access_test.h"
3640 struct A {
3641 const $ns::$optional<int>& get() const { return x; }
3642 $ns::$optional<int> take();
3643 $ns::$optional<int> x;
3646 void target(A& a) {
3647 if (a.get().has_value()) {
3648 $ns::$optional<int> other = a.take();
3649 a.get().value(); // [[unsafe]]
3650 if (other.has_value()) {
3651 other.value();
3655 )cc");
3658 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorDifferentObjects) {
3659 ExpectDiagnosticsFor(R"cc(
3660 #include "unchecked_optional_access_test.h"
3662 struct A {
3663 const $ns::$optional<int>& get() const { return x; }
3664 $ns::$optional<int> x;
3667 void target(A& a1, A& a2) {
3668 if (a1.get().has_value()) {
3669 a2.get().value(); // [[unsafe]]
3672 )cc");
3675 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorLoop) {
3676 ExpectDiagnosticsFor(R"cc(
3677 #include "unchecked_optional_access_test.h"
3679 struct A {
3680 const $ns::$optional<int>& get() const { return x; }
3681 $ns::$optional<int> x;
3684 void target(A& a, int N) {
3685 for (int i = 0; i < N; ++i) {
3686 if (a.get().has_value()) {
3687 a.get().value();
3691 )cc");
3694 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessor) {
3695 ExpectDiagnosticsFor(R"cc(
3696 #include "unchecked_optional_access_test.h"
3698 struct A {
3699 $ns::$optional<int> get() const { return x; }
3700 $ns::$optional<int> x;
3703 void target(A& a) {
3704 if (a.get().has_value()) {
3705 a.get().value();
3708 )cc");
3711 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessorWithModInBetween) {
3712 ExpectDiagnosticsFor(R"cc(
3713 #include "unchecked_optional_access_test.h"
3715 struct A {
3716 $ns::$optional<int> get() const { return x; }
3717 void clear();
3718 $ns::$optional<int> x;
3721 void target(A& a) {
3722 if (a.get().has_value()) {
3723 a.clear();
3724 a.get().value(); // [[unsafe]]
3727 )cc");
3730 TEST_P(UncheckedOptionalAccessTest, ConstPointerAccessor) {
3731 ExpectDiagnosticsFor(R"cc(
3732 #include "unchecked_optional_access_test.h"
3734 struct A {
3735 $ns::$optional<int> x;
3738 struct MyUniquePtr {
3739 A* operator->() const;
3742 void target(MyUniquePtr p) {
3743 if (p->x) {
3744 *p->x;
3747 )cc",
3748 /*IgnoreSmartPointerDereference=*/false);
3751 TEST_P(UncheckedOptionalAccessTest, ConstPointerAccessorWithModInBetween) {
3752 ExpectDiagnosticsFor(R"cc(
3753 #include "unchecked_optional_access_test.h"
3755 struct A {
3756 $ns::$optional<int> x;
3759 struct MyUniquePtr {
3760 A* operator->() const;
3761 void reset(A*);
3764 void target(MyUniquePtr p) {
3765 if (p->x) {
3766 p.reset(nullptr);
3767 *p->x; // [[unsafe]]
3770 )cc",
3771 /*IgnoreSmartPointerDereference=*/false);
3774 TEST_P(UncheckedOptionalAccessTest, SmartPointerAccessorMixed) {
3775 ExpectDiagnosticsFor(R"cc(
3776 #include "unchecked_optional_access_test.h"
3778 struct A {
3779 $ns::$optional<int> x;
3782 namespace absl {
3783 template<typename T>
3784 class StatusOr {
3785 public:
3786 bool ok() const;
3788 const T& operator*() const&;
3789 T& operator*() &;
3791 const T* operator->() const;
3792 T* operator->();
3794 const T& value() const;
3795 T& value();
3799 void target(absl::StatusOr<A> &mut, const absl::StatusOr<A> &imm) {
3800 if (!mut.ok() || !imm.ok())
3801 return;
3803 if (mut->x.has_value()) {
3804 mut->x.value();
3805 ((*mut).x).value();
3806 (mut.value().x).value();
3808 // check flagged after modifying
3809 mut = imm;
3810 mut->x.value(); // [[unsafe]]
3812 if (imm->x.has_value()) {
3813 imm->x.value();
3814 ((*imm).x).value();
3815 (imm.value().x).value();
3818 )cc",
3819 /*IgnoreSmartPointerDereference=*/false);
3822 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessor) {
3823 ExpectDiagnosticsFor(R"cc(
3824 #include "unchecked_optional_access_test.h"
3826 struct A {
3827 bool isFoo() const { return f; }
3828 bool f;
3831 void target(A& a) {
3832 std::optional<int> opt;
3833 if (a.isFoo()) {
3834 opt = 1;
3836 if (a.isFoo()) {
3837 opt.value();
3840 )cc");
3843 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessorWithModInBetween) {
3844 ExpectDiagnosticsFor(R"cc(
3845 #include "unchecked_optional_access_test.h"
3847 struct A {
3848 bool isFoo() const { return f; }
3849 void clear();
3850 bool f;
3853 void target(A& a) {
3854 std::optional<int> opt;
3855 if (a.isFoo()) {
3856 opt = 1;
3858 a.clear();
3859 if (a.isFoo()) {
3860 opt.value(); // [[unsafe]]
3863 )cc");
3866 // FIXME: Add support for:
3867 // - constructors (copy, move)
3868 // - assignment operators (default, copy, move)
3869 // - invalidation (passing optional by non-const reference/pointer)