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