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< 1346 UncheckedOptionalAccessLattice> 1347 &State) mutable { 1348 auto EltDiagnostics = Diagnoser(Elt, Ctx, State); 1349 llvm::move(EltDiagnostics, std::back_inserter(Diagnostics)); 1350 }, 1351 /*After=*/nullptr}) 1352 .withASTBuildArgs( 1353 {"-fsyntax-only", CxxMode, "-Wno-undefined-inline"}) 1354 .withASTBuildVirtualMappedFiles( 1355 tooling::FileContentMappings(Headers.begin(), Headers.end())), 1356 /*VerifyResults=*/[&Diagnostics]( 1357 const llvm::DenseMap<unsigned, std::string> 1358 &Annotations, 1359 const AnalysisOutputs &AO) { 1360 llvm::DenseSet<unsigned> AnnotationLines; 1361 for (const auto &[Line, _] : Annotations) { 1362 AnnotationLines.insert(Line); 1363 } 1364 auto &SrcMgr = AO.ASTCtx.getSourceManager(); 1365 llvm::DenseSet<unsigned> DiagnosticLines; 1366 for (SourceLocation &Loc : Diagnostics) { 1367 unsigned Line = SrcMgr.getPresumedLineNumber(Loc); 1368 DiagnosticLines.insert(Line); 1369 if (!AnnotationLines.contains(Line)) { 1370 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts( 1371 new DiagnosticOptions()); 1372 TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(), 1373 DiagOpts.get()); 1374 TD.emitDiagnostic(FullSourceLoc(Loc, SrcMgr), 1375 DiagnosticsEngine::Error, 1376 "unexpected diagnostic", {}, {}); 1377 } 1378 } 1379 1380 EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines)); 1381 }); 1382 if (Error) 1383 FAIL() << llvm::toString(std::move(Error)); 1384 } 1385 }; 1386 1387 INSTANTIATE_TEST_SUITE_P( 1388 UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest, 1389 ::testing::Values(OptionalTypeIdentifier{"std", "optional"}, 1390 OptionalTypeIdentifier{"absl", "optional"}, 1391 OptionalTypeIdentifier{"base", "Optional"}), 1392 [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) { 1393 return Info.param.NamespaceName; 1394 }); 1395 1396 // Verifies that similarly-named types are ignored. 1397 TEST_P(UncheckedOptionalAccessTest, NonTrackedOptionalType) { 1398 ExpectDiagnosticsFor( 1399 R"( 1400 namespace other { 1401 namespace $ns { 1402 template <typename T> 1403 struct $optional { 1404 T value(); 1405 }; 1406 } 1407 1408 void target($ns::$optional<int> opt) { 1409 opt.value(); 1410 } 1411 } 1412 )"); 1413 } 1414 1415 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) { 1416 ExpectDiagnosticsFor(R"( 1417 void target() { 1418 (void)0; 1419 } 1420 )"); 1421 } 1422 1423 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) { 1424 ExpectDiagnosticsFor( 1425 R"( 1426 #include "unchecked_optional_access_test.h" 1427 1428 void target($ns::$optional<int> opt) { 1429 opt.value(); // [[unsafe]] 1430 } 1431 )"); 1432 1433 ExpectDiagnosticsFor( 1434 R"( 1435 #include "unchecked_optional_access_test.h" 1436 1437 void target($ns::$optional<int> opt) { 1438 std::move(opt).value(); // [[unsafe]] 1439 } 1440 )"); 1441 } 1442 1443 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) { 1444 ExpectDiagnosticsFor( 1445 R"( 1446 #include "unchecked_optional_access_test.h" 1447 1448 void target($ns::$optional<int> opt) { 1449 *opt; // [[unsafe]] 1450 } 1451 )"); 1452 1453 ExpectDiagnosticsFor( 1454 R"( 1455 #include "unchecked_optional_access_test.h" 1456 1457 void target($ns::$optional<int> opt) { 1458 *std::move(opt); // [[unsafe]] 1459 } 1460 )"); 1461 } 1462 1463 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) { 1464 ExpectDiagnosticsFor( 1465 R"( 1466 #include "unchecked_optional_access_test.h" 1467 1468 struct Foo { 1469 void foo(); 1470 }; 1471 1472 void target($ns::$optional<Foo> opt) { 1473 opt->foo(); // [[unsafe]] 1474 } 1475 )"); 1476 1477 ExpectDiagnosticsFor( 1478 R"( 1479 #include "unchecked_optional_access_test.h" 1480 1481 struct Foo { 1482 void foo(); 1483 }; 1484 1485 void target($ns::$optional<Foo> opt) { 1486 std::move(opt)->foo(); // [[unsafe]] 1487 } 1488 )"); 1489 } 1490 1491 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) { 1492 ExpectDiagnosticsFor(R"( 1493 #include "unchecked_optional_access_test.h" 1494 1495 void target($ns::$optional<int> opt) { 1496 if (opt.has_value()) { 1497 opt.value(); 1498 } 1499 } 1500 )"); 1501 } 1502 1503 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) { 1504 ExpectDiagnosticsFor(R"( 1505 #include "unchecked_optional_access_test.h" 1506 1507 void target($ns::$optional<int> opt) { 1508 if (opt) { 1509 opt.value(); 1510 } 1511 } 1512 )"); 1513 } 1514 1515 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) { 1516 ExpectDiagnosticsFor( 1517 R"( 1518 #include "unchecked_optional_access_test.h" 1519 1520 void target() { 1521 Make<$ns::$optional<int>>().value(); // [[unsafe]] 1522 (void)0; 1523 } 1524 )"); 1525 1526 ExpectDiagnosticsFor( 1527 R"( 1528 #include "unchecked_optional_access_test.h" 1529 1530 void target($ns::$optional<int> opt) { 1531 std::move(opt).value(); // [[unsafe]] 1532 } 1533 )"); 1534 } 1535 1536 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) { 1537 ExpectDiagnosticsFor( 1538 R"( 1539 #include "unchecked_optional_access_test.h" 1540 1541 void target() { 1542 $ns::$optional<int> opt; 1543 opt.value(); // [[unsafe]] 1544 } 1545 )"); 1546 } 1547 1548 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) { 1549 ExpectDiagnosticsFor( 1550 R"( 1551 #include "unchecked_optional_access_test.h" 1552 1553 void target() { 1554 $ns::$optional<int> opt($ns::nullopt); 1555 opt.value(); // [[unsafe]] 1556 } 1557 )"); 1558 } 1559 1560 TEST_P(UncheckedOptionalAccessTest, NulloptConstructorWithSugaredType) { 1561 ExpectDiagnosticsFor( 1562 R"( 1563 #include "unchecked_optional_access_test.h" 1564 template <typename T> 1565 using wrapper = T; 1566 1567 template <typename T> 1568 wrapper<T> wrap(T); 1569 1570 void target() { 1571 $ns::$optional<int> opt(wrap($ns::nullopt)); 1572 opt.value(); // [[unsafe]] 1573 } 1574 )"); 1575 } 1576 1577 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) { 1578 ExpectDiagnosticsFor(R"( 1579 #include "unchecked_optional_access_test.h" 1580 1581 void target() { 1582 $ns::$optional<int> opt($ns::in_place, 3); 1583 opt.value(); 1584 } 1585 )"); 1586 1587 ExpectDiagnosticsFor(R"( 1588 #include "unchecked_optional_access_test.h" 1589 1590 struct Foo {}; 1591 1592 void target() { 1593 $ns::$optional<Foo> opt($ns::in_place); 1594 opt.value(); 1595 } 1596 )"); 1597 1598 ExpectDiagnosticsFor(R"( 1599 #include "unchecked_optional_access_test.h" 1600 1601 struct Foo { 1602 explicit Foo(int, bool); 1603 }; 1604 1605 void target() { 1606 $ns::$optional<Foo> opt($ns::in_place, 3, false); 1607 opt.value(); 1608 } 1609 )"); 1610 1611 ExpectDiagnosticsFor(R"( 1612 #include "unchecked_optional_access_test.h" 1613 1614 struct Foo { 1615 explicit Foo(std::initializer_list<int>); 1616 }; 1617 1618 void target() { 1619 $ns::$optional<Foo> opt($ns::in_place, {3}); 1620 opt.value(); 1621 } 1622 )"); 1623 } 1624 1625 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) { 1626 ExpectDiagnosticsFor(R"( 1627 #include "unchecked_optional_access_test.h" 1628 1629 void target() { 1630 $ns::$optional<int> opt(21); 1631 opt.value(); 1632 } 1633 )"); 1634 1635 ExpectDiagnosticsFor(R"( 1636 #include "unchecked_optional_access_test.h" 1637 1638 void target() { 1639 $ns::$optional<int> opt = $ns::$optional<int>(21); 1640 opt.value(); 1641 } 1642 )"); 1643 ExpectDiagnosticsFor(R"( 1644 #include "unchecked_optional_access_test.h" 1645 1646 void target() { 1647 $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>()); 1648 opt.value(); 1649 } 1650 )"); 1651 1652 ExpectDiagnosticsFor(R"( 1653 #include "unchecked_optional_access_test.h" 1654 1655 struct MyString { 1656 MyString(const char*); 1657 }; 1658 1659 void target() { 1660 $ns::$optional<MyString> opt("foo"); 1661 opt.value(); 1662 } 1663 )"); 1664 1665 ExpectDiagnosticsFor(R"( 1666 #include "unchecked_optional_access_test.h" 1667 1668 struct Foo {}; 1669 1670 struct Bar { 1671 Bar(const Foo&); 1672 }; 1673 1674 void target() { 1675 $ns::$optional<Bar> opt(Make<Foo>()); 1676 opt.value(); 1677 } 1678 )"); 1679 1680 ExpectDiagnosticsFor(R"( 1681 #include "unchecked_optional_access_test.h" 1682 1683 struct Foo { 1684 explicit Foo(int); 1685 }; 1686 1687 void target() { 1688 $ns::$optional<Foo> opt(3); 1689 opt.value(); 1690 } 1691 )"); 1692 } 1693 1694 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) { 1695 ExpectDiagnosticsFor( 1696 R"( 1697 #include "unchecked_optional_access_test.h" 1698 1699 struct Foo {}; 1700 1701 struct Bar { 1702 Bar(const Foo&); 1703 }; 1704 1705 void target() { 1706 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>()); 1707 opt.value(); // [[unsafe]] 1708 } 1709 )"); 1710 1711 ExpectDiagnosticsFor( 1712 R"( 1713 #include "unchecked_optional_access_test.h" 1714 1715 struct Foo {}; 1716 1717 struct Bar { 1718 explicit Bar(const Foo&); 1719 }; 1720 1721 void target() { 1722 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>()); 1723 opt.value(); // [[unsafe]] 1724 } 1725 )"); 1726 1727 ExpectDiagnosticsFor( 1728 R"( 1729 #include "unchecked_optional_access_test.h" 1730 1731 struct Foo {}; 1732 1733 struct Bar { 1734 Bar(const Foo&); 1735 }; 1736 1737 void target() { 1738 $ns::$optional<Foo> opt1 = $ns::nullopt; 1739 $ns::$optional<Bar> opt2(opt1); 1740 opt2.value(); // [[unsafe]] 1741 } 1742 )"); 1743 1744 ExpectDiagnosticsFor(R"( 1745 #include "unchecked_optional_access_test.h" 1746 1747 struct Foo {}; 1748 1749 struct Bar { 1750 Bar(const Foo&); 1751 }; 1752 1753 void target() { 1754 $ns::$optional<Foo> opt1(Make<Foo>()); 1755 $ns::$optional<Bar> opt2(opt1); 1756 opt2.value(); 1757 } 1758 )"); 1759 1760 ExpectDiagnosticsFor(R"( 1761 #include "unchecked_optional_access_test.h" 1762 1763 struct Foo {}; 1764 1765 struct Bar { 1766 explicit Bar(const Foo&); 1767 }; 1768 1769 void target() { 1770 $ns::$optional<Foo> opt1(Make<Foo>()); 1771 $ns::$optional<Bar> opt2(opt1); 1772 opt2.value(); 1773 } 1774 )"); 1775 } 1776 1777 TEST_P(UncheckedOptionalAccessTest, MakeOptional) { 1778 ExpectDiagnosticsFor(R"( 1779 #include "unchecked_optional_access_test.h" 1780 1781 void target() { 1782 $ns::$optional<int> opt = $ns::make_optional(0); 1783 opt.value(); 1784 } 1785 )"); 1786 1787 ExpectDiagnosticsFor(R"( 1788 #include "unchecked_optional_access_test.h" 1789 1790 struct Foo { 1791 Foo(int, int); 1792 }; 1793 1794 void target() { 1795 $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22); 1796 opt.value(); 1797 } 1798 )"); 1799 1800 ExpectDiagnosticsFor(R"( 1801 #include "unchecked_optional_access_test.h" 1802 1803 struct Foo { 1804 constexpr Foo(std::initializer_list<char>); 1805 }; 1806 1807 void target() { 1808 char a = 'a'; 1809 $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a}); 1810 opt.value(); 1811 } 1812 )"); 1813 } 1814 1815 TEST_P(UncheckedOptionalAccessTest, ValueOr) { 1816 ExpectDiagnosticsFor(R"( 1817 #include "unchecked_optional_access_test.h" 1818 1819 void target() { 1820 $ns::$optional<int> opt; 1821 opt.value_or(0); 1822 (void)0; 1823 } 1824 )"); 1825 } 1826 1827 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointers) { 1828 ExpectDiagnosticsFor( 1829 R"code( 1830 #include "unchecked_optional_access_test.h" 1831 1832 void target($ns::$optional<int*> opt) { 1833 if (opt.value_or(nullptr) != nullptr) { 1834 opt.value(); 1835 } else { 1836 opt.value(); // [[unsafe]] 1837 } 1838 } 1839 )code"); 1840 } 1841 1842 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonIntegers) { 1843 ExpectDiagnosticsFor( 1844 R"code( 1845 #include "unchecked_optional_access_test.h" 1846 1847 void target($ns::$optional<int> opt) { 1848 if (opt.value_or(0) != 0) { 1849 opt.value(); 1850 } else { 1851 opt.value(); // [[unsafe]] 1852 } 1853 } 1854 )code"); 1855 } 1856 1857 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonStrings) { 1858 ExpectDiagnosticsFor( 1859 R"code( 1860 #include "unchecked_optional_access_test.h" 1861 1862 void target($ns::$optional<std::string> opt) { 1863 if (!opt.value_or("").empty()) { 1864 opt.value(); 1865 } else { 1866 opt.value(); // [[unsafe]] 1867 } 1868 } 1869 )code"); 1870 1871 ExpectDiagnosticsFor( 1872 R"code( 1873 #include "unchecked_optional_access_test.h" 1874 1875 void target($ns::$optional<std::string> opt) { 1876 if (opt.value_or("") != "") { 1877 opt.value(); 1878 } else { 1879 opt.value(); // [[unsafe]] 1880 } 1881 } 1882 )code"); 1883 } 1884 1885 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointerToOptional) { 1886 // FIXME: make `opt` a parameter directly, once we ensure that all `optional` 1887 // values have a `has_value` property. 1888 ExpectDiagnosticsFor( 1889 R"code( 1890 #include "unchecked_optional_access_test.h" 1891 1892 void target($ns::$optional<int> p) { 1893 $ns::$optional<int> *opt = &p; 1894 if (opt->value_or(0) != 0) { 1895 opt->value(); 1896 } else { 1897 opt->value(); // [[unsafe]] 1898 } 1899 } 1900 )code"); 1901 } 1902 1903 TEST_P(UncheckedOptionalAccessTest, Emplace) { 1904 ExpectDiagnosticsFor(R"( 1905 #include "unchecked_optional_access_test.h" 1906 1907 void target() { 1908 $ns::$optional<int> opt; 1909 opt.emplace(0); 1910 opt.value(); 1911 } 1912 )"); 1913 1914 ExpectDiagnosticsFor(R"( 1915 #include "unchecked_optional_access_test.h" 1916 1917 void target($ns::$optional<int> *opt) { 1918 opt->emplace(0); 1919 opt->value(); 1920 } 1921 )"); 1922 1923 // FIXME: Add tests that call `emplace` in conditional branches: 1924 // ExpectDiagnosticsFor( 1925 // R"( 1926 // #include "unchecked_optional_access_test.h" 1927 // 1928 // void target($ns::$optional<int> opt, bool b) { 1929 // if (b) { 1930 // opt.emplace(0); 1931 // } 1932 // if (b) { 1933 // opt.value(); 1934 // } else { 1935 // opt.value(); // [[unsafe]] 1936 // } 1937 // } 1938 // )"); 1939 } 1940 1941 TEST_P(UncheckedOptionalAccessTest, Reset) { 1942 ExpectDiagnosticsFor( 1943 R"( 1944 #include "unchecked_optional_access_test.h" 1945 1946 void target() { 1947 $ns::$optional<int> opt = $ns::make_optional(0); 1948 opt.reset(); 1949 opt.value(); // [[unsafe]] 1950 } 1951 )"); 1952 1953 ExpectDiagnosticsFor( 1954 R"( 1955 #include "unchecked_optional_access_test.h" 1956 1957 void target($ns::$optional<int> &opt) { 1958 if (opt.has_value()) { 1959 opt.reset(); 1960 opt.value(); // [[unsafe]] 1961 } 1962 } 1963 )"); 1964 1965 // FIXME: Add tests that call `reset` in conditional branches: 1966 // ExpectDiagnosticsFor( 1967 // R"( 1968 // #include "unchecked_optional_access_test.h" 1969 // 1970 // void target(bool b) { 1971 // $ns::$optional<int> opt = $ns::make_optional(0); 1972 // if (b) { 1973 // opt.reset(); 1974 // } 1975 // if (b) { 1976 // opt.value(); // [[unsafe]] 1977 // } else { 1978 // opt.value(); 1979 // } 1980 // } 1981 // )"); 1982 } 1983 1984 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) { 1985 ExpectDiagnosticsFor(R"( 1986 #include "unchecked_optional_access_test.h" 1987 1988 struct Foo {}; 1989 1990 void target() { 1991 $ns::$optional<Foo> opt; 1992 opt = Foo(); 1993 opt.value(); 1994 } 1995 )"); 1996 1997 ExpectDiagnosticsFor(R"( 1998 #include "unchecked_optional_access_test.h" 1999 2000 struct Foo {}; 2001 2002 void target() { 2003 $ns::$optional<Foo> opt; 2004 (opt = Foo()).value(); 2005 (void)0; 2006 } 2007 )"); 2008 2009 ExpectDiagnosticsFor(R"( 2010 #include "unchecked_optional_access_test.h" 2011 2012 struct MyString { 2013 MyString(const char*); 2014 }; 2015 2016 void target() { 2017 $ns::$optional<MyString> opt; 2018 opt = "foo"; 2019 opt.value(); 2020 } 2021 )"); 2022 2023 ExpectDiagnosticsFor(R"( 2024 #include "unchecked_optional_access_test.h" 2025 2026 struct MyString { 2027 MyString(const char*); 2028 }; 2029 2030 void target() { 2031 $ns::$optional<MyString> opt; 2032 (opt = "foo").value(); 2033 } 2034 )"); 2035 } 2036 2037 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) { 2038 ExpectDiagnosticsFor( 2039 R"( 2040 #include "unchecked_optional_access_test.h" 2041 2042 struct Foo {}; 2043 2044 struct Bar { 2045 Bar(const Foo&); 2046 }; 2047 2048 void target() { 2049 $ns::$optional<Foo> opt1 = Foo(); 2050 $ns::$optional<Bar> opt2; 2051 opt2 = opt1; 2052 opt2.value(); 2053 } 2054 )"); 2055 2056 ExpectDiagnosticsFor( 2057 R"( 2058 #include "unchecked_optional_access_test.h" 2059 2060 struct Foo {}; 2061 2062 struct Bar { 2063 Bar(const Foo&); 2064 }; 2065 2066 void target() { 2067 $ns::$optional<Foo> opt1; 2068 $ns::$optional<Bar> opt2; 2069 if (opt2.has_value()) { 2070 opt2 = opt1; 2071 opt2.value(); // [[unsafe]] 2072 } 2073 } 2074 )"); 2075 2076 ExpectDiagnosticsFor( 2077 R"( 2078 #include "unchecked_optional_access_test.h" 2079 2080 struct Foo {}; 2081 2082 struct Bar { 2083 Bar(const Foo&); 2084 }; 2085 2086 void target() { 2087 $ns::$optional<Foo> opt1 = Foo(); 2088 $ns::$optional<Bar> opt2; 2089 (opt2 = opt1).value(); 2090 (void)0; 2091 } 2092 )"); 2093 } 2094 2095 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) { 2096 ExpectDiagnosticsFor( 2097 R"( 2098 #include "unchecked_optional_access_test.h" 2099 2100 void target() { 2101 $ns::$optional<int> opt = 3; 2102 opt = $ns::nullopt; 2103 opt.value(); // [[unsafe]] 2104 } 2105 )"); 2106 2107 ExpectDiagnosticsFor( 2108 R"( 2109 #include "unchecked_optional_access_test.h" 2110 2111 void target() { 2112 $ns::$optional<int> opt = 3; 2113 (opt = $ns::nullopt).value(); // [[unsafe]] 2114 } 2115 )"); 2116 } 2117 2118 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) { 2119 ExpectDiagnosticsFor( 2120 R"( 2121 #include "unchecked_optional_access_test.h" 2122 2123 void target() { 2124 $ns::$optional<int> opt1 = $ns::nullopt; 2125 $ns::$optional<int> opt2 = 3; 2126 2127 opt1.swap(opt2); 2128 2129 opt1.value(); 2130 2131 opt2.value(); // [[unsafe]] 2132 } 2133 )"); 2134 2135 ExpectDiagnosticsFor( 2136 R"( 2137 #include "unchecked_optional_access_test.h" 2138 2139 void target() { 2140 $ns::$optional<int> opt1 = $ns::nullopt; 2141 $ns::$optional<int> opt2 = 3; 2142 2143 opt2.swap(opt1); 2144 2145 opt1.value(); 2146 2147 opt2.value(); // [[unsafe]] 2148 } 2149 )"); 2150 } 2151 2152 TEST_P(UncheckedOptionalAccessTest, OptionalReturnedFromFuntionCall) { 2153 ExpectDiagnosticsFor( 2154 R"( 2155 #include "unchecked_optional_access_test.h" 2156 2157 struct S { 2158 $ns::$optional<float> x; 2159 } s; 2160 S getOptional() { 2161 return s; 2162 } 2163 2164 void target() { 2165 getOptional().x = 0; 2166 } 2167 )"); 2168 } 2169 2170 TEST_P(UncheckedOptionalAccessTest, NonConstMethodMayClearOptionalField) { 2171 ExpectDiagnosticsFor( 2172 R"( 2173 #include "unchecked_optional_access_test.h" 2174 2175 struct Foo { 2176 $ns::$optional<std::string> opt; 2177 void clear(); // assume this may modify the opt field's state 2178 }; 2179 2180 void target(Foo& foo) { 2181 if (foo.opt) { 2182 foo.opt.value(); 2183 foo.clear(); 2184 foo.opt.value(); // [[unsafe]] 2185 } 2186 } 2187 )"); 2188 } 2189 2190 TEST_P(UncheckedOptionalAccessTest, 2191 NonConstMethodMayNotClearConstOptionalField) { 2192 ExpectDiagnosticsFor( 2193 R"( 2194 #include "unchecked_optional_access_test.h" 2195 2196 struct Foo { 2197 const $ns::$optional<std::string> opt; 2198 void clear(); 2199 }; 2200 2201 void target(Foo& foo) { 2202 if (foo.opt) { 2203 foo.opt.value(); 2204 foo.clear(); 2205 foo.opt.value(); 2206 } 2207 } 2208 )"); 2209 } 2210 2211 TEST_P(UncheckedOptionalAccessTest, StdSwap) { 2212 ExpectDiagnosticsFor( 2213 R"( 2214 #include "unchecked_optional_access_test.h" 2215 2216 void target() { 2217 $ns::$optional<int> opt1 = $ns::nullopt; 2218 $ns::$optional<int> opt2 = 3; 2219 2220 std::swap(opt1, opt2); 2221 2222 opt1.value(); 2223 2224 opt2.value(); // [[unsafe]] 2225 } 2226 )"); 2227 2228 ExpectDiagnosticsFor( 2229 R"( 2230 #include "unchecked_optional_access_test.h" 2231 2232 void target() { 2233 $ns::$optional<int> opt1 = $ns::nullopt; 2234 $ns::$optional<int> opt2 = 3; 2235 2236 std::swap(opt2, opt1); 2237 2238 opt1.value(); 2239 2240 opt2.value(); // [[unsafe]] 2241 } 2242 )"); 2243 } 2244 2245 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocLeft) { 2246 ExpectDiagnosticsFor( 2247 R"( 2248 #include "unchecked_optional_access_test.h" 2249 2250 struct L { $ns::$optional<int> hd; L* tl; }; 2251 2252 void target() { 2253 $ns::$optional<int> foo = 3; 2254 L bar; 2255 2256 // Any `tl` beyond the first is not modeled. 2257 bar.tl->tl->hd.swap(foo); 2258 2259 bar.tl->tl->hd.value(); // [[unsafe]] 2260 foo.value(); // [[unsafe]] 2261 } 2262 )"); 2263 } 2264 2265 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocRight) { 2266 ExpectDiagnosticsFor( 2267 R"( 2268 #include "unchecked_optional_access_test.h" 2269 2270 struct L { $ns::$optional<int> hd; L* tl; }; 2271 2272 void target() { 2273 $ns::$optional<int> foo = 3; 2274 L bar; 2275 2276 // Any `tl` beyond the first is not modeled. 2277 foo.swap(bar.tl->tl->hd); 2278 2279 bar.tl->tl->hd.value(); // [[unsafe]] 2280 foo.value(); // [[unsafe]] 2281 } 2282 )"); 2283 } 2284 2285 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftSet) { 2286 ExpectDiagnosticsFor( 2287 R"( 2288 #include "unchecked_optional_access_test.h" 2289 2290 struct S { int x; }; 2291 struct A { $ns::$optional<S> late; }; 2292 struct B { A f3; }; 2293 struct C { B f2; }; 2294 struct D { C f1; }; 2295 2296 void target() { 2297 $ns::$optional<S> foo = S{3}; 2298 D bar; 2299 2300 bar.f1.f2.f3.late.swap(foo); 2301 2302 bar.f1.f2.f3.late.value(); 2303 foo.value(); // [[unsafe]] 2304 } 2305 )"); 2306 } 2307 2308 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftUnset) { 2309 ExpectDiagnosticsFor( 2310 R"( 2311 #include "unchecked_optional_access_test.h" 2312 2313 struct S { int x; }; 2314 struct A { $ns::$optional<S> late; }; 2315 struct B { A f3; }; 2316 struct C { B f2; }; 2317 struct D { C f1; }; 2318 2319 void target() { 2320 $ns::$optional<S> foo; 2321 D bar; 2322 2323 bar.f1.f2.f3.late.swap(foo); 2324 2325 bar.f1.f2.f3.late.value(); // [[unsafe]] 2326 foo.value(); // [[unsafe]] 2327 } 2328 )"); 2329 } 2330 2331 // fixme: use recursion instead of depth. 2332 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightSet) { 2333 ExpectDiagnosticsFor( 2334 R"( 2335 #include "unchecked_optional_access_test.h" 2336 2337 struct S { int x; }; 2338 struct A { $ns::$optional<S> late; }; 2339 struct B { A f3; }; 2340 struct C { B f2; }; 2341 struct D { C f1; }; 2342 2343 void target() { 2344 $ns::$optional<S> foo = S{3}; 2345 D bar; 2346 2347 foo.swap(bar.f1.f2.f3.late); 2348 2349 bar.f1.f2.f3.late.value(); 2350 foo.value(); // [[unsafe]] 2351 } 2352 )"); 2353 } 2354 2355 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightUnset) { 2356 ExpectDiagnosticsFor( 2357 R"( 2358 #include "unchecked_optional_access_test.h" 2359 2360 struct S { int x; }; 2361 struct A { $ns::$optional<S> late; }; 2362 struct B { A f3; }; 2363 struct C { B f2; }; 2364 struct D { C f1; }; 2365 2366 void target() { 2367 $ns::$optional<S> foo; 2368 D bar; 2369 2370 foo.swap(bar.f1.f2.f3.late); 2371 2372 bar.f1.f2.f3.late.value(); // [[unsafe]] 2373 foo.value(); // [[unsafe]] 2374 } 2375 )"); 2376 } 2377 2378 TEST_P(UncheckedOptionalAccessTest, UniquePtrToOptional) { 2379 // We suppress diagnostics for optionals in smart pointers (other than 2380 // `optional` itself). 2381 ExpectDiagnosticsFor( 2382 R"( 2383 #include "unchecked_optional_access_test.h" 2384 2385 template <typename T> 2386 struct smart_ptr { 2387 T& operator*() &; 2388 T* operator->(); 2389 }; 2390 2391 void target() { 2392 smart_ptr<$ns::$optional<bool>> foo; 2393 foo->value(); 2394 (*foo).value(); 2395 } 2396 )"); 2397 } 2398 2399 TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) { 2400 // We suppress diagnostics for optional fields reachable from smart pointers 2401 // (other than `optional` itself) through (exactly) one member access. 2402 ExpectDiagnosticsFor( 2403 R"( 2404 #include "unchecked_optional_access_test.h" 2405 2406 template <typename T> 2407 struct smart_ptr { 2408 T& operator*() &; 2409 T* operator->(); 2410 }; 2411 2412 struct Foo { 2413 $ns::$optional<int> opt; 2414 }; 2415 2416 void target() { 2417 smart_ptr<Foo> foo; 2418 *foo->opt; 2419 *(*foo).opt; 2420 } 2421 )"); 2422 } 2423 2424 TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) { 2425 ExpectDiagnosticsFor( 2426 R"( 2427 #include "unchecked_optional_access_test.h" 2428 2429 $ns::$optional<int> MakeOpt(); 2430 2431 void target() { 2432 $ns::$optional<int> opt = 0; 2433 opt = MakeOpt(); 2434 opt.value(); // [[unsafe]] 2435 } 2436 )"); 2437 ExpectDiagnosticsFor( 2438 R"( 2439 #include "unchecked_optional_access_test.h" 2440 2441 const $ns::$optional<int>& MakeOpt(); 2442 2443 void target() { 2444 $ns::$optional<int> opt = 0; 2445 opt = MakeOpt(); 2446 opt.value(); // [[unsafe]] 2447 } 2448 )"); 2449 2450 ExpectDiagnosticsFor( 2451 R"( 2452 #include "unchecked_optional_access_test.h" 2453 2454 using IntOpt = $ns::$optional<int>; 2455 IntOpt MakeOpt(); 2456 2457 void target() { 2458 IntOpt opt = 0; 2459 opt = MakeOpt(); 2460 opt.value(); // [[unsafe]] 2461 } 2462 )"); 2463 2464 ExpectDiagnosticsFor( 2465 R"( 2466 #include "unchecked_optional_access_test.h" 2467 2468 using IntOpt = $ns::$optional<int>; 2469 const IntOpt& MakeOpt(); 2470 2471 void target() { 2472 IntOpt opt = 0; 2473 opt = MakeOpt(); 2474 opt.value(); // [[unsafe]] 2475 } 2476 )"); 2477 } 2478 2479 2480 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftSet) { 2481 ExpectDiagnosticsFor( 2482 R"( 2483 #include "unchecked_optional_access_test.h" 2484 2485 void target() { 2486 $ns::$optional<int> opt1 = 3; 2487 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2488 2489 if (opt1 == opt2) { 2490 opt2.value(); 2491 } else { 2492 opt2.value(); // [[unsafe]] 2493 } 2494 } 2495 )"); 2496 } 2497 2498 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightSet) { 2499 ExpectDiagnosticsFor( 2500 R"( 2501 #include "unchecked_optional_access_test.h" 2502 2503 void target() { 2504 $ns::$optional<int> opt1 = 3; 2505 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2506 2507 if (opt2 == opt1) { 2508 opt2.value(); 2509 } else { 2510 opt2.value(); // [[unsafe]] 2511 } 2512 } 2513 )"); 2514 } 2515 2516 TEST_P(UncheckedOptionalAccessTest, EqualityCheckVerifySetAfterEq) { 2517 ExpectDiagnosticsFor( 2518 R"( 2519 #include "unchecked_optional_access_test.h" 2520 2521 void target() { 2522 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>(); 2523 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2524 2525 if (opt1 == opt2) { 2526 if (opt1.has_value()) 2527 opt2.value(); 2528 if (opt2.has_value()) 2529 opt1.value(); 2530 } 2531 } 2532 )"); 2533 } 2534 2535 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftUnset) { 2536 ExpectDiagnosticsFor( 2537 R"( 2538 #include "unchecked_optional_access_test.h" 2539 2540 void target() { 2541 $ns::$optional<int> opt1 = $ns::nullopt; 2542 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2543 2544 if (opt1 == opt2) { 2545 opt2.value(); // [[unsafe]] 2546 } else { 2547 opt2.value(); 2548 } 2549 } 2550 )"); 2551 } 2552 2553 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightUnset) { 2554 ExpectDiagnosticsFor( 2555 R"( 2556 #include "unchecked_optional_access_test.h" 2557 2558 void target() { 2559 $ns::$optional<int> opt1 = $ns::nullopt; 2560 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2561 2562 if (opt2 == opt1) { 2563 opt2.value(); // [[unsafe]] 2564 } else { 2565 opt2.value(); 2566 } 2567 } 2568 )"); 2569 } 2570 2571 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightNullopt) { 2572 ExpectDiagnosticsFor( 2573 R"( 2574 #include "unchecked_optional_access_test.h" 2575 2576 void target() { 2577 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2578 2579 if (opt == $ns::nullopt) { 2580 opt.value(); // [[unsafe]] 2581 } else { 2582 opt.value(); 2583 } 2584 } 2585 )"); 2586 } 2587 2588 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftNullopt) { 2589 ExpectDiagnosticsFor( 2590 R"( 2591 #include "unchecked_optional_access_test.h" 2592 2593 void target() { 2594 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2595 2596 if ($ns::nullopt == opt) { 2597 opt.value(); // [[unsafe]] 2598 } else { 2599 opt.value(); 2600 } 2601 } 2602 )"); 2603 } 2604 2605 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightValue) { 2606 ExpectDiagnosticsFor( 2607 R"( 2608 #include "unchecked_optional_access_test.h" 2609 2610 void target() { 2611 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2612 2613 if (opt == 3) { 2614 opt.value(); 2615 } else { 2616 opt.value(); // [[unsafe]] 2617 } 2618 } 2619 )"); 2620 } 2621 2622 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftValue) { 2623 ExpectDiagnosticsFor( 2624 R"( 2625 #include "unchecked_optional_access_test.h" 2626 2627 void target() { 2628 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2629 2630 if (3 == opt) { 2631 opt.value(); 2632 } else { 2633 opt.value(); // [[unsafe]] 2634 } 2635 } 2636 )"); 2637 } 2638 2639 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftSet) { 2640 ExpectDiagnosticsFor( 2641 R"( 2642 #include "unchecked_optional_access_test.h" 2643 2644 void target() { 2645 $ns::$optional<int> opt1 = 3; 2646 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2647 2648 if (opt1 != opt2) { 2649 opt2.value(); // [[unsafe]] 2650 } else { 2651 opt2.value(); 2652 } 2653 } 2654 )"); 2655 } 2656 2657 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightSet) { 2658 ExpectDiagnosticsFor( 2659 R"( 2660 #include "unchecked_optional_access_test.h" 2661 2662 void target() { 2663 $ns::$optional<int> opt1 = 3; 2664 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2665 2666 if (opt2 != opt1) { 2667 opt2.value(); // [[unsafe]] 2668 } else { 2669 opt2.value(); 2670 } 2671 } 2672 )"); 2673 } 2674 2675 TEST_P(UncheckedOptionalAccessTest, InequalityCheckVerifySetAfterEq) { 2676 ExpectDiagnosticsFor( 2677 R"( 2678 #include "unchecked_optional_access_test.h" 2679 2680 void target() { 2681 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>(); 2682 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2683 2684 if (opt1 != opt2) { 2685 if (opt1.has_value()) 2686 opt2.value(); // [[unsafe]] 2687 if (opt2.has_value()) 2688 opt1.value(); // [[unsafe]] 2689 } 2690 } 2691 )"); 2692 } 2693 2694 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftUnset) { 2695 ExpectDiagnosticsFor( 2696 R"( 2697 #include "unchecked_optional_access_test.h" 2698 2699 void target() { 2700 $ns::$optional<int> opt1 = $ns::nullopt; 2701 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2702 2703 if (opt1 != opt2) { 2704 opt2.value(); 2705 } else { 2706 opt2.value(); // [[unsafe]] 2707 } 2708 } 2709 )"); 2710 } 2711 2712 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightUnset) { 2713 ExpectDiagnosticsFor( 2714 R"( 2715 #include "unchecked_optional_access_test.h" 2716 2717 void target() { 2718 $ns::$optional<int> opt1 = $ns::nullopt; 2719 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2720 2721 if (opt2 != opt1) { 2722 opt2.value(); 2723 } else { 2724 opt2.value(); // [[unsafe]] 2725 } 2726 } 2727 )"); 2728 } 2729 2730 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightNullopt) { 2731 ExpectDiagnosticsFor( 2732 R"( 2733 #include "unchecked_optional_access_test.h" 2734 2735 void target() { 2736 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2737 2738 if (opt != $ns::nullopt) { 2739 opt.value(); 2740 } else { 2741 opt.value(); // [[unsafe]] 2742 } 2743 } 2744 )"); 2745 } 2746 2747 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftNullopt) { 2748 ExpectDiagnosticsFor( 2749 R"( 2750 #include "unchecked_optional_access_test.h" 2751 2752 void target() { 2753 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2754 2755 if ($ns::nullopt != opt) { 2756 opt.value(); 2757 } else { 2758 opt.value(); // [[unsafe]] 2759 } 2760 } 2761 )"); 2762 } 2763 2764 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightValue) { 2765 ExpectDiagnosticsFor( 2766 R"( 2767 #include "unchecked_optional_access_test.h" 2768 2769 void target() { 2770 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2771 2772 if (opt != 3) { 2773 opt.value(); // [[unsafe]] 2774 } else { 2775 opt.value(); 2776 } 2777 } 2778 )"); 2779 } 2780 2781 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftValue) { 2782 ExpectDiagnosticsFor( 2783 R"( 2784 #include "unchecked_optional_access_test.h" 2785 2786 void target() { 2787 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2788 2789 if (3 != opt) { 2790 opt.value(); // [[unsafe]] 2791 } else { 2792 opt.value(); 2793 } 2794 } 2795 )"); 2796 } 2797 2798 // Verifies that the model sees through aliases. 2799 TEST_P(UncheckedOptionalAccessTest, WithAlias) { 2800 ExpectDiagnosticsFor( 2801 R"( 2802 #include "unchecked_optional_access_test.h" 2803 2804 template <typename T> 2805 using MyOptional = $ns::$optional<T>; 2806 2807 void target(MyOptional<int> opt) { 2808 opt.value(); // [[unsafe]] 2809 } 2810 )"); 2811 } 2812 2813 TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) { 2814 // Basic test that nested values are populated. We nest an optional because 2815 // its easy to use in a test, but the type of the nested value shouldn't 2816 // matter. 2817 ExpectDiagnosticsFor( 2818 R"( 2819 #include "unchecked_optional_access_test.h" 2820 2821 using Foo = $ns::$optional<std::string>; 2822 2823 void target($ns::$optional<Foo> foo) { 2824 if (foo && *foo) { 2825 foo->value(); 2826 } 2827 } 2828 )"); 2829 2830 // Mutation is supported for nested values. 2831 ExpectDiagnosticsFor( 2832 R"( 2833 #include "unchecked_optional_access_test.h" 2834 2835 using Foo = $ns::$optional<std::string>; 2836 2837 void target($ns::$optional<Foo> foo) { 2838 if (foo && *foo) { 2839 foo->reset(); 2840 foo->value(); // [[unsafe]] 2841 } 2842 } 2843 )"); 2844 } 2845 2846 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignValue) { 2847 ExpectDiagnosticsFor( 2848 R"( 2849 #include "unchecked_optional_access_test.h" 2850 2851 using OptionalInt = $ns::$optional<int>; 2852 2853 void target($ns::$optional<OptionalInt> opt) { 2854 if (!opt) return; 2855 2856 // Accessing the outer optional is OK now. 2857 *opt; 2858 2859 // But accessing the nested optional is still unsafe because we haven't 2860 // checked it. 2861 **opt; // [[unsafe]] 2862 2863 *opt = 1; 2864 2865 // Accessing the nested optional is safe after assigning a value to it. 2866 **opt; 2867 } 2868 )"); 2869 } 2870 2871 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignOptional) { 2872 ExpectDiagnosticsFor( 2873 R"( 2874 #include "unchecked_optional_access_test.h" 2875 2876 using OptionalInt = $ns::$optional<int>; 2877 2878 void target($ns::$optional<OptionalInt> opt) { 2879 if (!opt) return; 2880 2881 // Accessing the outer optional is OK now. 2882 *opt; 2883 2884 // But accessing the nested optional is still unsafe because we haven't 2885 // checked it. 2886 **opt; // [[unsafe]] 2887 2888 // Assign from `optional<short>` so that we trigger conversion assignment 2889 // instead of move assignment. 2890 *opt = $ns::$optional<short>(); 2891 2892 // Accessing the nested optional is still unsafe after assigning an empty 2893 // optional to it. 2894 **opt; // [[unsafe]] 2895 } 2896 )"); 2897 } 2898 2899 // Tests that structs can be nested. We use an optional field because its easy 2900 // to use in a test, but the type of the field shouldn't matter. 2901 TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) { 2902 ExpectDiagnosticsFor( 2903 R"( 2904 #include "unchecked_optional_access_test.h" 2905 2906 struct Foo { 2907 $ns::$optional<std::string> opt; 2908 }; 2909 2910 void target($ns::$optional<Foo> foo) { 2911 if (foo && foo->opt) { 2912 foo->opt.value(); 2913 } 2914 } 2915 )"); 2916 } 2917 2918 // FIXME: A case that we should handle but currently don't. 2919 // When there is a field of type reference to non-optional, we may 2920 // stop recursively creating storage locations. 2921 // E.g., the field `second` below in `pair` should eventually lead to 2922 // the optional `x` in `A`. 2923 TEST_P(UncheckedOptionalAccessTest, NestedOptionalThroughNonOptionalRefField) { 2924 ExpectDiagnosticsFor(R"( 2925 #include "unchecked_optional_access_test.h" 2926 2927 struct A { 2928 $ns::$optional<int> x; 2929 }; 2930 2931 struct pair { 2932 int first; 2933 const A &second; 2934 }; 2935 2936 struct B { 2937 $ns::$optional<pair>& nonConstGetRef(); 2938 }; 2939 2940 void target(B b) { 2941 const auto& maybe_pair = b.nonConstGetRef(); 2942 if (!maybe_pair.has_value()) 2943 return; 2944 2945 if(!maybe_pair->second.x.has_value()) 2946 return; 2947 maybe_pair->second.x.value(); // [[unsafe]] 2948 } 2949 )"); 2950 } 2951 2952 TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) { 2953 ExpectDiagnosticsFor( 2954 R"( 2955 #include "unchecked_optional_access_test.h" 2956 2957 using Foo = $ns::$optional<std::string>; 2958 2959 void target($ns::$optional<Foo> foo, bool b) { 2960 if (!foo.has_value()) return; 2961 if (b) { 2962 if (!foo->has_value()) return; 2963 // We have created `foo.value()`. 2964 foo->value(); 2965 } else { 2966 if (!foo->has_value()) return; 2967 // We have created `foo.value()` again, in a different environment. 2968 foo->value(); 2969 } 2970 // Now we merge the two values. UncheckedOptionalAccessModel::merge() will 2971 // throw away the "value" property. 2972 foo->value(); 2973 } 2974 )"); 2975 } 2976 2977 // This test is aimed at the core model, not the diagnostic. It is a regression 2978 // test against a crash when using non-trivial smart pointers, like 2979 // `std::unique_ptr`. As such, it doesn't test the access itself, which would be 2980 // ignored regardless because of `IgnoreSmartPointerDereference = true`, above. 2981 TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) { 2982 ExpectDiagnosticsFor( 2983 R"( 2984 #include "unchecked_optional_access_test.h" 2985 2986 template <typename T> 2987 struct smart_ptr { 2988 typename std::add_lvalue_reference<T>::type operator*() &; 2989 }; 2990 2991 void target() { 2992 smart_ptr<$ns::$optional<int>> x; 2993 // Verify that this assignment does not crash. 2994 *x = 3; 2995 } 2996 )"); 2997 } 2998 2999 TEST_P(UncheckedOptionalAccessTest, CorrelatedBranches) { 3000 ExpectDiagnosticsFor(R"code( 3001 #include "unchecked_optional_access_test.h" 3002 3003 void target(bool b, $ns::$optional<int> opt) { 3004 if (b || opt.has_value()) { 3005 if (!b) { 3006 opt.value(); 3007 } 3008 } 3009 } 3010 )code"); 3011 3012 ExpectDiagnosticsFor(R"code( 3013 #include "unchecked_optional_access_test.h" 3014 3015 void target(bool b, $ns::$optional<int> opt) { 3016 if (b && !opt.has_value()) return; 3017 if (b) { 3018 opt.value(); 3019 } 3020 } 3021 )code"); 3022 3023 ExpectDiagnosticsFor( 3024 R"code( 3025 #include "unchecked_optional_access_test.h" 3026 3027 void target(bool b, $ns::$optional<int> opt) { 3028 if (opt.has_value()) b = true; 3029 if (b) { 3030 opt.value(); // [[unsafe]] 3031 } 3032 } 3033 )code"); 3034 3035 ExpectDiagnosticsFor(R"code( 3036 #include "unchecked_optional_access_test.h" 3037 3038 void target(bool b, $ns::$optional<int> opt) { 3039 if (b) return; 3040 if (opt.has_value()) b = true; 3041 if (b) { 3042 opt.value(); 3043 } 3044 } 3045 )code"); 3046 3047 ExpectDiagnosticsFor(R"( 3048 #include "unchecked_optional_access_test.h" 3049 3050 void target(bool b, $ns::$optional<int> opt) { 3051 if (opt.has_value() == b) { 3052 if (b) { 3053 opt.value(); 3054 } 3055 } 3056 } 3057 )"); 3058 3059 ExpectDiagnosticsFor(R"( 3060 #include "unchecked_optional_access_test.h" 3061 3062 void target(bool b, $ns::$optional<int> opt) { 3063 if (opt.has_value() != b) { 3064 if (!b) { 3065 opt.value(); 3066 } 3067 } 3068 } 3069 )"); 3070 3071 ExpectDiagnosticsFor(R"( 3072 #include "unchecked_optional_access_test.h" 3073 3074 void target(bool b) { 3075 $ns::$optional<int> opt1 = $ns::nullopt; 3076 $ns::$optional<int> opt2; 3077 if (b) { 3078 opt2 = $ns::nullopt; 3079 } else { 3080 opt2 = $ns::nullopt; 3081 } 3082 if (opt2.has_value()) { 3083 opt1.value(); 3084 } 3085 } 3086 )"); 3087 } 3088 3089 TEST_P(UncheckedOptionalAccessTest, JoinDistinctValues) { 3090 ExpectDiagnosticsFor( 3091 R"code( 3092 #include "unchecked_optional_access_test.h" 3093 3094 void target(bool b) { 3095 $ns::$optional<int> opt; 3096 if (b) { 3097 opt = Make<$ns::$optional<int>>(); 3098 } else { 3099 opt = Make<$ns::$optional<int>>(); 3100 } 3101 if (opt.has_value()) { 3102 opt.value(); 3103 } else { 3104 opt.value(); // [[unsafe]] 3105 } 3106 } 3107 )code"); 3108 3109 ExpectDiagnosticsFor(R"code( 3110 #include "unchecked_optional_access_test.h" 3111 3112 void target(bool b) { 3113 $ns::$optional<int> opt; 3114 if (b) { 3115 opt = Make<$ns::$optional<int>>(); 3116 if (!opt.has_value()) return; 3117 } else { 3118 opt = Make<$ns::$optional<int>>(); 3119 if (!opt.has_value()) return; 3120 } 3121 opt.value(); 3122 } 3123 )code"); 3124 3125 ExpectDiagnosticsFor( 3126 R"code( 3127 #include "unchecked_optional_access_test.h" 3128 3129 void target(bool b) { 3130 $ns::$optional<int> opt; 3131 if (b) { 3132 opt = Make<$ns::$optional<int>>(); 3133 if (!opt.has_value()) return; 3134 } else { 3135 opt = Make<$ns::$optional<int>>(); 3136 } 3137 opt.value(); // [[unsafe]] 3138 } 3139 )code"); 3140 3141 ExpectDiagnosticsFor( 3142 R"code( 3143 #include "unchecked_optional_access_test.h" 3144 3145 void target(bool b) { 3146 $ns::$optional<int> opt; 3147 if (b) { 3148 opt = 1; 3149 } else { 3150 opt = 2; 3151 } 3152 opt.value(); 3153 } 3154 )code"); 3155 3156 ExpectDiagnosticsFor( 3157 R"code( 3158 #include "unchecked_optional_access_test.h" 3159 3160 void target(bool b) { 3161 $ns::$optional<int> opt; 3162 if (b) { 3163 opt = 1; 3164 } else { 3165 opt = Make<$ns::$optional<int>>(); 3166 } 3167 opt.value(); // [[unsafe]] 3168 } 3169 )code"); 3170 } 3171 3172 TEST_P(UncheckedOptionalAccessTest, AccessValueInLoop) { 3173 ExpectDiagnosticsFor(R"( 3174 #include "unchecked_optional_access_test.h" 3175 3176 void target() { 3177 $ns::$optional<int> opt = 3; 3178 while (Make<bool>()) { 3179 opt.value(); 3180 } 3181 } 3182 )"); 3183 } 3184 3185 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopWithCheckSafe) { 3186 ExpectDiagnosticsFor(R"( 3187 #include "unchecked_optional_access_test.h" 3188 3189 void target() { 3190 $ns::$optional<int> opt = 3; 3191 while (Make<bool>()) { 3192 opt.value(); 3193 3194 opt = Make<$ns::$optional<int>>(); 3195 if (!opt.has_value()) return; 3196 } 3197 } 3198 )"); 3199 } 3200 3201 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopNoCheckUnsafe) { 3202 ExpectDiagnosticsFor( 3203 R"( 3204 #include "unchecked_optional_access_test.h" 3205 3206 void target() { 3207 $ns::$optional<int> opt = 3; 3208 while (Make<bool>()) { 3209 opt.value(); // [[unsafe]] 3210 3211 opt = Make<$ns::$optional<int>>(); 3212 } 3213 } 3214 )"); 3215 } 3216 3217 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnsetUnsafe) { 3218 ExpectDiagnosticsFor( 3219 R"( 3220 #include "unchecked_optional_access_test.h" 3221 3222 void target() { 3223 $ns::$optional<int> opt = 3; 3224 while (Make<bool>()) 3225 opt = $ns::nullopt; 3226 $ns::$optional<int> opt2 = $ns::nullopt; 3227 if (opt.has_value()) 3228 opt2 = $ns::$optional<int>(3); 3229 opt2.value(); // [[unsafe]] 3230 } 3231 )"); 3232 } 3233 3234 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToSetUnsafe) { 3235 ExpectDiagnosticsFor( 3236 R"( 3237 #include "unchecked_optional_access_test.h" 3238 3239 void target() { 3240 $ns::$optional<int> opt = $ns::nullopt; 3241 while (Make<bool>()) 3242 opt = $ns::$optional<int>(3); 3243 $ns::$optional<int> opt2 = $ns::nullopt; 3244 if (!opt.has_value()) 3245 opt2 = $ns::$optional<int>(3); 3246 opt2.value(); // [[unsafe]] 3247 } 3248 )"); 3249 } 3250 3251 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnknownUnsafe) { 3252 ExpectDiagnosticsFor( 3253 R"( 3254 #include "unchecked_optional_access_test.h" 3255 3256 void target() { 3257 $ns::$optional<int> opt = $ns::nullopt; 3258 while (Make<bool>()) 3259 opt = Make<$ns::$optional<int>>(); 3260 $ns::$optional<int> opt2 = $ns::nullopt; 3261 if (!opt.has_value()) 3262 opt2 = $ns::$optional<int>(3); 3263 opt2.value(); // [[unsafe]] 3264 } 3265 )"); 3266 } 3267 3268 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopBadConditionUnsafe) { 3269 ExpectDiagnosticsFor( 3270 R"( 3271 #include "unchecked_optional_access_test.h" 3272 3273 void target() { 3274 $ns::$optional<int> opt = 3; 3275 while (Make<bool>()) { 3276 opt.value(); // [[unsafe]] 3277 3278 opt = Make<$ns::$optional<int>>(); 3279 if (!opt.has_value()) continue; 3280 } 3281 } 3282 )"); 3283 } 3284 3285 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromStruct) { 3286 ExpectDiagnosticsFor(R"( 3287 #include "unchecked_optional_access_test.h" 3288 3289 struct kv { $ns::$optional<int> opt; int x; }; 3290 int target() { 3291 auto [contents, x] = Make<kv>(); 3292 return contents ? *contents : x; 3293 } 3294 )"); 3295 3296 ExpectDiagnosticsFor(R"( 3297 #include "unchecked_optional_access_test.h" 3298 3299 template <typename T1, typename T2> 3300 struct pair { T1 fst; T2 snd; }; 3301 int target() { 3302 auto [contents, x] = Make<pair<$ns::$optional<int>, int>>(); 3303 return contents ? *contents : x; 3304 } 3305 )"); 3306 } 3307 3308 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromTupleLikeType) { 3309 ExpectDiagnosticsFor(R"( 3310 #include "unchecked_optional_access_test.h" 3311 3312 namespace std { 3313 template <class> struct tuple_size; 3314 template <size_t, class> struct tuple_element; 3315 template <class...> class tuple; 3316 3317 template <class... T> 3318 struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {}; 3319 3320 template <size_t I, class... T> 3321 struct tuple_element<I, tuple<T...>> { 3322 using type = __type_pack_element<I, T...>; 3323 }; 3324 3325 template <class...> class tuple {}; 3326 template <size_t I, class... T> 3327 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 3328 } // namespace std 3329 3330 std::tuple<$ns::$optional<const char *>, int> get_opt(); 3331 void target() { 3332 auto [content, ck] = get_opt(); 3333 content ? *content : ""; 3334 } 3335 )"); 3336 } 3337 3338 TEST_P(UncheckedOptionalAccessTest, CtorInitializerNullopt) { 3339 using namespace ast_matchers; 3340 ExpectDiagnosticsFor( 3341 R"( 3342 #include "unchecked_optional_access_test.h" 3343 3344 struct Target { 3345 Target(): opt($ns::nullopt) { 3346 opt.value(); // [[unsafe]] 3347 } 3348 $ns::$optional<int> opt; 3349 }; 3350 )", 3351 cxxConstructorDecl(ofClass(hasName("Target")))); 3352 } 3353 3354 TEST_P(UncheckedOptionalAccessTest, CtorInitializerValue) { 3355 using namespace ast_matchers; 3356 ExpectDiagnosticsFor( 3357 R"( 3358 #include "unchecked_optional_access_test.h" 3359 3360 struct Target { 3361 Target(): opt(3) { 3362 opt.value(); 3363 } 3364 $ns::$optional<int> opt; 3365 }; 3366 )", 3367 cxxConstructorDecl(ofClass(hasName("Target")))); 3368 } 3369 3370 // This is regression test, it shouldn't crash. 3371 TEST_P(UncheckedOptionalAccessTest, Bitfield) { 3372 using namespace ast_matchers; 3373 ExpectDiagnosticsFor( 3374 R"( 3375 #include "unchecked_optional_access_test.h" 3376 struct Dst { 3377 unsigned int n : 1; 3378 }; 3379 void target() { 3380 $ns::$optional<bool> v; 3381 Dst d; 3382 if (v.has_value()) 3383 d.n = v.value(); 3384 } 3385 )"); 3386 } 3387 3388 TEST_P(UncheckedOptionalAccessTest, LambdaParam) { 3389 ExpectDiagnosticsForLambda(R"( 3390 #include "unchecked_optional_access_test.h" 3391 3392 void target() { 3393 []($ns::$optional<int> opt) { 3394 if (opt.has_value()) { 3395 opt.value(); 3396 } else { 3397 opt.value(); // [[unsafe]] 3398 } 3399 }(Make<$ns::$optional<int>>()); 3400 } 3401 )"); 3402 } 3403 3404 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopy) { 3405 ExpectDiagnosticsForLambda(R"( 3406 #include "unchecked_optional_access_test.h" 3407 3408 void target($ns::$optional<int> opt) { 3409 [opt]() { 3410 if (opt.has_value()) { 3411 opt.value(); 3412 } else { 3413 opt.value(); // [[unsafe]] 3414 } 3415 }(); 3416 } 3417 )"); 3418 } 3419 3420 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReference) { 3421 ExpectDiagnosticsForLambda(R"( 3422 #include "unchecked_optional_access_test.h" 3423 3424 void target($ns::$optional<int> opt) { 3425 [&opt]() { 3426 if (opt.has_value()) { 3427 opt.value(); 3428 } else { 3429 opt.value(); // [[unsafe]] 3430 } 3431 }(); 3432 } 3433 )"); 3434 } 3435 3436 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureWithInitializer) { 3437 ExpectDiagnosticsForLambda(R"( 3438 #include "unchecked_optional_access_test.h" 3439 3440 void target($ns::$optional<int> opt) { 3441 [opt2=opt]() { 3442 if (opt2.has_value()) { 3443 opt2.value(); 3444 } else { 3445 opt2.value(); // [[unsafe]] 3446 } 3447 }(); 3448 } 3449 )"); 3450 } 3451 3452 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopyImplicit) { 3453 ExpectDiagnosticsForLambda(R"( 3454 #include "unchecked_optional_access_test.h" 3455 3456 void target($ns::$optional<int> opt) { 3457 [=]() { 3458 if (opt.has_value()) { 3459 opt.value(); 3460 } else { 3461 opt.value(); // [[unsafe]] 3462 } 3463 }(); 3464 } 3465 )"); 3466 } 3467 3468 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReferenceImplicit) { 3469 ExpectDiagnosticsForLambda(R"( 3470 #include "unchecked_optional_access_test.h" 3471 3472 void target($ns::$optional<int> opt) { 3473 [&]() { 3474 if (opt.has_value()) { 3475 opt.value(); 3476 } else { 3477 opt.value(); // [[unsafe]] 3478 } 3479 }(); 3480 } 3481 )"); 3482 } 3483 3484 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureThis) { 3485 ExpectDiagnosticsForLambda(R"( 3486 #include "unchecked_optional_access_test.h" 3487 3488 struct Foo { 3489 $ns::$optional<int> opt; 3490 3491 void target() { 3492 [this]() { 3493 if (opt.has_value()) { 3494 opt.value(); 3495 } else { 3496 opt.value(); // [[unsafe]] 3497 } 3498 }(); 3499 } 3500 }; 3501 )"); 3502 } 3503 3504 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureStateNotPropagated) { 3505 // We can't propagate information from the surrounding context. 3506 ExpectDiagnosticsForLambda(R"( 3507 #include "unchecked_optional_access_test.h" 3508 3509 void target($ns::$optional<int> opt) { 3510 if (opt.has_value()) { 3511 [&opt]() { 3512 opt.value(); // [[unsafe]] 3513 }(); 3514 } 3515 } 3516 )"); 3517 } 3518 3519 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptional) { 3520 ExpectDiagnosticsFor(R"( 3521 #include "unchecked_optional_access_test.h" 3522 3523 struct Derived : public $ns::$optional<int> {}; 3524 3525 void target(Derived opt) { 3526 *opt; // [[unsafe]] 3527 if (opt.has_value()) 3528 *opt; 3529 3530 // The same thing, but with a pointer receiver. 3531 Derived *popt = &opt; 3532 **popt; // [[unsafe]] 3533 if (popt->has_value()) 3534 **popt; 3535 } 3536 )"); 3537 } 3538 3539 TEST_P(UncheckedOptionalAccessTest, ClassTemplateDerivedFromOptional) { 3540 ExpectDiagnosticsFor(R"( 3541 #include "unchecked_optional_access_test.h" 3542 3543 template <class T> 3544 struct Derived : public $ns::$optional<T> {}; 3545 3546 void target(Derived<int> opt) { 3547 *opt; // [[unsafe]] 3548 if (opt.has_value()) 3549 *opt; 3550 3551 // The same thing, but with a pointer receiver. 3552 Derived<int> *popt = &opt; 3553 **popt; // [[unsafe]] 3554 if (popt->has_value()) 3555 **popt; 3556 } 3557 )"); 3558 } 3559 3560 TEST_P(UncheckedOptionalAccessTest, ClassDerivedPrivatelyFromOptional) { 3561 // Classes that derive privately from optional can themselves still call 3562 // member functions of optional. Check that we model the optional correctly 3563 // in this situation. 3564 ExpectDiagnosticsFor(R"( 3565 #include "unchecked_optional_access_test.h" 3566 3567 struct Derived : private $ns::$optional<int> { 3568 void Method() { 3569 **this; // [[unsafe]] 3570 if (this->has_value()) 3571 **this; 3572 } 3573 }; 3574 )", 3575 ast_matchers::hasName("Method")); 3576 } 3577 3578 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptionalValueConstructor) { 3579 ExpectDiagnosticsFor(R"( 3580 #include "unchecked_optional_access_test.h" 3581 3582 struct Derived : public $ns::$optional<int> { 3583 Derived(int); 3584 }; 3585 3586 void target(Derived opt) { 3587 *opt; // [[unsafe]] 3588 opt = 1; 3589 *opt; 3590 } 3591 )"); 3592 } 3593 3594 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessor) { 3595 ExpectDiagnosticsFor(R"cc( 3596 #include "unchecked_optional_access_test.h" 3597 3598 struct A { 3599 const $ns::$optional<int>& get() const { return x; } 3600 $ns::$optional<int> x; 3601 }; 3602 3603 void target(A& a) { 3604 if (a.get().has_value()) { 3605 a.get().value(); 3606 } 3607 } 3608 )cc"); 3609 } 3610 3611 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModInBetween) { 3612 ExpectDiagnosticsFor(R"cc( 3613 #include "unchecked_optional_access_test.h" 3614 3615 struct A { 3616 const $ns::$optional<int>& get() const { return x; } 3617 void clear(); 3618 $ns::$optional<int> x; 3619 }; 3620 3621 void target(A& a) { 3622 if (a.get().has_value()) { 3623 a.clear(); 3624 a.get().value(); // [[unsafe]] 3625 } 3626 } 3627 )cc"); 3628 } 3629 3630 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModReturningOptional) { 3631 ExpectDiagnosticsFor(R"cc( 3632 #include "unchecked_optional_access_test.h" 3633 3634 struct A { 3635 const $ns::$optional<int>& get() const { return x; } 3636 $ns::$optional<int> take(); 3637 $ns::$optional<int> x; 3638 }; 3639 3640 void target(A& a) { 3641 if (a.get().has_value()) { 3642 $ns::$optional<int> other = a.take(); 3643 a.get().value(); // [[unsafe]] 3644 if (other.has_value()) { 3645 other.value(); 3646 } 3647 } 3648 } 3649 )cc"); 3650 } 3651 3652 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorDifferentObjects) { 3653 ExpectDiagnosticsFor(R"cc( 3654 #include "unchecked_optional_access_test.h" 3655 3656 struct A { 3657 const $ns::$optional<int>& get() const { return x; } 3658 $ns::$optional<int> x; 3659 }; 3660 3661 void target(A& a1, A& a2) { 3662 if (a1.get().has_value()) { 3663 a2.get().value(); // [[unsafe]] 3664 } 3665 } 3666 )cc"); 3667 } 3668 3669 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorLoop) { 3670 ExpectDiagnosticsFor(R"cc( 3671 #include "unchecked_optional_access_test.h" 3672 3673 struct A { 3674 const $ns::$optional<int>& get() const { return x; } 3675 $ns::$optional<int> x; 3676 }; 3677 3678 void target(A& a, int N) { 3679 for (int i = 0; i < N; ++i) { 3680 if (a.get().has_value()) { 3681 a.get().value(); 3682 } 3683 } 3684 } 3685 )cc"); 3686 } 3687 3688 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessor) { 3689 ExpectDiagnosticsFor(R"cc( 3690 #include "unchecked_optional_access_test.h" 3691 3692 struct A { 3693 $ns::$optional<int> get() const { return x; } 3694 $ns::$optional<int> x; 3695 }; 3696 3697 void target(A& a) { 3698 if (a.get().has_value()) { 3699 a.get().value(); 3700 } 3701 } 3702 )cc"); 3703 } 3704 3705 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessorWithModInBetween) { 3706 ExpectDiagnosticsFor(R"cc( 3707 #include "unchecked_optional_access_test.h" 3708 3709 struct A { 3710 $ns::$optional<int> get() const { return x; } 3711 void clear(); 3712 $ns::$optional<int> x; 3713 }; 3714 3715 void target(A& a) { 3716 if (a.get().has_value()) { 3717 a.clear(); 3718 a.get().value(); // [[unsafe]] 3719 } 3720 } 3721 )cc"); 3722 } 3723 3724 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessor) { 3725 ExpectDiagnosticsFor(R"cc( 3726 #include "unchecked_optional_access_test.h" 3727 3728 struct A { 3729 bool isFoo() const { return f; } 3730 bool f; 3731 }; 3732 3733 void target(A& a) { 3734 std::optional<int> opt; 3735 if (a.isFoo()) { 3736 opt = 1; 3737 } 3738 if (a.isFoo()) { 3739 opt.value(); 3740 } 3741 } 3742 )cc"); 3743 } 3744 3745 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessorWithModInBetween) { 3746 ExpectDiagnosticsFor(R"cc( 3747 #include "unchecked_optional_access_test.h" 3748 3749 struct A { 3750 bool isFoo() const { return f; } 3751 void clear(); 3752 bool f; 3753 }; 3754 3755 void target(A& a) { 3756 std::optional<int> opt; 3757 if (a.isFoo()) { 3758 opt = 1; 3759 } 3760 a.clear(); 3761 if (a.isFoo()) { 3762 opt.value(); // [[unsafe]] 3763 } 3764 } 3765 )cc"); 3766 } 3767 3768 // FIXME: Add support for: 3769 // - constructors (copy, move) 3770 // - assignment operators (default, copy, move) 3771 // - invalidation (passing optional by non-const reference/pointer) 3772