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, OptionalFieldModified) { 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, StdSwap) { 2191 ExpectDiagnosticsFor( 2192 R"( 2193 #include "unchecked_optional_access_test.h" 2194 2195 void target() { 2196 $ns::$optional<int> opt1 = $ns::nullopt; 2197 $ns::$optional<int> opt2 = 3; 2198 2199 std::swap(opt1, opt2); 2200 2201 opt1.value(); 2202 2203 opt2.value(); // [[unsafe]] 2204 } 2205 )"); 2206 2207 ExpectDiagnosticsFor( 2208 R"( 2209 #include "unchecked_optional_access_test.h" 2210 2211 void target() { 2212 $ns::$optional<int> opt1 = $ns::nullopt; 2213 $ns::$optional<int> opt2 = 3; 2214 2215 std::swap(opt2, opt1); 2216 2217 opt1.value(); 2218 2219 opt2.value(); // [[unsafe]] 2220 } 2221 )"); 2222 } 2223 2224 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocLeft) { 2225 ExpectDiagnosticsFor( 2226 R"( 2227 #include "unchecked_optional_access_test.h" 2228 2229 struct L { $ns::$optional<int> hd; L* tl; }; 2230 2231 void target() { 2232 $ns::$optional<int> foo = 3; 2233 L bar; 2234 2235 // Any `tl` beyond the first is not modeled. 2236 bar.tl->tl->hd.swap(foo); 2237 2238 bar.tl->tl->hd.value(); // [[unsafe]] 2239 foo.value(); // [[unsafe]] 2240 } 2241 )"); 2242 } 2243 2244 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocRight) { 2245 ExpectDiagnosticsFor( 2246 R"( 2247 #include "unchecked_optional_access_test.h" 2248 2249 struct L { $ns::$optional<int> hd; L* tl; }; 2250 2251 void target() { 2252 $ns::$optional<int> foo = 3; 2253 L bar; 2254 2255 // Any `tl` beyond the first is not modeled. 2256 foo.swap(bar.tl->tl->hd); 2257 2258 bar.tl->tl->hd.value(); // [[unsafe]] 2259 foo.value(); // [[unsafe]] 2260 } 2261 )"); 2262 } 2263 2264 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftSet) { 2265 ExpectDiagnosticsFor( 2266 R"( 2267 #include "unchecked_optional_access_test.h" 2268 2269 struct S { int x; }; 2270 struct A { $ns::$optional<S> late; }; 2271 struct B { A f3; }; 2272 struct C { B f2; }; 2273 struct D { C f1; }; 2274 2275 void target() { 2276 $ns::$optional<S> foo = S{3}; 2277 D bar; 2278 2279 bar.f1.f2.f3.late.swap(foo); 2280 2281 bar.f1.f2.f3.late.value(); 2282 foo.value(); // [[unsafe]] 2283 } 2284 )"); 2285 } 2286 2287 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftUnset) { 2288 ExpectDiagnosticsFor( 2289 R"( 2290 #include "unchecked_optional_access_test.h" 2291 2292 struct S { int x; }; 2293 struct A { $ns::$optional<S> late; }; 2294 struct B { A f3; }; 2295 struct C { B f2; }; 2296 struct D { C f1; }; 2297 2298 void target() { 2299 $ns::$optional<S> foo; 2300 D bar; 2301 2302 bar.f1.f2.f3.late.swap(foo); 2303 2304 bar.f1.f2.f3.late.value(); // [[unsafe]] 2305 foo.value(); // [[unsafe]] 2306 } 2307 )"); 2308 } 2309 2310 // fixme: use recursion instead of depth. 2311 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightSet) { 2312 ExpectDiagnosticsFor( 2313 R"( 2314 #include "unchecked_optional_access_test.h" 2315 2316 struct S { int x; }; 2317 struct A { $ns::$optional<S> late; }; 2318 struct B { A f3; }; 2319 struct C { B f2; }; 2320 struct D { C f1; }; 2321 2322 void target() { 2323 $ns::$optional<S> foo = S{3}; 2324 D bar; 2325 2326 foo.swap(bar.f1.f2.f3.late); 2327 2328 bar.f1.f2.f3.late.value(); 2329 foo.value(); // [[unsafe]] 2330 } 2331 )"); 2332 } 2333 2334 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightUnset) { 2335 ExpectDiagnosticsFor( 2336 R"( 2337 #include "unchecked_optional_access_test.h" 2338 2339 struct S { int x; }; 2340 struct A { $ns::$optional<S> late; }; 2341 struct B { A f3; }; 2342 struct C { B f2; }; 2343 struct D { C f1; }; 2344 2345 void target() { 2346 $ns::$optional<S> foo; 2347 D bar; 2348 2349 foo.swap(bar.f1.f2.f3.late); 2350 2351 bar.f1.f2.f3.late.value(); // [[unsafe]] 2352 foo.value(); // [[unsafe]] 2353 } 2354 )"); 2355 } 2356 2357 TEST_P(UncheckedOptionalAccessTest, UniquePtrToOptional) { 2358 // We suppress diagnostics for optionals in smart pointers (other than 2359 // `optional` itself). 2360 ExpectDiagnosticsFor( 2361 R"( 2362 #include "unchecked_optional_access_test.h" 2363 2364 template <typename T> 2365 struct smart_ptr { 2366 T& operator*() &; 2367 T* operator->(); 2368 }; 2369 2370 void target() { 2371 smart_ptr<$ns::$optional<bool>> foo; 2372 foo->value(); 2373 (*foo).value(); 2374 } 2375 )"); 2376 } 2377 2378 TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) { 2379 // We suppress diagnostics for optional fields reachable from smart pointers 2380 // (other than `optional` itself) through (exactly) one member access. 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 struct Foo { 2392 $ns::$optional<int> opt; 2393 }; 2394 2395 void target() { 2396 smart_ptr<Foo> foo; 2397 *foo->opt; 2398 *(*foo).opt; 2399 } 2400 )"); 2401 } 2402 2403 TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) { 2404 ExpectDiagnosticsFor( 2405 R"( 2406 #include "unchecked_optional_access_test.h" 2407 2408 $ns::$optional<int> MakeOpt(); 2409 2410 void target() { 2411 $ns::$optional<int> opt = 0; 2412 opt = MakeOpt(); 2413 opt.value(); // [[unsafe]] 2414 } 2415 )"); 2416 ExpectDiagnosticsFor( 2417 R"( 2418 #include "unchecked_optional_access_test.h" 2419 2420 const $ns::$optional<int>& MakeOpt(); 2421 2422 void target() { 2423 $ns::$optional<int> opt = 0; 2424 opt = MakeOpt(); 2425 opt.value(); // [[unsafe]] 2426 } 2427 )"); 2428 2429 ExpectDiagnosticsFor( 2430 R"( 2431 #include "unchecked_optional_access_test.h" 2432 2433 using IntOpt = $ns::$optional<int>; 2434 IntOpt MakeOpt(); 2435 2436 void target() { 2437 IntOpt opt = 0; 2438 opt = MakeOpt(); 2439 opt.value(); // [[unsafe]] 2440 } 2441 )"); 2442 2443 ExpectDiagnosticsFor( 2444 R"( 2445 #include "unchecked_optional_access_test.h" 2446 2447 using IntOpt = $ns::$optional<int>; 2448 const IntOpt& MakeOpt(); 2449 2450 void target() { 2451 IntOpt opt = 0; 2452 opt = MakeOpt(); 2453 opt.value(); // [[unsafe]] 2454 } 2455 )"); 2456 } 2457 2458 2459 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftSet) { 2460 ExpectDiagnosticsFor( 2461 R"( 2462 #include "unchecked_optional_access_test.h" 2463 2464 void target() { 2465 $ns::$optional<int> opt1 = 3; 2466 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2467 2468 if (opt1 == opt2) { 2469 opt2.value(); 2470 } else { 2471 opt2.value(); // [[unsafe]] 2472 } 2473 } 2474 )"); 2475 } 2476 2477 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightSet) { 2478 ExpectDiagnosticsFor( 2479 R"( 2480 #include "unchecked_optional_access_test.h" 2481 2482 void target() { 2483 $ns::$optional<int> opt1 = 3; 2484 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2485 2486 if (opt2 == opt1) { 2487 opt2.value(); 2488 } else { 2489 opt2.value(); // [[unsafe]] 2490 } 2491 } 2492 )"); 2493 } 2494 2495 TEST_P(UncheckedOptionalAccessTest, EqualityCheckVerifySetAfterEq) { 2496 ExpectDiagnosticsFor( 2497 R"( 2498 #include "unchecked_optional_access_test.h" 2499 2500 void target() { 2501 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>(); 2502 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2503 2504 if (opt1 == opt2) { 2505 if (opt1.has_value()) 2506 opt2.value(); 2507 if (opt2.has_value()) 2508 opt1.value(); 2509 } 2510 } 2511 )"); 2512 } 2513 2514 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftUnset) { 2515 ExpectDiagnosticsFor( 2516 R"( 2517 #include "unchecked_optional_access_test.h" 2518 2519 void target() { 2520 $ns::$optional<int> opt1 = $ns::nullopt; 2521 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2522 2523 if (opt1 == opt2) { 2524 opt2.value(); // [[unsafe]] 2525 } else { 2526 opt2.value(); 2527 } 2528 } 2529 )"); 2530 } 2531 2532 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightUnset) { 2533 ExpectDiagnosticsFor( 2534 R"( 2535 #include "unchecked_optional_access_test.h" 2536 2537 void target() { 2538 $ns::$optional<int> opt1 = $ns::nullopt; 2539 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2540 2541 if (opt2 == opt1) { 2542 opt2.value(); // [[unsafe]] 2543 } else { 2544 opt2.value(); 2545 } 2546 } 2547 )"); 2548 } 2549 2550 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightNullopt) { 2551 ExpectDiagnosticsFor( 2552 R"( 2553 #include "unchecked_optional_access_test.h" 2554 2555 void target() { 2556 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2557 2558 if (opt == $ns::nullopt) { 2559 opt.value(); // [[unsafe]] 2560 } else { 2561 opt.value(); 2562 } 2563 } 2564 )"); 2565 } 2566 2567 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftNullopt) { 2568 ExpectDiagnosticsFor( 2569 R"( 2570 #include "unchecked_optional_access_test.h" 2571 2572 void target() { 2573 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2574 2575 if ($ns::nullopt == opt) { 2576 opt.value(); // [[unsafe]] 2577 } else { 2578 opt.value(); 2579 } 2580 } 2581 )"); 2582 } 2583 2584 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightValue) { 2585 ExpectDiagnosticsFor( 2586 R"( 2587 #include "unchecked_optional_access_test.h" 2588 2589 void target() { 2590 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2591 2592 if (opt == 3) { 2593 opt.value(); 2594 } else { 2595 opt.value(); // [[unsafe]] 2596 } 2597 } 2598 )"); 2599 } 2600 2601 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftValue) { 2602 ExpectDiagnosticsFor( 2603 R"( 2604 #include "unchecked_optional_access_test.h" 2605 2606 void target() { 2607 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2608 2609 if (3 == opt) { 2610 opt.value(); 2611 } else { 2612 opt.value(); // [[unsafe]] 2613 } 2614 } 2615 )"); 2616 } 2617 2618 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftSet) { 2619 ExpectDiagnosticsFor( 2620 R"( 2621 #include "unchecked_optional_access_test.h" 2622 2623 void target() { 2624 $ns::$optional<int> opt1 = 3; 2625 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2626 2627 if (opt1 != opt2) { 2628 opt2.value(); // [[unsafe]] 2629 } else { 2630 opt2.value(); 2631 } 2632 } 2633 )"); 2634 } 2635 2636 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightSet) { 2637 ExpectDiagnosticsFor( 2638 R"( 2639 #include "unchecked_optional_access_test.h" 2640 2641 void target() { 2642 $ns::$optional<int> opt1 = 3; 2643 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2644 2645 if (opt2 != opt1) { 2646 opt2.value(); // [[unsafe]] 2647 } else { 2648 opt2.value(); 2649 } 2650 } 2651 )"); 2652 } 2653 2654 TEST_P(UncheckedOptionalAccessTest, InequalityCheckVerifySetAfterEq) { 2655 ExpectDiagnosticsFor( 2656 R"( 2657 #include "unchecked_optional_access_test.h" 2658 2659 void target() { 2660 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>(); 2661 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2662 2663 if (opt1 != opt2) { 2664 if (opt1.has_value()) 2665 opt2.value(); // [[unsafe]] 2666 if (opt2.has_value()) 2667 opt1.value(); // [[unsafe]] 2668 } 2669 } 2670 )"); 2671 } 2672 2673 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftUnset) { 2674 ExpectDiagnosticsFor( 2675 R"( 2676 #include "unchecked_optional_access_test.h" 2677 2678 void target() { 2679 $ns::$optional<int> opt1 = $ns::nullopt; 2680 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2681 2682 if (opt1 != opt2) { 2683 opt2.value(); 2684 } else { 2685 opt2.value(); // [[unsafe]] 2686 } 2687 } 2688 )"); 2689 } 2690 2691 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightUnset) { 2692 ExpectDiagnosticsFor( 2693 R"( 2694 #include "unchecked_optional_access_test.h" 2695 2696 void target() { 2697 $ns::$optional<int> opt1 = $ns::nullopt; 2698 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2699 2700 if (opt2 != opt1) { 2701 opt2.value(); 2702 } else { 2703 opt2.value(); // [[unsafe]] 2704 } 2705 } 2706 )"); 2707 } 2708 2709 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightNullopt) { 2710 ExpectDiagnosticsFor( 2711 R"( 2712 #include "unchecked_optional_access_test.h" 2713 2714 void target() { 2715 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2716 2717 if (opt != $ns::nullopt) { 2718 opt.value(); 2719 } else { 2720 opt.value(); // [[unsafe]] 2721 } 2722 } 2723 )"); 2724 } 2725 2726 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftNullopt) { 2727 ExpectDiagnosticsFor( 2728 R"( 2729 #include "unchecked_optional_access_test.h" 2730 2731 void target() { 2732 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2733 2734 if ($ns::nullopt != opt) { 2735 opt.value(); 2736 } else { 2737 opt.value(); // [[unsafe]] 2738 } 2739 } 2740 )"); 2741 } 2742 2743 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightValue) { 2744 ExpectDiagnosticsFor( 2745 R"( 2746 #include "unchecked_optional_access_test.h" 2747 2748 void target() { 2749 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2750 2751 if (opt != 3) { 2752 opt.value(); // [[unsafe]] 2753 } else { 2754 opt.value(); 2755 } 2756 } 2757 )"); 2758 } 2759 2760 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftValue) { 2761 ExpectDiagnosticsFor( 2762 R"( 2763 #include "unchecked_optional_access_test.h" 2764 2765 void target() { 2766 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2767 2768 if (3 != opt) { 2769 opt.value(); // [[unsafe]] 2770 } else { 2771 opt.value(); 2772 } 2773 } 2774 )"); 2775 } 2776 2777 // Verifies that the model sees through aliases. 2778 TEST_P(UncheckedOptionalAccessTest, WithAlias) { 2779 ExpectDiagnosticsFor( 2780 R"( 2781 #include "unchecked_optional_access_test.h" 2782 2783 template <typename T> 2784 using MyOptional = $ns::$optional<T>; 2785 2786 void target(MyOptional<int> opt) { 2787 opt.value(); // [[unsafe]] 2788 } 2789 )"); 2790 } 2791 2792 TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) { 2793 // Basic test that nested values are populated. We nest an optional because 2794 // its easy to use in a test, but the type of the nested value shouldn't 2795 // matter. 2796 ExpectDiagnosticsFor( 2797 R"( 2798 #include "unchecked_optional_access_test.h" 2799 2800 using Foo = $ns::$optional<std::string>; 2801 2802 void target($ns::$optional<Foo> foo) { 2803 if (foo && *foo) { 2804 foo->value(); 2805 } 2806 } 2807 )"); 2808 2809 // Mutation is supported for nested values. 2810 ExpectDiagnosticsFor( 2811 R"( 2812 #include "unchecked_optional_access_test.h" 2813 2814 using Foo = $ns::$optional<std::string>; 2815 2816 void target($ns::$optional<Foo> foo) { 2817 if (foo && *foo) { 2818 foo->reset(); 2819 foo->value(); // [[unsafe]] 2820 } 2821 } 2822 )"); 2823 } 2824 2825 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignValue) { 2826 ExpectDiagnosticsFor( 2827 R"( 2828 #include "unchecked_optional_access_test.h" 2829 2830 using OptionalInt = $ns::$optional<int>; 2831 2832 void target($ns::$optional<OptionalInt> opt) { 2833 if (!opt) return; 2834 2835 // Accessing the outer optional is OK now. 2836 *opt; 2837 2838 // But accessing the nested optional is still unsafe because we haven't 2839 // checked it. 2840 **opt; // [[unsafe]] 2841 2842 *opt = 1; 2843 2844 // Accessing the nested optional is safe after assigning a value to it. 2845 **opt; 2846 } 2847 )"); 2848 } 2849 2850 TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignOptional) { 2851 ExpectDiagnosticsFor( 2852 R"( 2853 #include "unchecked_optional_access_test.h" 2854 2855 using OptionalInt = $ns::$optional<int>; 2856 2857 void target($ns::$optional<OptionalInt> opt) { 2858 if (!opt) return; 2859 2860 // Accessing the outer optional is OK now. 2861 *opt; 2862 2863 // But accessing the nested optional is still unsafe because we haven't 2864 // checked it. 2865 **opt; // [[unsafe]] 2866 2867 // Assign from `optional<short>` so that we trigger conversion assignment 2868 // instead of move assignment. 2869 *opt = $ns::$optional<short>(); 2870 2871 // Accessing the nested optional is still unsafe after assigning an empty 2872 // optional to it. 2873 **opt; // [[unsafe]] 2874 } 2875 )"); 2876 } 2877 2878 // Tests that structs can be nested. We use an optional field because its easy 2879 // to use in a test, but the type of the field shouldn't matter. 2880 TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) { 2881 ExpectDiagnosticsFor( 2882 R"( 2883 #include "unchecked_optional_access_test.h" 2884 2885 struct Foo { 2886 $ns::$optional<std::string> opt; 2887 }; 2888 2889 void target($ns::$optional<Foo> foo) { 2890 if (foo && foo->opt) { 2891 foo->opt.value(); 2892 } 2893 } 2894 )"); 2895 } 2896 2897 // FIXME: A case that we should handle but currently don't. 2898 // When there is a field of type reference to non-optional, we may 2899 // stop recursively creating storage locations. 2900 // E.g., the field `second` below in `pair` should eventually lead to 2901 // the optional `x` in `A`. 2902 TEST_P(UncheckedOptionalAccessTest, NestedOptionalThroughNonOptionalRefField) { 2903 ExpectDiagnosticsFor(R"( 2904 #include "unchecked_optional_access_test.h" 2905 2906 struct A { 2907 $ns::$optional<int> x; 2908 }; 2909 2910 struct pair { 2911 int first; 2912 const A &second; 2913 }; 2914 2915 struct B { 2916 $ns::$optional<pair>& nonConstGetRef(); 2917 }; 2918 2919 void target(B b) { 2920 const auto& maybe_pair = b.nonConstGetRef(); 2921 if (!maybe_pair.has_value()) 2922 return; 2923 2924 if(!maybe_pair->second.x.has_value()) 2925 return; 2926 maybe_pair->second.x.value(); // [[unsafe]] 2927 } 2928 )"); 2929 } 2930 2931 TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) { 2932 ExpectDiagnosticsFor( 2933 R"( 2934 #include "unchecked_optional_access_test.h" 2935 2936 using Foo = $ns::$optional<std::string>; 2937 2938 void target($ns::$optional<Foo> foo, bool b) { 2939 if (!foo.has_value()) return; 2940 if (b) { 2941 if (!foo->has_value()) return; 2942 // We have created `foo.value()`. 2943 foo->value(); 2944 } else { 2945 if (!foo->has_value()) return; 2946 // We have created `foo.value()` again, in a different environment. 2947 foo->value(); 2948 } 2949 // Now we merge the two values. UncheckedOptionalAccessModel::merge() will 2950 // throw away the "value" property. 2951 foo->value(); 2952 } 2953 )"); 2954 } 2955 2956 // This test is aimed at the core model, not the diagnostic. It is a regression 2957 // test against a crash when using non-trivial smart pointers, like 2958 // `std::unique_ptr`. As such, it doesn't test the access itself, which would be 2959 // ignored regardless because of `IgnoreSmartPointerDereference = true`, above. 2960 TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) { 2961 ExpectDiagnosticsFor( 2962 R"( 2963 #include "unchecked_optional_access_test.h" 2964 2965 template <typename T> 2966 struct smart_ptr { 2967 typename std::add_lvalue_reference<T>::type operator*() &; 2968 }; 2969 2970 void target() { 2971 smart_ptr<$ns::$optional<int>> x; 2972 // Verify that this assignment does not crash. 2973 *x = 3; 2974 } 2975 )"); 2976 } 2977 2978 TEST_P(UncheckedOptionalAccessTest, CorrelatedBranches) { 2979 ExpectDiagnosticsFor(R"code( 2980 #include "unchecked_optional_access_test.h" 2981 2982 void target(bool b, $ns::$optional<int> opt) { 2983 if (b || opt.has_value()) { 2984 if (!b) { 2985 opt.value(); 2986 } 2987 } 2988 } 2989 )code"); 2990 2991 ExpectDiagnosticsFor(R"code( 2992 #include "unchecked_optional_access_test.h" 2993 2994 void target(bool b, $ns::$optional<int> opt) { 2995 if (b && !opt.has_value()) return; 2996 if (b) { 2997 opt.value(); 2998 } 2999 } 3000 )code"); 3001 3002 ExpectDiagnosticsFor( 3003 R"code( 3004 #include "unchecked_optional_access_test.h" 3005 3006 void target(bool b, $ns::$optional<int> opt) { 3007 if (opt.has_value()) b = true; 3008 if (b) { 3009 opt.value(); // [[unsafe]] 3010 } 3011 } 3012 )code"); 3013 3014 ExpectDiagnosticsFor(R"code( 3015 #include "unchecked_optional_access_test.h" 3016 3017 void target(bool b, $ns::$optional<int> opt) { 3018 if (b) return; 3019 if (opt.has_value()) b = true; 3020 if (b) { 3021 opt.value(); 3022 } 3023 } 3024 )code"); 3025 3026 ExpectDiagnosticsFor(R"( 3027 #include "unchecked_optional_access_test.h" 3028 3029 void target(bool b, $ns::$optional<int> opt) { 3030 if (opt.has_value() == b) { 3031 if (b) { 3032 opt.value(); 3033 } 3034 } 3035 } 3036 )"); 3037 3038 ExpectDiagnosticsFor(R"( 3039 #include "unchecked_optional_access_test.h" 3040 3041 void target(bool b, $ns::$optional<int> opt) { 3042 if (opt.has_value() != b) { 3043 if (!b) { 3044 opt.value(); 3045 } 3046 } 3047 } 3048 )"); 3049 3050 ExpectDiagnosticsFor(R"( 3051 #include "unchecked_optional_access_test.h" 3052 3053 void target(bool b) { 3054 $ns::$optional<int> opt1 = $ns::nullopt; 3055 $ns::$optional<int> opt2; 3056 if (b) { 3057 opt2 = $ns::nullopt; 3058 } else { 3059 opt2 = $ns::nullopt; 3060 } 3061 if (opt2.has_value()) { 3062 opt1.value(); 3063 } 3064 } 3065 )"); 3066 } 3067 3068 TEST_P(UncheckedOptionalAccessTest, JoinDistinctValues) { 3069 ExpectDiagnosticsFor( 3070 R"code( 3071 #include "unchecked_optional_access_test.h" 3072 3073 void target(bool b) { 3074 $ns::$optional<int> opt; 3075 if (b) { 3076 opt = Make<$ns::$optional<int>>(); 3077 } else { 3078 opt = Make<$ns::$optional<int>>(); 3079 } 3080 if (opt.has_value()) { 3081 opt.value(); 3082 } else { 3083 opt.value(); // [[unsafe]] 3084 } 3085 } 3086 )code"); 3087 3088 ExpectDiagnosticsFor(R"code( 3089 #include "unchecked_optional_access_test.h" 3090 3091 void target(bool b) { 3092 $ns::$optional<int> opt; 3093 if (b) { 3094 opt = Make<$ns::$optional<int>>(); 3095 if (!opt.has_value()) return; 3096 } else { 3097 opt = Make<$ns::$optional<int>>(); 3098 if (!opt.has_value()) return; 3099 } 3100 opt.value(); 3101 } 3102 )code"); 3103 3104 ExpectDiagnosticsFor( 3105 R"code( 3106 #include "unchecked_optional_access_test.h" 3107 3108 void target(bool b) { 3109 $ns::$optional<int> opt; 3110 if (b) { 3111 opt = Make<$ns::$optional<int>>(); 3112 if (!opt.has_value()) return; 3113 } else { 3114 opt = Make<$ns::$optional<int>>(); 3115 } 3116 opt.value(); // [[unsafe]] 3117 } 3118 )code"); 3119 3120 ExpectDiagnosticsFor( 3121 R"code( 3122 #include "unchecked_optional_access_test.h" 3123 3124 void target(bool b) { 3125 $ns::$optional<int> opt; 3126 if (b) { 3127 opt = 1; 3128 } else { 3129 opt = 2; 3130 } 3131 opt.value(); 3132 } 3133 )code"); 3134 3135 ExpectDiagnosticsFor( 3136 R"code( 3137 #include "unchecked_optional_access_test.h" 3138 3139 void target(bool b) { 3140 $ns::$optional<int> opt; 3141 if (b) { 3142 opt = 1; 3143 } else { 3144 opt = Make<$ns::$optional<int>>(); 3145 } 3146 opt.value(); // [[unsafe]] 3147 } 3148 )code"); 3149 } 3150 3151 TEST_P(UncheckedOptionalAccessTest, AccessValueInLoop) { 3152 ExpectDiagnosticsFor(R"( 3153 #include "unchecked_optional_access_test.h" 3154 3155 void target() { 3156 $ns::$optional<int> opt = 3; 3157 while (Make<bool>()) { 3158 opt.value(); 3159 } 3160 } 3161 )"); 3162 } 3163 3164 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopWithCheckSafe) { 3165 ExpectDiagnosticsFor(R"( 3166 #include "unchecked_optional_access_test.h" 3167 3168 void target() { 3169 $ns::$optional<int> opt = 3; 3170 while (Make<bool>()) { 3171 opt.value(); 3172 3173 opt = Make<$ns::$optional<int>>(); 3174 if (!opt.has_value()) return; 3175 } 3176 } 3177 )"); 3178 } 3179 3180 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopNoCheckUnsafe) { 3181 ExpectDiagnosticsFor( 3182 R"( 3183 #include "unchecked_optional_access_test.h" 3184 3185 void target() { 3186 $ns::$optional<int> opt = 3; 3187 while (Make<bool>()) { 3188 opt.value(); // [[unsafe]] 3189 3190 opt = Make<$ns::$optional<int>>(); 3191 } 3192 } 3193 )"); 3194 } 3195 3196 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnsetUnsafe) { 3197 ExpectDiagnosticsFor( 3198 R"( 3199 #include "unchecked_optional_access_test.h" 3200 3201 void target() { 3202 $ns::$optional<int> opt = 3; 3203 while (Make<bool>()) 3204 opt = $ns::nullopt; 3205 $ns::$optional<int> opt2 = $ns::nullopt; 3206 if (opt.has_value()) 3207 opt2 = $ns::$optional<int>(3); 3208 opt2.value(); // [[unsafe]] 3209 } 3210 )"); 3211 } 3212 3213 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToSetUnsafe) { 3214 ExpectDiagnosticsFor( 3215 R"( 3216 #include "unchecked_optional_access_test.h" 3217 3218 void target() { 3219 $ns::$optional<int> opt = $ns::nullopt; 3220 while (Make<bool>()) 3221 opt = $ns::$optional<int>(3); 3222 $ns::$optional<int> opt2 = $ns::nullopt; 3223 if (!opt.has_value()) 3224 opt2 = $ns::$optional<int>(3); 3225 opt2.value(); // [[unsafe]] 3226 } 3227 )"); 3228 } 3229 3230 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnknownUnsafe) { 3231 ExpectDiagnosticsFor( 3232 R"( 3233 #include "unchecked_optional_access_test.h" 3234 3235 void target() { 3236 $ns::$optional<int> opt = $ns::nullopt; 3237 while (Make<bool>()) 3238 opt = Make<$ns::$optional<int>>(); 3239 $ns::$optional<int> opt2 = $ns::nullopt; 3240 if (!opt.has_value()) 3241 opt2 = $ns::$optional<int>(3); 3242 opt2.value(); // [[unsafe]] 3243 } 3244 )"); 3245 } 3246 3247 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopBadConditionUnsafe) { 3248 ExpectDiagnosticsFor( 3249 R"( 3250 #include "unchecked_optional_access_test.h" 3251 3252 void target() { 3253 $ns::$optional<int> opt = 3; 3254 while (Make<bool>()) { 3255 opt.value(); // [[unsafe]] 3256 3257 opt = Make<$ns::$optional<int>>(); 3258 if (!opt.has_value()) continue; 3259 } 3260 } 3261 )"); 3262 } 3263 3264 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromStruct) { 3265 ExpectDiagnosticsFor(R"( 3266 #include "unchecked_optional_access_test.h" 3267 3268 struct kv { $ns::$optional<int> opt; int x; }; 3269 int target() { 3270 auto [contents, x] = Make<kv>(); 3271 return contents ? *contents : x; 3272 } 3273 )"); 3274 3275 ExpectDiagnosticsFor(R"( 3276 #include "unchecked_optional_access_test.h" 3277 3278 template <typename T1, typename T2> 3279 struct pair { T1 fst; T2 snd; }; 3280 int target() { 3281 auto [contents, x] = Make<pair<$ns::$optional<int>, int>>(); 3282 return contents ? *contents : x; 3283 } 3284 )"); 3285 } 3286 3287 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromTupleLikeType) { 3288 ExpectDiagnosticsFor(R"( 3289 #include "unchecked_optional_access_test.h" 3290 3291 namespace std { 3292 template <class> struct tuple_size; 3293 template <size_t, class> struct tuple_element; 3294 template <class...> class tuple; 3295 3296 template <class... T> 3297 struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {}; 3298 3299 template <size_t I, class... T> 3300 struct tuple_element<I, tuple<T...>> { 3301 using type = __type_pack_element<I, T...>; 3302 }; 3303 3304 template <class...> class tuple {}; 3305 template <size_t I, class... T> 3306 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 3307 } // namespace std 3308 3309 std::tuple<$ns::$optional<const char *>, int> get_opt(); 3310 void target() { 3311 auto [content, ck] = get_opt(); 3312 content ? *content : ""; 3313 } 3314 )"); 3315 } 3316 3317 TEST_P(UncheckedOptionalAccessTest, CtorInitializerNullopt) { 3318 using namespace ast_matchers; 3319 ExpectDiagnosticsFor( 3320 R"( 3321 #include "unchecked_optional_access_test.h" 3322 3323 struct Target { 3324 Target(): opt($ns::nullopt) { 3325 opt.value(); // [[unsafe]] 3326 } 3327 $ns::$optional<int> opt; 3328 }; 3329 )", 3330 cxxConstructorDecl(ofClass(hasName("Target")))); 3331 } 3332 3333 TEST_P(UncheckedOptionalAccessTest, CtorInitializerValue) { 3334 using namespace ast_matchers; 3335 ExpectDiagnosticsFor( 3336 R"( 3337 #include "unchecked_optional_access_test.h" 3338 3339 struct Target { 3340 Target(): opt(3) { 3341 opt.value(); 3342 } 3343 $ns::$optional<int> opt; 3344 }; 3345 )", 3346 cxxConstructorDecl(ofClass(hasName("Target")))); 3347 } 3348 3349 // This is regression test, it shouldn't crash. 3350 TEST_P(UncheckedOptionalAccessTest, Bitfield) { 3351 using namespace ast_matchers; 3352 ExpectDiagnosticsFor( 3353 R"( 3354 #include "unchecked_optional_access_test.h" 3355 struct Dst { 3356 unsigned int n : 1; 3357 }; 3358 void target() { 3359 $ns::$optional<bool> v; 3360 Dst d; 3361 if (v.has_value()) 3362 d.n = v.value(); 3363 } 3364 )"); 3365 } 3366 3367 TEST_P(UncheckedOptionalAccessTest, LambdaParam) { 3368 ExpectDiagnosticsForLambda(R"( 3369 #include "unchecked_optional_access_test.h" 3370 3371 void target() { 3372 []($ns::$optional<int> opt) { 3373 if (opt.has_value()) { 3374 opt.value(); 3375 } else { 3376 opt.value(); // [[unsafe]] 3377 } 3378 }(Make<$ns::$optional<int>>()); 3379 } 3380 )"); 3381 } 3382 3383 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopy) { 3384 ExpectDiagnosticsForLambda(R"( 3385 #include "unchecked_optional_access_test.h" 3386 3387 void target($ns::$optional<int> opt) { 3388 [opt]() { 3389 if (opt.has_value()) { 3390 opt.value(); 3391 } else { 3392 opt.value(); // [[unsafe]] 3393 } 3394 }(); 3395 } 3396 )"); 3397 } 3398 3399 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReference) { 3400 ExpectDiagnosticsForLambda(R"( 3401 #include "unchecked_optional_access_test.h" 3402 3403 void target($ns::$optional<int> opt) { 3404 [&opt]() { 3405 if (opt.has_value()) { 3406 opt.value(); 3407 } else { 3408 opt.value(); // [[unsafe]] 3409 } 3410 }(); 3411 } 3412 )"); 3413 } 3414 3415 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureWithInitializer) { 3416 ExpectDiagnosticsForLambda(R"( 3417 #include "unchecked_optional_access_test.h" 3418 3419 void target($ns::$optional<int> opt) { 3420 [opt2=opt]() { 3421 if (opt2.has_value()) { 3422 opt2.value(); 3423 } else { 3424 opt2.value(); // [[unsafe]] 3425 } 3426 }(); 3427 } 3428 )"); 3429 } 3430 3431 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopyImplicit) { 3432 ExpectDiagnosticsForLambda(R"( 3433 #include "unchecked_optional_access_test.h" 3434 3435 void target($ns::$optional<int> opt) { 3436 [=]() { 3437 if (opt.has_value()) { 3438 opt.value(); 3439 } else { 3440 opt.value(); // [[unsafe]] 3441 } 3442 }(); 3443 } 3444 )"); 3445 } 3446 3447 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReferenceImplicit) { 3448 ExpectDiagnosticsForLambda(R"( 3449 #include "unchecked_optional_access_test.h" 3450 3451 void target($ns::$optional<int> opt) { 3452 [&]() { 3453 if (opt.has_value()) { 3454 opt.value(); 3455 } else { 3456 opt.value(); // [[unsafe]] 3457 } 3458 }(); 3459 } 3460 )"); 3461 } 3462 3463 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureThis) { 3464 ExpectDiagnosticsForLambda(R"( 3465 #include "unchecked_optional_access_test.h" 3466 3467 struct Foo { 3468 $ns::$optional<int> opt; 3469 3470 void target() { 3471 [this]() { 3472 if (opt.has_value()) { 3473 opt.value(); 3474 } else { 3475 opt.value(); // [[unsafe]] 3476 } 3477 }(); 3478 } 3479 }; 3480 )"); 3481 } 3482 3483 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureStateNotPropagated) { 3484 // We can't propagate information from the surrounding context. 3485 ExpectDiagnosticsForLambda(R"( 3486 #include "unchecked_optional_access_test.h" 3487 3488 void target($ns::$optional<int> opt) { 3489 if (opt.has_value()) { 3490 [&opt]() { 3491 opt.value(); // [[unsafe]] 3492 }(); 3493 } 3494 } 3495 )"); 3496 } 3497 3498 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptional) { 3499 ExpectDiagnosticsFor(R"( 3500 #include "unchecked_optional_access_test.h" 3501 3502 struct Derived : public $ns::$optional<int> {}; 3503 3504 void target(Derived opt) { 3505 *opt; // [[unsafe]] 3506 if (opt.has_value()) 3507 *opt; 3508 3509 // The same thing, but with a pointer receiver. 3510 Derived *popt = &opt; 3511 **popt; // [[unsafe]] 3512 if (popt->has_value()) 3513 **popt; 3514 } 3515 )"); 3516 } 3517 3518 TEST_P(UncheckedOptionalAccessTest, ClassTemplateDerivedFromOptional) { 3519 ExpectDiagnosticsFor(R"( 3520 #include "unchecked_optional_access_test.h" 3521 3522 template <class T> 3523 struct Derived : public $ns::$optional<T> {}; 3524 3525 void target(Derived<int> opt) { 3526 *opt; // [[unsafe]] 3527 if (opt.has_value()) 3528 *opt; 3529 3530 // The same thing, but with a pointer receiver. 3531 Derived<int> *popt = &opt; 3532 **popt; // [[unsafe]] 3533 if (popt->has_value()) 3534 **popt; 3535 } 3536 )"); 3537 } 3538 3539 TEST_P(UncheckedOptionalAccessTest, ClassDerivedPrivatelyFromOptional) { 3540 // Classes that derive privately from optional can themselves still call 3541 // member functions of optional. Check that we model the optional correctly 3542 // in this situation. 3543 ExpectDiagnosticsFor(R"( 3544 #include "unchecked_optional_access_test.h" 3545 3546 struct Derived : private $ns::$optional<int> { 3547 void Method() { 3548 **this; // [[unsafe]] 3549 if (this->has_value()) 3550 **this; 3551 } 3552 }; 3553 )", 3554 ast_matchers::hasName("Method")); 3555 } 3556 3557 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptionalValueConstructor) { 3558 ExpectDiagnosticsFor(R"( 3559 #include "unchecked_optional_access_test.h" 3560 3561 struct Derived : public $ns::$optional<int> { 3562 Derived(int); 3563 }; 3564 3565 void target(Derived opt) { 3566 *opt; // [[unsafe]] 3567 opt = 1; 3568 *opt; 3569 } 3570 )"); 3571 } 3572 3573 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessor) { 3574 ExpectDiagnosticsFor(R"cc( 3575 #include "unchecked_optional_access_test.h" 3576 3577 struct A { 3578 const $ns::$optional<int>& get() const { return x; } 3579 $ns::$optional<int> x; 3580 }; 3581 3582 void target(A& a) { 3583 if (a.get().has_value()) { 3584 a.get().value(); 3585 } 3586 } 3587 )cc"); 3588 } 3589 3590 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModInBetween) { 3591 ExpectDiagnosticsFor(R"cc( 3592 #include "unchecked_optional_access_test.h" 3593 3594 struct A { 3595 const $ns::$optional<int>& get() const { return x; } 3596 void clear(); 3597 $ns::$optional<int> x; 3598 }; 3599 3600 void target(A& a) { 3601 if (a.get().has_value()) { 3602 a.clear(); 3603 a.get().value(); // [[unsafe]] 3604 } 3605 } 3606 )cc"); 3607 } 3608 3609 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModReturningOptional) { 3610 ExpectDiagnosticsFor(R"cc( 3611 #include "unchecked_optional_access_test.h" 3612 3613 struct A { 3614 const $ns::$optional<int>& get() const { return x; } 3615 $ns::$optional<int> take(); 3616 $ns::$optional<int> x; 3617 }; 3618 3619 void target(A& a) { 3620 if (a.get().has_value()) { 3621 $ns::$optional<int> other = a.take(); 3622 a.get().value(); // [[unsafe]] 3623 if (other.has_value()) { 3624 other.value(); 3625 } 3626 } 3627 } 3628 )cc"); 3629 } 3630 3631 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorDifferentObjects) { 3632 ExpectDiagnosticsFor(R"cc( 3633 #include "unchecked_optional_access_test.h" 3634 3635 struct A { 3636 const $ns::$optional<int>& get() const { return x; } 3637 $ns::$optional<int> x; 3638 }; 3639 3640 void target(A& a1, A& a2) { 3641 if (a1.get().has_value()) { 3642 a2.get().value(); // [[unsafe]] 3643 } 3644 } 3645 )cc"); 3646 } 3647 3648 TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorLoop) { 3649 ExpectDiagnosticsFor(R"cc( 3650 #include "unchecked_optional_access_test.h" 3651 3652 struct A { 3653 const $ns::$optional<int>& get() const { return x; } 3654 $ns::$optional<int> x; 3655 }; 3656 3657 void target(A& a, int N) { 3658 for (int i = 0; i < N; ++i) { 3659 if (a.get().has_value()) { 3660 a.get().value(); 3661 } 3662 } 3663 } 3664 )cc"); 3665 } 3666 3667 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessor) { 3668 ExpectDiagnosticsFor(R"cc( 3669 #include "unchecked_optional_access_test.h" 3670 3671 struct A { 3672 $ns::$optional<int> get() const { return x; } 3673 $ns::$optional<int> x; 3674 }; 3675 3676 void target(A& a) { 3677 if (a.get().has_value()) { 3678 a.get().value(); 3679 } 3680 } 3681 )cc"); 3682 } 3683 3684 TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessorWithModInBetween) { 3685 ExpectDiagnosticsFor(R"cc( 3686 #include "unchecked_optional_access_test.h" 3687 3688 struct A { 3689 $ns::$optional<int> get() const { return x; } 3690 void clear(); 3691 $ns::$optional<int> x; 3692 }; 3693 3694 void target(A& a) { 3695 if (a.get().has_value()) { 3696 a.clear(); 3697 a.get().value(); // [[unsafe]] 3698 } 3699 } 3700 )cc"); 3701 } 3702 3703 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessor) { 3704 ExpectDiagnosticsFor(R"cc( 3705 #include "unchecked_optional_access_test.h" 3706 3707 struct A { 3708 bool isFoo() const { return f; } 3709 bool f; 3710 }; 3711 3712 void target(A& a) { 3713 std::optional<int> opt; 3714 if (a.isFoo()) { 3715 opt = 1; 3716 } 3717 if (a.isFoo()) { 3718 opt.value(); 3719 } 3720 } 3721 )cc"); 3722 } 3723 3724 TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessorWithModInBetween) { 3725 ExpectDiagnosticsFor(R"cc( 3726 #include "unchecked_optional_access_test.h" 3727 3728 struct A { 3729 bool isFoo() const { return f; } 3730 void clear(); 3731 bool f; 3732 }; 3733 3734 void target(A& a) { 3735 std::optional<int> opt; 3736 if (a.isFoo()) { 3737 opt = 1; 3738 } 3739 a.clear(); 3740 if (a.isFoo()) { 3741 opt.value(); // [[unsafe]] 3742 } 3743 } 3744 )cc"); 3745 } 3746 3747 // FIXME: Add support for: 3748 // - constructors (copy, move) 3749 // - assignment operators (default, copy, move) 3750 // - invalidation (passing optional by non-const reference/pointer) 3751