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 initializer_list() noexcept; 556 }; 557 558 } // namespace std 559 560 #endif // INITIALIZER_LIST_H 561 )"; 562 563 static constexpr char StdOptionalHeader[] = R"( 564 #include "std_initializer_list.h" 565 #include "std_type_traits.h" 566 #include "std_utility.h" 567 568 namespace std { 569 570 struct in_place_t {}; 571 constexpr in_place_t in_place; 572 573 struct nullopt_t { 574 constexpr explicit nullopt_t() {} 575 }; 576 constexpr nullopt_t nullopt; 577 578 template <class _Tp> 579 struct __optional_destruct_base { 580 constexpr void reset() noexcept; 581 }; 582 583 template <class _Tp> 584 struct __optional_storage_base : __optional_destruct_base<_Tp> { 585 constexpr bool has_value() const noexcept; 586 }; 587 588 template <typename _Tp> 589 class optional : private __optional_storage_base<_Tp> { 590 using __base = __optional_storage_base<_Tp>; 591 592 public: 593 using value_type = _Tp; 594 595 private: 596 struct _CheckOptionalArgsConstructor { 597 template <class _Up> 598 static constexpr bool __enable_implicit() { 599 return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>; 600 } 601 602 template <class _Up> 603 static constexpr bool __enable_explicit() { 604 return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>; 605 } 606 }; 607 template <class _Up> 608 using _CheckOptionalArgsCtor = 609 _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value && 610 _IsNotSame<__uncvref_t<_Up>, optional>::value, 611 _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>; 612 template <class _QualUp> 613 struct _CheckOptionalLikeConstructor { 614 template <class _Up, class _Opt = optional<_Up>> 615 using __check_constructible_from_opt = 616 _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>, 617 is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>, 618 is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>, 619 is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>; 620 template <class _Up, class _QUp = _QualUp> 621 static constexpr bool __enable_implicit() { 622 return is_convertible<_QUp, _Tp>::value && 623 !__check_constructible_from_opt<_Up>::value; 624 } 625 template <class _Up, class _QUp = _QualUp> 626 static constexpr bool __enable_explicit() { 627 return !is_convertible<_QUp, _Tp>::value && 628 !__check_constructible_from_opt<_Up>::value; 629 } 630 }; 631 632 template <class _Up, class _QualUp> 633 using _CheckOptionalLikeCtor = 634 _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value, 635 _CheckOptionalLikeConstructor<_QualUp>, 636 __check_tuple_constructor_fail>; 637 638 639 template <class _Up, class _QualUp> 640 using _CheckOptionalLikeAssign = _If< 641 _And< 642 _IsNotSame<_Up, _Tp>, 643 is_constructible<_Tp, _QualUp>, 644 is_assignable<_Tp&, _QualUp> 645 >::value, 646 _CheckOptionalLikeConstructor<_QualUp>, 647 __check_tuple_constructor_fail 648 >; 649 650 public: 651 constexpr optional() noexcept {} 652 constexpr optional(const optional&) = default; 653 constexpr optional(optional&&) = default; 654 constexpr optional(nullopt_t) noexcept {} 655 656 template < 657 class _InPlaceT, class... _Args, 658 class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>, 659 is_constructible<value_type, _Args...>>::value>> 660 constexpr explicit optional(_InPlaceT, _Args&&... __args); 661 662 template <class _Up, class... _Args, 663 class = enable_if_t<is_constructible_v< 664 value_type, initializer_list<_Up>&, _Args...>>> 665 constexpr explicit optional(in_place_t, initializer_list<_Up> __il, 666 _Args&&... __args); 667 668 template < 669 class _Up = value_type, 670 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), 671 int> = 0> 672 constexpr optional(_Up&& __v); 673 674 template < 675 class _Up, 676 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), 677 int> = 0> 678 constexpr explicit optional(_Up&& __v); 679 680 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>:: 681 template __enable_implicit<_Up>(), 682 int> = 0> 683 constexpr optional(const optional<_Up>& __v); 684 685 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>:: 686 template __enable_explicit<_Up>(), 687 int> = 0> 688 constexpr explicit optional(const optional<_Up>& __v); 689 690 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>:: 691 template __enable_implicit<_Up>(), 692 int> = 0> 693 constexpr optional(optional<_Up>&& __v); 694 695 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>:: 696 template __enable_explicit<_Up>(), 697 int> = 0> 698 constexpr explicit optional(optional<_Up>&& __v); 699 700 constexpr optional& operator=(nullopt_t) noexcept; 701 702 optional& operator=(const optional&); 703 704 optional& operator=(optional&&); 705 706 template <class _Up = value_type, 707 class = enable_if_t<_And<_IsNotSame<__uncvref_t<_Up>, optional>, 708 _Or<_IsNotSame<__uncvref_t<_Up>, value_type>, 709 _Not<is_scalar<value_type>>>, 710 is_constructible<value_type, _Up>, 711 is_assignable<value_type&, _Up>>::value>> 712 constexpr optional& operator=(_Up&& __v); 713 714 template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>:: 715 template __enable_assign<_Up>(), 716 int> = 0> 717 constexpr optional& operator=(const optional<_Up>& __v); 718 719 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>:: 720 template __enable_assign<_Up>(), 721 int> = 0> 722 constexpr optional& operator=(optional<_Up>&& __v); 723 724 const _Tp& operator*() const&; 725 _Tp& operator*() &; 726 const _Tp&& operator*() const&&; 727 _Tp&& operator*() &&; 728 729 const _Tp* operator->() const; 730 _Tp* operator->(); 731 732 const _Tp& value() const&; 733 _Tp& value() &; 734 const _Tp&& value() const&&; 735 _Tp&& value() &&; 736 737 template <typename U> 738 constexpr _Tp value_or(U&& v) const&; 739 template <typename U> 740 _Tp value_or(U&& v) &&; 741 742 template <typename... Args> 743 _Tp& emplace(Args&&... args); 744 745 template <typename U, typename... Args> 746 _Tp& emplace(std::initializer_list<U> ilist, Args&&... args); 747 748 using __base::reset; 749 750 constexpr explicit operator bool() const noexcept; 751 using __base::has_value; 752 753 constexpr void swap(optional& __opt) noexcept; 754 }; 755 756 template <typename T> 757 constexpr optional<typename std::decay<T>::type> make_optional(T&& v); 758 759 template <typename T, typename... Args> 760 constexpr optional<T> make_optional(Args&&... args); 761 762 template <typename T, typename U, typename... Args> 763 constexpr optional<T> make_optional(std::initializer_list<U> il, 764 Args&&... args); 765 766 template <typename T, typename U> 767 constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs); 768 template <typename T, typename U> 769 constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs); 770 771 template <typename T> 772 constexpr bool operator==(const optional<T> &opt, nullopt_t); 773 774 // C++20 and later do not define the following overloads because they are 775 // provided by rewritten candidates instead. 776 #if __cplusplus < 202002L 777 template <typename T> 778 constexpr bool operator==(nullopt_t, const optional<T> &opt); 779 template <typename T> 780 constexpr bool operator!=(const optional<T> &opt, nullopt_t); 781 template <typename T> 782 constexpr bool operator!=(nullopt_t, const optional<T> &opt); 783 #endif // __cplusplus < 202002L 784 785 template <typename T, typename U> 786 constexpr bool operator==(const optional<T> &opt, const U &value); 787 template <typename T, typename U> 788 constexpr bool operator==(const T &value, const optional<U> &opt); 789 template <typename T, typename U> 790 constexpr bool operator!=(const optional<T> &opt, const U &value); 791 template <typename T, typename U> 792 constexpr bool operator!=(const T &value, const optional<U> &opt); 793 794 } // namespace std 795 )"; 796 797 static constexpr char AbslOptionalHeader[] = R"( 798 #include "absl_type_traits.h" 799 #include "std_initializer_list.h" 800 #include "std_type_traits.h" 801 #include "std_utility.h" 802 803 namespace absl { 804 805 struct nullopt_t { 806 constexpr explicit nullopt_t() {} 807 }; 808 constexpr nullopt_t nullopt; 809 810 struct in_place_t {}; 811 constexpr in_place_t in_place; 812 813 template <typename T> 814 class optional; 815 816 namespace optional_internal { 817 818 template <typename T, typename U> 819 struct is_constructible_convertible_from_optional 820 : std::integral_constant< 821 bool, std::is_constructible<T, optional<U>&>::value || 822 std::is_constructible<T, optional<U>&&>::value || 823 std::is_constructible<T, const optional<U>&>::value || 824 std::is_constructible<T, const optional<U>&&>::value || 825 std::is_convertible<optional<U>&, T>::value || 826 std::is_convertible<optional<U>&&, T>::value || 827 std::is_convertible<const optional<U>&, T>::value || 828 std::is_convertible<const optional<U>&&, T>::value> {}; 829 830 template <typename T, typename U> 831 struct is_constructible_convertible_assignable_from_optional 832 : std::integral_constant< 833 bool, is_constructible_convertible_from_optional<T, U>::value || 834 std::is_assignable<T&, optional<U>&>::value || 835 std::is_assignable<T&, optional<U>&&>::value || 836 std::is_assignable<T&, const optional<U>&>::value || 837 std::is_assignable<T&, const optional<U>&&>::value> {}; 838 839 } // namespace optional_internal 840 841 template <typename T> 842 class optional { 843 public: 844 constexpr optional() noexcept; 845 846 constexpr optional(nullopt_t) noexcept; 847 848 optional(const optional&) = default; 849 850 optional(optional&&) = default; 851 852 template <typename InPlaceT, typename... Args, 853 absl::enable_if_t<absl::conjunction< 854 std::is_same<InPlaceT, in_place_t>, 855 std::is_constructible<T, Args&&...>>::value>* = nullptr> 856 constexpr explicit optional(InPlaceT, Args&&... args); 857 858 template <typename U, typename... Args, 859 typename = typename std::enable_if<std::is_constructible< 860 T, std::initializer_list<U>&, Args&&...>::value>::type> 861 constexpr explicit optional(in_place_t, std::initializer_list<U> il, 862 Args&&... args); 863 864 template < 865 typename U = T, 866 typename std::enable_if< 867 absl::conjunction<absl::negation<std::is_same< 868 in_place_t, typename std::decay<U>::type>>, 869 absl::negation<std::is_same< 870 optional<T>, typename std::decay<U>::type>>, 871 std::is_convertible<U&&, T>, 872 std::is_constructible<T, U&&>>::value, 873 bool>::type = false> 874 constexpr optional(U&& v); 875 876 template < 877 typename U = T, 878 typename std::enable_if< 879 absl::conjunction<absl::negation<std::is_same< 880 in_place_t, typename std::decay<U>::type>>, 881 absl::negation<std::is_same< 882 optional<T>, typename std::decay<U>::type>>, 883 absl::negation<std::is_convertible<U&&, T>>, 884 std::is_constructible<T, U&&>>::value, 885 bool>::type = false> 886 explicit constexpr optional(U&& v); 887 888 template <typename U, 889 typename std::enable_if< 890 absl::conjunction< 891 absl::negation<std::is_same<T, U>>, 892 std::is_constructible<T, const U&>, 893 absl::negation< 894 optional_internal:: 895 is_constructible_convertible_from_optional<T, U>>, 896 std::is_convertible<const U&, T>>::value, 897 bool>::type = false> 898 optional(const optional<U>& rhs); 899 900 template <typename U, 901 typename std::enable_if< 902 absl::conjunction< 903 absl::negation<std::is_same<T, U>>, 904 std::is_constructible<T, const U&>, 905 absl::negation< 906 optional_internal:: 907 is_constructible_convertible_from_optional<T, U>>, 908 absl::negation<std::is_convertible<const U&, T>>>::value, 909 bool>::type = false> 910 explicit optional(const optional<U>& rhs); 911 912 template < 913 typename U, 914 typename std::enable_if< 915 absl::conjunction< 916 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, 917 absl::negation< 918 optional_internal::is_constructible_convertible_from_optional< 919 T, U>>, 920 std::is_convertible<U&&, T>>::value, 921 bool>::type = false> 922 optional(optional<U>&& rhs); 923 924 template < 925 typename U, 926 typename std::enable_if< 927 absl::conjunction< 928 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, 929 absl::negation< 930 optional_internal::is_constructible_convertible_from_optional< 931 T, U>>, 932 absl::negation<std::is_convertible<U&&, T>>>::value, 933 bool>::type = false> 934 explicit optional(optional<U>&& rhs); 935 936 optional& operator=(nullopt_t) noexcept; 937 938 optional& operator=(const optional& src); 939 940 optional& operator=(optional&& src); 941 942 template < 943 typename U = T, 944 typename = typename std::enable_if<absl::conjunction< 945 absl::negation< 946 std::is_same<optional<T>, typename std::decay<U>::type>>, 947 absl::negation< 948 absl::conjunction<std::is_scalar<T>, 949 std::is_same<T, typename std::decay<U>::type>>>, 950 std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type> 951 optional& operator=(U&& v); 952 953 template < 954 typename U, 955 typename = typename std::enable_if<absl::conjunction< 956 absl::negation<std::is_same<T, U>>, 957 std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>, 958 absl::negation< 959 optional_internal:: 960 is_constructible_convertible_assignable_from_optional< 961 T, U>>>::value>::type> 962 optional& operator=(const optional<U>& rhs); 963 964 template <typename U, 965 typename = typename std::enable_if<absl::conjunction< 966 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>, 967 std::is_assignable<T&, U>, 968 absl::negation< 969 optional_internal:: 970 is_constructible_convertible_assignable_from_optional< 971 T, U>>>::value>::type> 972 optional& operator=(optional<U>&& rhs); 973 974 const T& operator*() const&; 975 T& operator*() &; 976 const T&& operator*() const&&; 977 T&& operator*() &&; 978 979 const T* operator->() const; 980 T* operator->(); 981 982 const T& value() const&; 983 T& value() &; 984 const T&& value() const&&; 985 T&& value() &&; 986 987 template <typename U> 988 constexpr T value_or(U&& v) const&; 989 template <typename U> 990 T value_or(U&& v) &&; 991 992 template <typename... Args> 993 T& emplace(Args&&... args); 994 995 template <typename U, typename... Args> 996 T& emplace(std::initializer_list<U> ilist, Args&&... args); 997 998 void reset() noexcept; 999 1000 constexpr explicit operator bool() const noexcept; 1001 constexpr bool has_value() const noexcept; 1002 1003 void swap(optional& rhs) noexcept; 1004 }; 1005 1006 template <typename T> 1007 constexpr optional<typename std::decay<T>::type> make_optional(T&& v); 1008 1009 template <typename T, typename... Args> 1010 constexpr optional<T> make_optional(Args&&... args); 1011 1012 template <typename T, typename U, typename... Args> 1013 constexpr optional<T> make_optional(std::initializer_list<U> il, 1014 Args&&... args); 1015 1016 template <typename T, typename U> 1017 constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs); 1018 template <typename T, typename U> 1019 constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs); 1020 1021 template <typename T> 1022 constexpr bool operator==(const optional<T> &opt, nullopt_t); 1023 template <typename T> 1024 constexpr bool operator==(nullopt_t, const optional<T> &opt); 1025 template <typename T> 1026 constexpr bool operator!=(const optional<T> &opt, nullopt_t); 1027 template <typename T> 1028 constexpr bool operator!=(nullopt_t, const optional<T> &opt); 1029 1030 template <typename T, typename U> 1031 constexpr bool operator==(const optional<T> &opt, const U &value); 1032 template <typename T, typename U> 1033 constexpr bool operator==(const T &value, const optional<U> &opt); 1034 template <typename T, typename U> 1035 constexpr bool operator!=(const optional<T> &opt, const U &value); 1036 template <typename T, typename U> 1037 constexpr bool operator!=(const T &value, const optional<U> &opt); 1038 1039 } // namespace absl 1040 )"; 1041 1042 static constexpr char BaseOptionalHeader[] = R"( 1043 #include "std_initializer_list.h" 1044 #include "std_type_traits.h" 1045 #include "std_utility.h" 1046 1047 namespace base { 1048 1049 struct in_place_t {}; 1050 constexpr in_place_t in_place; 1051 1052 struct nullopt_t { 1053 constexpr explicit nullopt_t() {} 1054 }; 1055 constexpr nullopt_t nullopt; 1056 1057 template <typename T> 1058 class Optional; 1059 1060 namespace internal { 1061 1062 template <typename T> 1063 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>; 1064 1065 template <typename T, typename U> 1066 struct IsConvertibleFromOptional 1067 : std::integral_constant< 1068 bool, std::is_constructible<T, Optional<U>&>::value || 1069 std::is_constructible<T, const Optional<U>&>::value || 1070 std::is_constructible<T, Optional<U>&&>::value || 1071 std::is_constructible<T, const Optional<U>&&>::value || 1072 std::is_convertible<Optional<U>&, T>::value || 1073 std::is_convertible<const Optional<U>&, T>::value || 1074 std::is_convertible<Optional<U>&&, T>::value || 1075 std::is_convertible<const Optional<U>&&, T>::value> {}; 1076 1077 template <typename T, typename U> 1078 struct IsAssignableFromOptional 1079 : std::integral_constant< 1080 bool, IsConvertibleFromOptional<T, U>::value || 1081 std::is_assignable<T&, Optional<U>&>::value || 1082 std::is_assignable<T&, const Optional<U>&>::value || 1083 std::is_assignable<T&, Optional<U>&&>::value || 1084 std::is_assignable<T&, const Optional<U>&&>::value> {}; 1085 1086 } // namespace internal 1087 1088 template <typename T> 1089 class Optional { 1090 public: 1091 using value_type = T; 1092 1093 constexpr Optional() = default; 1094 constexpr Optional(const Optional& other) noexcept = default; 1095 constexpr Optional(Optional&& other) noexcept = default; 1096 1097 constexpr Optional(nullopt_t); 1098 1099 template <typename U, 1100 typename std::enable_if< 1101 std::is_constructible<T, const U&>::value && 1102 !internal::IsConvertibleFromOptional<T, U>::value && 1103 std::is_convertible<const U&, T>::value, 1104 bool>::type = false> 1105 Optional(const Optional<U>& other) noexcept; 1106 1107 template <typename U, 1108 typename std::enable_if< 1109 std::is_constructible<T, const U&>::value && 1110 !internal::IsConvertibleFromOptional<T, U>::value && 1111 !std::is_convertible<const U&, T>::value, 1112 bool>::type = false> 1113 explicit Optional(const Optional<U>& other) noexcept; 1114 1115 template <typename U, 1116 typename std::enable_if< 1117 std::is_constructible<T, U&&>::value && 1118 !internal::IsConvertibleFromOptional<T, U>::value && 1119 std::is_convertible<U&&, T>::value, 1120 bool>::type = false> 1121 Optional(Optional<U>&& other) noexcept; 1122 1123 template <typename U, 1124 typename std::enable_if< 1125 std::is_constructible<T, U&&>::value && 1126 !internal::IsConvertibleFromOptional<T, U>::value && 1127 !std::is_convertible<U&&, T>::value, 1128 bool>::type = false> 1129 explicit Optional(Optional<U>&& other) noexcept; 1130 1131 template <class... Args> 1132 constexpr explicit Optional(in_place_t, Args&&... args); 1133 1134 template <class U, class... Args, 1135 class = typename std::enable_if<std::is_constructible< 1136 value_type, std::initializer_list<U>&, Args...>::value>::type> 1137 constexpr explicit Optional(in_place_t, std::initializer_list<U> il, 1138 Args&&... args); 1139 1140 template < 1141 typename U = value_type, 1142 typename std::enable_if< 1143 std::is_constructible<T, U&&>::value && 1144 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value && 1145 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value && 1146 std::is_convertible<U&&, T>::value, 1147 bool>::type = false> 1148 constexpr Optional(U&& value); 1149 1150 template < 1151 typename U = value_type, 1152 typename std::enable_if< 1153 std::is_constructible<T, U&&>::value && 1154 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value && 1155 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value && 1156 !std::is_convertible<U&&, T>::value, 1157 bool>::type = false> 1158 constexpr explicit Optional(U&& value); 1159 1160 Optional& operator=(const Optional& other) noexcept; 1161 1162 Optional& operator=(Optional&& other) noexcept; 1163 1164 Optional& operator=(nullopt_t); 1165 1166 template <typename U> 1167 typename std::enable_if< 1168 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value && 1169 std::is_constructible<T, U>::value && 1170 std::is_assignable<T&, U>::value && 1171 (!std::is_scalar<T>::value || 1172 !std::is_same<typename std::decay<U>::type, T>::value), 1173 Optional&>::type 1174 operator=(U&& value) noexcept; 1175 1176 template <typename U> 1177 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value && 1178 std::is_constructible<T, const U&>::value && 1179 std::is_assignable<T&, const U&>::value, 1180 Optional&>::type 1181 operator=(const Optional<U>& other) noexcept; 1182 1183 template <typename U> 1184 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value && 1185 std::is_constructible<T, U>::value && 1186 std::is_assignable<T&, U>::value, 1187 Optional&>::type 1188 operator=(Optional<U>&& other) noexcept; 1189 1190 const T& operator*() const&; 1191 T& operator*() &; 1192 const T&& operator*() const&&; 1193 T&& operator*() &&; 1194 1195 const T* operator->() const; 1196 T* operator->(); 1197 1198 const T& value() const&; 1199 T& value() &; 1200 const T&& value() const&&; 1201 T&& value() &&; 1202 1203 template <typename U> 1204 constexpr T value_or(U&& v) const&; 1205 template <typename U> 1206 T value_or(U&& v) &&; 1207 1208 template <typename... Args> 1209 T& emplace(Args&&... args); 1210 1211 template <typename U, typename... Args> 1212 T& emplace(std::initializer_list<U> ilist, Args&&... args); 1213 1214 void reset() noexcept; 1215 1216 constexpr explicit operator bool() const noexcept; 1217 constexpr bool has_value() const noexcept; 1218 1219 void swap(Optional& other); 1220 }; 1221 1222 template <typename T> 1223 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v); 1224 1225 template <typename T, typename... Args> 1226 constexpr Optional<T> make_optional(Args&&... args); 1227 1228 template <typename T, typename U, typename... Args> 1229 constexpr Optional<T> make_optional(std::initializer_list<U> il, 1230 Args&&... args); 1231 1232 template <typename T, typename U> 1233 constexpr bool operator==(const Optional<T> &lhs, const Optional<U> &rhs); 1234 template <typename T, typename U> 1235 constexpr bool operator!=(const Optional<T> &lhs, const Optional<U> &rhs); 1236 1237 template <typename T> 1238 constexpr bool operator==(const Optional<T> &opt, nullopt_t); 1239 template <typename T> 1240 constexpr bool operator==(nullopt_t, const Optional<T> &opt); 1241 template <typename T> 1242 constexpr bool operator!=(const Optional<T> &opt, nullopt_t); 1243 template <typename T> 1244 constexpr bool operator!=(nullopt_t, const Optional<T> &opt); 1245 1246 template <typename T, typename U> 1247 constexpr bool operator==(const Optional<T> &opt, const U &value); 1248 template <typename T, typename U> 1249 constexpr bool operator==(const T &value, const Optional<U> &opt); 1250 template <typename T, typename U> 1251 constexpr bool operator!=(const Optional<T> &opt, const U &value); 1252 template <typename T, typename U> 1253 constexpr bool operator!=(const T &value, const Optional<U> &opt); 1254 1255 } // namespace base 1256 )"; 1257 1258 /// Replaces all occurrences of `Pattern` in `S` with `Replacement`. 1259 static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern, 1260 const std::string &Replacement) { 1261 size_t Pos = 0; 1262 while (true) { 1263 Pos = S.find(Pattern, Pos); 1264 if (Pos == std::string::npos) 1265 break; 1266 S.replace(Pos, Pattern.size(), Replacement); 1267 } 1268 } 1269 1270 struct OptionalTypeIdentifier { 1271 std::string NamespaceName; 1272 std::string TypeName; 1273 }; 1274 1275 static raw_ostream &operator<<(raw_ostream &OS, 1276 const OptionalTypeIdentifier &TypeId) { 1277 OS << TypeId.NamespaceName << "::" << TypeId.TypeName; 1278 return OS; 1279 } 1280 1281 class UncheckedOptionalAccessTest 1282 : public ::testing::TestWithParam<OptionalTypeIdentifier> { 1283 protected: 1284 void ExpectDiagnosticsFor(std::string SourceCode) { 1285 ExpectDiagnosticsFor(SourceCode, ast_matchers::hasName("target")); 1286 } 1287 1288 void ExpectDiagnosticsForLambda(std::string SourceCode) { 1289 ExpectDiagnosticsFor( 1290 SourceCode, ast_matchers::hasDeclContext( 1291 ast_matchers::cxxRecordDecl(ast_matchers::isLambda()))); 1292 } 1293 1294 template <typename FuncDeclMatcher> 1295 void ExpectDiagnosticsFor(std::string SourceCode, 1296 FuncDeclMatcher FuncMatcher) { 1297 // Run in C++17 and C++20 mode to cover differences in the AST between modes 1298 // (e.g. C++20 can contain `CXXRewrittenBinaryOperator`). 1299 for (const char *CxxMode : {"-std=c++17", "-std=c++20"}) 1300 ExpectDiagnosticsFor(SourceCode, FuncMatcher, CxxMode); 1301 } 1302 1303 template <typename FuncDeclMatcher> 1304 void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher, 1305 const char *CxxMode) { 1306 ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName); 1307 ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName); 1308 1309 std::vector<std::pair<std::string, std::string>> Headers; 1310 Headers.emplace_back("cstddef.h", CSDtdDefHeader); 1311 Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader); 1312 Headers.emplace_back("std_string.h", StdStringHeader); 1313 Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader); 1314 Headers.emplace_back("std_utility.h", StdUtilityHeader); 1315 Headers.emplace_back("std_optional.h", StdOptionalHeader); 1316 Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader); 1317 Headers.emplace_back("absl_optional.h", AbslOptionalHeader); 1318 Headers.emplace_back("base_optional.h", BaseOptionalHeader); 1319 Headers.emplace_back("unchecked_optional_access_test.h", R"( 1320 #include "absl_optional.h" 1321 #include "base_optional.h" 1322 #include "std_initializer_list.h" 1323 #include "std_optional.h" 1324 #include "std_string.h" 1325 #include "std_utility.h" 1326 1327 template <typename T> 1328 T Make(); 1329 )"); 1330 UncheckedOptionalAccessModelOptions Options{ 1331 /*IgnoreSmartPointerDereference=*/true}; 1332 std::vector<SourceLocation> Diagnostics; 1333 llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>( 1334 AnalysisInputs<UncheckedOptionalAccessModel>( 1335 SourceCode, std::move(FuncMatcher), 1336 [](ASTContext &Ctx, Environment &Env) { 1337 return UncheckedOptionalAccessModel(Ctx, Env); 1338 }) 1339 .withPostVisitCFG( 1340 [&Diagnostics, 1341 Diagnoser = UncheckedOptionalAccessDiagnoser(Options)]( 1342 ASTContext &Ctx, const CFGElement &Elt, 1343 const TransferStateForDiagnostics<NoopLattice> 1344 &State) mutable { 1345 auto EltDiagnostics = Diagnoser(Elt, Ctx, State); 1346 llvm::move(EltDiagnostics, std::back_inserter(Diagnostics)); 1347 }) 1348 .withASTBuildArgs( 1349 {"-fsyntax-only", CxxMode, "-Wno-undefined-inline"}) 1350 .withASTBuildVirtualMappedFiles( 1351 tooling::FileContentMappings(Headers.begin(), Headers.end())), 1352 /*VerifyResults=*/[&Diagnostics]( 1353 const llvm::DenseMap<unsigned, std::string> 1354 &Annotations, 1355 const AnalysisOutputs &AO) { 1356 llvm::DenseSet<unsigned> AnnotationLines; 1357 for (const auto &[Line, _] : Annotations) { 1358 AnnotationLines.insert(Line); 1359 } 1360 auto &SrcMgr = AO.ASTCtx.getSourceManager(); 1361 llvm::DenseSet<unsigned> DiagnosticLines; 1362 for (SourceLocation &Loc : Diagnostics) { 1363 unsigned Line = SrcMgr.getPresumedLineNumber(Loc); 1364 DiagnosticLines.insert(Line); 1365 if (!AnnotationLines.contains(Line)) { 1366 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts( 1367 new DiagnosticOptions()); 1368 TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(), 1369 DiagOpts.get()); 1370 TD.emitDiagnostic( 1371 FullSourceLoc(Loc, SrcMgr), DiagnosticsEngine::Error, 1372 "unexpected diagnostic", std::nullopt, std::nullopt); 1373 } 1374 } 1375 1376 EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines)); 1377 }); 1378 if (Error) 1379 FAIL() << llvm::toString(std::move(Error)); 1380 } 1381 }; 1382 1383 INSTANTIATE_TEST_SUITE_P( 1384 UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest, 1385 ::testing::Values(OptionalTypeIdentifier{"std", "optional"}, 1386 OptionalTypeIdentifier{"absl", "optional"}, 1387 OptionalTypeIdentifier{"base", "Optional"}), 1388 [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) { 1389 return Info.param.NamespaceName; 1390 }); 1391 1392 // Verifies that similarly-named types are ignored. 1393 TEST_P(UncheckedOptionalAccessTest, NonTrackedOptionalType) { 1394 ExpectDiagnosticsFor( 1395 R"( 1396 namespace other { 1397 namespace $ns { 1398 template <typename T> 1399 struct $optional { 1400 T value(); 1401 }; 1402 } 1403 1404 void target($ns::$optional<int> opt) { 1405 opt.value(); 1406 } 1407 } 1408 )"); 1409 } 1410 1411 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) { 1412 ExpectDiagnosticsFor(R"( 1413 void target() { 1414 (void)0; 1415 } 1416 )"); 1417 } 1418 1419 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) { 1420 ExpectDiagnosticsFor( 1421 R"( 1422 #include "unchecked_optional_access_test.h" 1423 1424 void target($ns::$optional<int> opt) { 1425 opt.value(); // [[unsafe]] 1426 } 1427 )"); 1428 1429 ExpectDiagnosticsFor( 1430 R"( 1431 #include "unchecked_optional_access_test.h" 1432 1433 void target($ns::$optional<int> opt) { 1434 std::move(opt).value(); // [[unsafe]] 1435 } 1436 )"); 1437 } 1438 1439 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) { 1440 ExpectDiagnosticsFor( 1441 R"( 1442 #include "unchecked_optional_access_test.h" 1443 1444 void target($ns::$optional<int> opt) { 1445 *opt; // [[unsafe]] 1446 } 1447 )"); 1448 1449 ExpectDiagnosticsFor( 1450 R"( 1451 #include "unchecked_optional_access_test.h" 1452 1453 void target($ns::$optional<int> opt) { 1454 *std::move(opt); // [[unsafe]] 1455 } 1456 )"); 1457 } 1458 1459 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) { 1460 ExpectDiagnosticsFor( 1461 R"( 1462 #include "unchecked_optional_access_test.h" 1463 1464 struct Foo { 1465 void foo(); 1466 }; 1467 1468 void target($ns::$optional<Foo> opt) { 1469 opt->foo(); // [[unsafe]] 1470 } 1471 )"); 1472 1473 ExpectDiagnosticsFor( 1474 R"( 1475 #include "unchecked_optional_access_test.h" 1476 1477 struct Foo { 1478 void foo(); 1479 }; 1480 1481 void target($ns::$optional<Foo> opt) { 1482 std::move(opt)->foo(); // [[unsafe]] 1483 } 1484 )"); 1485 } 1486 1487 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) { 1488 ExpectDiagnosticsFor(R"( 1489 #include "unchecked_optional_access_test.h" 1490 1491 void target($ns::$optional<int> opt) { 1492 if (opt.has_value()) { 1493 opt.value(); 1494 } 1495 } 1496 )"); 1497 } 1498 1499 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) { 1500 ExpectDiagnosticsFor(R"( 1501 #include "unchecked_optional_access_test.h" 1502 1503 void target($ns::$optional<int> opt) { 1504 if (opt) { 1505 opt.value(); 1506 } 1507 } 1508 )"); 1509 } 1510 1511 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) { 1512 ExpectDiagnosticsFor( 1513 R"( 1514 #include "unchecked_optional_access_test.h" 1515 1516 void target() { 1517 Make<$ns::$optional<int>>().value(); // [[unsafe]] 1518 (void)0; 1519 } 1520 )"); 1521 1522 ExpectDiagnosticsFor( 1523 R"( 1524 #include "unchecked_optional_access_test.h" 1525 1526 void target($ns::$optional<int> opt) { 1527 std::move(opt).value(); // [[unsafe]] 1528 } 1529 )"); 1530 } 1531 1532 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) { 1533 ExpectDiagnosticsFor( 1534 R"( 1535 #include "unchecked_optional_access_test.h" 1536 1537 void target() { 1538 $ns::$optional<int> opt; 1539 opt.value(); // [[unsafe]] 1540 } 1541 )"); 1542 } 1543 1544 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) { 1545 ExpectDiagnosticsFor( 1546 R"( 1547 #include "unchecked_optional_access_test.h" 1548 1549 void target() { 1550 $ns::$optional<int> opt($ns::nullopt); 1551 opt.value(); // [[unsafe]] 1552 } 1553 )"); 1554 } 1555 1556 TEST_P(UncheckedOptionalAccessTest, NulloptConstructorWithSugaredType) { 1557 ExpectDiagnosticsFor( 1558 R"( 1559 #include "unchecked_optional_access_test.h" 1560 template <typename T> 1561 using wrapper = T; 1562 1563 template <typename T> 1564 wrapper<T> wrap(T); 1565 1566 void target() { 1567 $ns::$optional<int> opt(wrap($ns::nullopt)); 1568 opt.value(); // [[unsafe]] 1569 } 1570 )"); 1571 } 1572 1573 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) { 1574 ExpectDiagnosticsFor(R"( 1575 #include "unchecked_optional_access_test.h" 1576 1577 void target() { 1578 $ns::$optional<int> opt($ns::in_place, 3); 1579 opt.value(); 1580 } 1581 )"); 1582 1583 ExpectDiagnosticsFor(R"( 1584 #include "unchecked_optional_access_test.h" 1585 1586 struct Foo {}; 1587 1588 void target() { 1589 $ns::$optional<Foo> opt($ns::in_place); 1590 opt.value(); 1591 } 1592 )"); 1593 1594 ExpectDiagnosticsFor(R"( 1595 #include "unchecked_optional_access_test.h" 1596 1597 struct Foo { 1598 explicit Foo(int, bool); 1599 }; 1600 1601 void target() { 1602 $ns::$optional<Foo> opt($ns::in_place, 3, false); 1603 opt.value(); 1604 } 1605 )"); 1606 1607 ExpectDiagnosticsFor(R"( 1608 #include "unchecked_optional_access_test.h" 1609 1610 struct Foo { 1611 explicit Foo(std::initializer_list<int>); 1612 }; 1613 1614 void target() { 1615 $ns::$optional<Foo> opt($ns::in_place, {3}); 1616 opt.value(); 1617 } 1618 )"); 1619 } 1620 1621 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) { 1622 ExpectDiagnosticsFor(R"( 1623 #include "unchecked_optional_access_test.h" 1624 1625 void target() { 1626 $ns::$optional<int> opt(21); 1627 opt.value(); 1628 } 1629 )"); 1630 1631 ExpectDiagnosticsFor(R"( 1632 #include "unchecked_optional_access_test.h" 1633 1634 void target() { 1635 $ns::$optional<int> opt = $ns::$optional<int>(21); 1636 opt.value(); 1637 } 1638 )"); 1639 ExpectDiagnosticsFor(R"( 1640 #include "unchecked_optional_access_test.h" 1641 1642 void target() { 1643 $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>()); 1644 opt.value(); 1645 } 1646 )"); 1647 1648 ExpectDiagnosticsFor(R"( 1649 #include "unchecked_optional_access_test.h" 1650 1651 struct MyString { 1652 MyString(const char*); 1653 }; 1654 1655 void target() { 1656 $ns::$optional<MyString> opt("foo"); 1657 opt.value(); 1658 } 1659 )"); 1660 1661 ExpectDiagnosticsFor(R"( 1662 #include "unchecked_optional_access_test.h" 1663 1664 struct Foo {}; 1665 1666 struct Bar { 1667 Bar(const Foo&); 1668 }; 1669 1670 void target() { 1671 $ns::$optional<Bar> opt(Make<Foo>()); 1672 opt.value(); 1673 } 1674 )"); 1675 1676 ExpectDiagnosticsFor(R"( 1677 #include "unchecked_optional_access_test.h" 1678 1679 struct Foo { 1680 explicit Foo(int); 1681 }; 1682 1683 void target() { 1684 $ns::$optional<Foo> opt(3); 1685 opt.value(); 1686 } 1687 )"); 1688 } 1689 1690 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) { 1691 ExpectDiagnosticsFor( 1692 R"( 1693 #include "unchecked_optional_access_test.h" 1694 1695 struct Foo {}; 1696 1697 struct Bar { 1698 Bar(const Foo&); 1699 }; 1700 1701 void target() { 1702 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>()); 1703 opt.value(); // [[unsafe]] 1704 } 1705 )"); 1706 1707 ExpectDiagnosticsFor( 1708 R"( 1709 #include "unchecked_optional_access_test.h" 1710 1711 struct Foo {}; 1712 1713 struct Bar { 1714 explicit Bar(const Foo&); 1715 }; 1716 1717 void target() { 1718 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>()); 1719 opt.value(); // [[unsafe]] 1720 } 1721 )"); 1722 1723 ExpectDiagnosticsFor( 1724 R"( 1725 #include "unchecked_optional_access_test.h" 1726 1727 struct Foo {}; 1728 1729 struct Bar { 1730 Bar(const Foo&); 1731 }; 1732 1733 void target() { 1734 $ns::$optional<Foo> opt1 = $ns::nullopt; 1735 $ns::$optional<Bar> opt2(opt1); 1736 opt2.value(); // [[unsafe]] 1737 } 1738 )"); 1739 1740 ExpectDiagnosticsFor(R"( 1741 #include "unchecked_optional_access_test.h" 1742 1743 struct Foo {}; 1744 1745 struct Bar { 1746 Bar(const Foo&); 1747 }; 1748 1749 void target() { 1750 $ns::$optional<Foo> opt1(Make<Foo>()); 1751 $ns::$optional<Bar> opt2(opt1); 1752 opt2.value(); 1753 } 1754 )"); 1755 1756 ExpectDiagnosticsFor(R"( 1757 #include "unchecked_optional_access_test.h" 1758 1759 struct Foo {}; 1760 1761 struct Bar { 1762 explicit Bar(const Foo&); 1763 }; 1764 1765 void target() { 1766 $ns::$optional<Foo> opt1(Make<Foo>()); 1767 $ns::$optional<Bar> opt2(opt1); 1768 opt2.value(); 1769 } 1770 )"); 1771 } 1772 1773 TEST_P(UncheckedOptionalAccessTest, MakeOptional) { 1774 ExpectDiagnosticsFor(R"( 1775 #include "unchecked_optional_access_test.h" 1776 1777 void target() { 1778 $ns::$optional<int> opt = $ns::make_optional(0); 1779 opt.value(); 1780 } 1781 )"); 1782 1783 ExpectDiagnosticsFor(R"( 1784 #include "unchecked_optional_access_test.h" 1785 1786 struct Foo { 1787 Foo(int, int); 1788 }; 1789 1790 void target() { 1791 $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22); 1792 opt.value(); 1793 } 1794 )"); 1795 1796 ExpectDiagnosticsFor(R"( 1797 #include "unchecked_optional_access_test.h" 1798 1799 struct Foo { 1800 constexpr Foo(std::initializer_list<char>); 1801 }; 1802 1803 void target() { 1804 char a = 'a'; 1805 $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a}); 1806 opt.value(); 1807 } 1808 )"); 1809 } 1810 1811 TEST_P(UncheckedOptionalAccessTest, ValueOr) { 1812 ExpectDiagnosticsFor(R"( 1813 #include "unchecked_optional_access_test.h" 1814 1815 void target() { 1816 $ns::$optional<int> opt; 1817 opt.value_or(0); 1818 (void)0; 1819 } 1820 )"); 1821 } 1822 1823 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointers) { 1824 ExpectDiagnosticsFor( 1825 R"code( 1826 #include "unchecked_optional_access_test.h" 1827 1828 void target($ns::$optional<int*> opt) { 1829 if (opt.value_or(nullptr) != nullptr) { 1830 opt.value(); 1831 } else { 1832 opt.value(); // [[unsafe]] 1833 } 1834 } 1835 )code"); 1836 } 1837 1838 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonIntegers) { 1839 ExpectDiagnosticsFor( 1840 R"code( 1841 #include "unchecked_optional_access_test.h" 1842 1843 void target($ns::$optional<int> opt) { 1844 if (opt.value_or(0) != 0) { 1845 opt.value(); 1846 } else { 1847 opt.value(); // [[unsafe]] 1848 } 1849 } 1850 )code"); 1851 } 1852 1853 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonStrings) { 1854 ExpectDiagnosticsFor( 1855 R"code( 1856 #include "unchecked_optional_access_test.h" 1857 1858 void target($ns::$optional<std::string> opt) { 1859 if (!opt.value_or("").empty()) { 1860 opt.value(); 1861 } else { 1862 opt.value(); // [[unsafe]] 1863 } 1864 } 1865 )code"); 1866 1867 ExpectDiagnosticsFor( 1868 R"code( 1869 #include "unchecked_optional_access_test.h" 1870 1871 void target($ns::$optional<std::string> opt) { 1872 if (opt.value_or("") != "") { 1873 opt.value(); 1874 } else { 1875 opt.value(); // [[unsafe]] 1876 } 1877 } 1878 )code"); 1879 } 1880 1881 TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointerToOptional) { 1882 // FIXME: make `opt` a parameter directly, once we ensure that all `optional` 1883 // values have a `has_value` property. 1884 ExpectDiagnosticsFor( 1885 R"code( 1886 #include "unchecked_optional_access_test.h" 1887 1888 void target($ns::$optional<int> p) { 1889 $ns::$optional<int> *opt = &p; 1890 if (opt->value_or(0) != 0) { 1891 opt->value(); 1892 } else { 1893 opt->value(); // [[unsafe]] 1894 } 1895 } 1896 )code"); 1897 } 1898 1899 TEST_P(UncheckedOptionalAccessTest, Emplace) { 1900 ExpectDiagnosticsFor(R"( 1901 #include "unchecked_optional_access_test.h" 1902 1903 void target() { 1904 $ns::$optional<int> opt; 1905 opt.emplace(0); 1906 opt.value(); 1907 } 1908 )"); 1909 1910 ExpectDiagnosticsFor(R"( 1911 #include "unchecked_optional_access_test.h" 1912 1913 void target($ns::$optional<int> *opt) { 1914 opt->emplace(0); 1915 opt->value(); 1916 } 1917 )"); 1918 1919 // FIXME: Add tests that call `emplace` in conditional branches: 1920 // ExpectDiagnosticsFor( 1921 // R"( 1922 // #include "unchecked_optional_access_test.h" 1923 // 1924 // void target($ns::$optional<int> opt, bool b) { 1925 // if (b) { 1926 // opt.emplace(0); 1927 // } 1928 // if (b) { 1929 // opt.value(); 1930 // } else { 1931 // opt.value(); // [[unsafe]] 1932 // } 1933 // } 1934 // )"); 1935 } 1936 1937 TEST_P(UncheckedOptionalAccessTest, Reset) { 1938 ExpectDiagnosticsFor( 1939 R"( 1940 #include "unchecked_optional_access_test.h" 1941 1942 void target() { 1943 $ns::$optional<int> opt = $ns::make_optional(0); 1944 opt.reset(); 1945 opt.value(); // [[unsafe]] 1946 } 1947 )"); 1948 1949 ExpectDiagnosticsFor( 1950 R"( 1951 #include "unchecked_optional_access_test.h" 1952 1953 void target($ns::$optional<int> &opt) { 1954 if (opt.has_value()) { 1955 opt.reset(); 1956 opt.value(); // [[unsafe]] 1957 } 1958 } 1959 )"); 1960 1961 // FIXME: Add tests that call `reset` in conditional branches: 1962 // ExpectDiagnosticsFor( 1963 // R"( 1964 // #include "unchecked_optional_access_test.h" 1965 // 1966 // void target(bool b) { 1967 // $ns::$optional<int> opt = $ns::make_optional(0); 1968 // if (b) { 1969 // opt.reset(); 1970 // } 1971 // if (b) { 1972 // opt.value(); // [[unsafe]] 1973 // } else { 1974 // opt.value(); 1975 // } 1976 // } 1977 // )"); 1978 } 1979 1980 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) { 1981 ExpectDiagnosticsFor(R"( 1982 #include "unchecked_optional_access_test.h" 1983 1984 struct Foo {}; 1985 1986 void target() { 1987 $ns::$optional<Foo> opt; 1988 opt = Foo(); 1989 opt.value(); 1990 } 1991 )"); 1992 1993 ExpectDiagnosticsFor(R"( 1994 #include "unchecked_optional_access_test.h" 1995 1996 struct Foo {}; 1997 1998 void target() { 1999 $ns::$optional<Foo> opt; 2000 (opt = Foo()).value(); 2001 (void)0; 2002 } 2003 )"); 2004 2005 ExpectDiagnosticsFor(R"( 2006 #include "unchecked_optional_access_test.h" 2007 2008 struct MyString { 2009 MyString(const char*); 2010 }; 2011 2012 void target() { 2013 $ns::$optional<MyString> opt; 2014 opt = "foo"; 2015 opt.value(); 2016 } 2017 )"); 2018 2019 ExpectDiagnosticsFor(R"( 2020 #include "unchecked_optional_access_test.h" 2021 2022 struct MyString { 2023 MyString(const char*); 2024 }; 2025 2026 void target() { 2027 $ns::$optional<MyString> opt; 2028 (opt = "foo").value(); 2029 } 2030 )"); 2031 } 2032 2033 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) { 2034 ExpectDiagnosticsFor( 2035 R"( 2036 #include "unchecked_optional_access_test.h" 2037 2038 struct Foo {}; 2039 2040 struct Bar { 2041 Bar(const Foo&); 2042 }; 2043 2044 void target() { 2045 $ns::$optional<Foo> opt1 = Foo(); 2046 $ns::$optional<Bar> opt2; 2047 opt2 = opt1; 2048 opt2.value(); 2049 } 2050 )"); 2051 2052 ExpectDiagnosticsFor( 2053 R"( 2054 #include "unchecked_optional_access_test.h" 2055 2056 struct Foo {}; 2057 2058 struct Bar { 2059 Bar(const Foo&); 2060 }; 2061 2062 void target() { 2063 $ns::$optional<Foo> opt1; 2064 $ns::$optional<Bar> opt2; 2065 if (opt2.has_value()) { 2066 opt2 = opt1; 2067 opt2.value(); // [[unsafe]] 2068 } 2069 } 2070 )"); 2071 2072 ExpectDiagnosticsFor( 2073 R"( 2074 #include "unchecked_optional_access_test.h" 2075 2076 struct Foo {}; 2077 2078 struct Bar { 2079 Bar(const Foo&); 2080 }; 2081 2082 void target() { 2083 $ns::$optional<Foo> opt1 = Foo(); 2084 $ns::$optional<Bar> opt2; 2085 (opt2 = opt1).value(); 2086 (void)0; 2087 } 2088 )"); 2089 } 2090 2091 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) { 2092 ExpectDiagnosticsFor( 2093 R"( 2094 #include "unchecked_optional_access_test.h" 2095 2096 void target() { 2097 $ns::$optional<int> opt = 3; 2098 opt = $ns::nullopt; 2099 opt.value(); // [[unsafe]] 2100 } 2101 )"); 2102 2103 ExpectDiagnosticsFor( 2104 R"( 2105 #include "unchecked_optional_access_test.h" 2106 2107 void target() { 2108 $ns::$optional<int> opt = 3; 2109 (opt = $ns::nullopt).value(); // [[unsafe]] 2110 } 2111 )"); 2112 } 2113 2114 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) { 2115 ExpectDiagnosticsFor( 2116 R"( 2117 #include "unchecked_optional_access_test.h" 2118 2119 void target() { 2120 $ns::$optional<int> opt1 = $ns::nullopt; 2121 $ns::$optional<int> opt2 = 3; 2122 2123 opt1.swap(opt2); 2124 2125 opt1.value(); 2126 2127 opt2.value(); // [[unsafe]] 2128 } 2129 )"); 2130 2131 ExpectDiagnosticsFor( 2132 R"( 2133 #include "unchecked_optional_access_test.h" 2134 2135 void target() { 2136 $ns::$optional<int> opt1 = $ns::nullopt; 2137 $ns::$optional<int> opt2 = 3; 2138 2139 opt2.swap(opt1); 2140 2141 opt1.value(); 2142 2143 opt2.value(); // [[unsafe]] 2144 } 2145 )"); 2146 } 2147 2148 TEST_P(UncheckedOptionalAccessTest, OptionalReturnedFromFuntionCall) { 2149 ExpectDiagnosticsFor( 2150 R"( 2151 #include "unchecked_optional_access_test.h" 2152 2153 struct S { 2154 $ns::$optional<float> x; 2155 } s; 2156 S getOptional() { 2157 return s; 2158 } 2159 2160 void target() { 2161 getOptional().x = 0; 2162 } 2163 )"); 2164 } 2165 2166 TEST_P(UncheckedOptionalAccessTest, StdSwap) { 2167 ExpectDiagnosticsFor( 2168 R"( 2169 #include "unchecked_optional_access_test.h" 2170 2171 void target() { 2172 $ns::$optional<int> opt1 = $ns::nullopt; 2173 $ns::$optional<int> opt2 = 3; 2174 2175 std::swap(opt1, opt2); 2176 2177 opt1.value(); 2178 2179 opt2.value(); // [[unsafe]] 2180 } 2181 )"); 2182 2183 ExpectDiagnosticsFor( 2184 R"( 2185 #include "unchecked_optional_access_test.h" 2186 2187 void target() { 2188 $ns::$optional<int> opt1 = $ns::nullopt; 2189 $ns::$optional<int> opt2 = 3; 2190 2191 std::swap(opt2, opt1); 2192 2193 opt1.value(); 2194 2195 opt2.value(); // [[unsafe]] 2196 } 2197 )"); 2198 } 2199 2200 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocLeft) { 2201 ExpectDiagnosticsFor( 2202 R"( 2203 #include "unchecked_optional_access_test.h" 2204 2205 struct L { $ns::$optional<int> hd; L* tl; }; 2206 2207 void target() { 2208 $ns::$optional<int> foo = 3; 2209 L bar; 2210 2211 // Any `tl` beyond the first is not modeled. 2212 bar.tl->tl->hd.swap(foo); 2213 2214 bar.tl->tl->hd.value(); // [[unsafe]] 2215 foo.value(); // [[unsafe]] 2216 } 2217 )"); 2218 } 2219 2220 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocRight) { 2221 ExpectDiagnosticsFor( 2222 R"( 2223 #include "unchecked_optional_access_test.h" 2224 2225 struct L { $ns::$optional<int> hd; L* tl; }; 2226 2227 void target() { 2228 $ns::$optional<int> foo = 3; 2229 L bar; 2230 2231 // Any `tl` beyond the first is not modeled. 2232 foo.swap(bar.tl->tl->hd); 2233 2234 bar.tl->tl->hd.value(); // [[unsafe]] 2235 foo.value(); // [[unsafe]] 2236 } 2237 )"); 2238 } 2239 2240 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftSet) { 2241 ExpectDiagnosticsFor( 2242 R"( 2243 #include "unchecked_optional_access_test.h" 2244 2245 struct S { int x; }; 2246 struct A { $ns::$optional<S> late; }; 2247 struct B { A f3; }; 2248 struct C { B f2; }; 2249 struct D { C f1; }; 2250 2251 void target() { 2252 $ns::$optional<S> foo = S{3}; 2253 D bar; 2254 2255 bar.f1.f2.f3.late.swap(foo); 2256 2257 bar.f1.f2.f3.late.value(); 2258 foo.value(); // [[unsafe]] 2259 } 2260 )"); 2261 } 2262 2263 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftUnset) { 2264 ExpectDiagnosticsFor( 2265 R"( 2266 #include "unchecked_optional_access_test.h" 2267 2268 struct S { int x; }; 2269 struct A { $ns::$optional<S> late; }; 2270 struct B { A f3; }; 2271 struct C { B f2; }; 2272 struct D { C f1; }; 2273 2274 void target() { 2275 $ns::$optional<S> foo; 2276 D bar; 2277 2278 bar.f1.f2.f3.late.swap(foo); 2279 2280 bar.f1.f2.f3.late.value(); // [[unsafe]] 2281 foo.value(); // [[unsafe]] 2282 } 2283 )"); 2284 } 2285 2286 // fixme: use recursion instead of depth. 2287 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightSet) { 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 = S{3}; 2300 D bar; 2301 2302 foo.swap(bar.f1.f2.f3.late); 2303 2304 bar.f1.f2.f3.late.value(); 2305 foo.value(); // [[unsafe]] 2306 } 2307 )"); 2308 } 2309 2310 TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightUnset) { 2311 ExpectDiagnosticsFor( 2312 R"( 2313 #include "unchecked_optional_access_test.h" 2314 2315 struct S { int x; }; 2316 struct A { $ns::$optional<S> late; }; 2317 struct B { A f3; }; 2318 struct C { B f2; }; 2319 struct D { C f1; }; 2320 2321 void target() { 2322 $ns::$optional<S> foo; 2323 D bar; 2324 2325 foo.swap(bar.f1.f2.f3.late); 2326 2327 bar.f1.f2.f3.late.value(); // [[unsafe]] 2328 foo.value(); // [[unsafe]] 2329 } 2330 )"); 2331 } 2332 2333 TEST_P(UncheckedOptionalAccessTest, UniquePtrToOptional) { 2334 // We suppress diagnostics for optionals in smart pointers (other than 2335 // `optional` itself). 2336 ExpectDiagnosticsFor( 2337 R"( 2338 #include "unchecked_optional_access_test.h" 2339 2340 template <typename T> 2341 struct smart_ptr { 2342 T& operator*() &; 2343 T* operator->(); 2344 }; 2345 2346 void target() { 2347 smart_ptr<$ns::$optional<bool>> foo; 2348 foo->value(); 2349 (*foo).value(); 2350 } 2351 )"); 2352 } 2353 2354 TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) { 2355 // We suppress diagnostics for optional fields reachable from smart pointers 2356 // (other than `optional` itself) through (exactly) one member access. 2357 ExpectDiagnosticsFor( 2358 R"( 2359 #include "unchecked_optional_access_test.h" 2360 2361 template <typename T> 2362 struct smart_ptr { 2363 T& operator*() &; 2364 T* operator->(); 2365 }; 2366 2367 struct Foo { 2368 $ns::$optional<int> opt; 2369 }; 2370 2371 void target() { 2372 smart_ptr<Foo> foo; 2373 *foo->opt; 2374 *(*foo).opt; 2375 } 2376 )"); 2377 } 2378 2379 TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) { 2380 ExpectDiagnosticsFor( 2381 R"( 2382 #include "unchecked_optional_access_test.h" 2383 2384 $ns::$optional<int> MakeOpt(); 2385 2386 void target() { 2387 $ns::$optional<int> opt = 0; 2388 opt = MakeOpt(); 2389 opt.value(); // [[unsafe]] 2390 } 2391 )"); 2392 ExpectDiagnosticsFor( 2393 R"( 2394 #include "unchecked_optional_access_test.h" 2395 2396 const $ns::$optional<int>& MakeOpt(); 2397 2398 void target() { 2399 $ns::$optional<int> opt = 0; 2400 opt = MakeOpt(); 2401 opt.value(); // [[unsafe]] 2402 } 2403 )"); 2404 2405 ExpectDiagnosticsFor( 2406 R"( 2407 #include "unchecked_optional_access_test.h" 2408 2409 using IntOpt = $ns::$optional<int>; 2410 IntOpt MakeOpt(); 2411 2412 void target() { 2413 IntOpt opt = 0; 2414 opt = MakeOpt(); 2415 opt.value(); // [[unsafe]] 2416 } 2417 )"); 2418 2419 ExpectDiagnosticsFor( 2420 R"( 2421 #include "unchecked_optional_access_test.h" 2422 2423 using IntOpt = $ns::$optional<int>; 2424 const IntOpt& MakeOpt(); 2425 2426 void target() { 2427 IntOpt opt = 0; 2428 opt = MakeOpt(); 2429 opt.value(); // [[unsafe]] 2430 } 2431 )"); 2432 } 2433 2434 2435 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftSet) { 2436 ExpectDiagnosticsFor( 2437 R"( 2438 #include "unchecked_optional_access_test.h" 2439 2440 void target() { 2441 $ns::$optional<int> opt1 = 3; 2442 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2443 2444 if (opt1 == opt2) { 2445 opt2.value(); 2446 } else { 2447 opt2.value(); // [[unsafe]] 2448 } 2449 } 2450 )"); 2451 } 2452 2453 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightSet) { 2454 ExpectDiagnosticsFor( 2455 R"( 2456 #include "unchecked_optional_access_test.h" 2457 2458 void target() { 2459 $ns::$optional<int> opt1 = 3; 2460 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2461 2462 if (opt2 == opt1) { 2463 opt2.value(); 2464 } else { 2465 opt2.value(); // [[unsafe]] 2466 } 2467 } 2468 )"); 2469 } 2470 2471 TEST_P(UncheckedOptionalAccessTest, EqualityCheckVerifySetAfterEq) { 2472 ExpectDiagnosticsFor( 2473 R"( 2474 #include "unchecked_optional_access_test.h" 2475 2476 void target() { 2477 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>(); 2478 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2479 2480 if (opt1 == opt2) { 2481 if (opt1.has_value()) 2482 opt2.value(); 2483 if (opt2.has_value()) 2484 opt1.value(); 2485 } 2486 } 2487 )"); 2488 } 2489 2490 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftUnset) { 2491 ExpectDiagnosticsFor( 2492 R"( 2493 #include "unchecked_optional_access_test.h" 2494 2495 void target() { 2496 $ns::$optional<int> opt1 = $ns::nullopt; 2497 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2498 2499 if (opt1 == opt2) { 2500 opt2.value(); // [[unsafe]] 2501 } else { 2502 opt2.value(); 2503 } 2504 } 2505 )"); 2506 } 2507 2508 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightUnset) { 2509 ExpectDiagnosticsFor( 2510 R"( 2511 #include "unchecked_optional_access_test.h" 2512 2513 void target() { 2514 $ns::$optional<int> opt1 = $ns::nullopt; 2515 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2516 2517 if (opt2 == opt1) { 2518 opt2.value(); // [[unsafe]] 2519 } else { 2520 opt2.value(); 2521 } 2522 } 2523 )"); 2524 } 2525 2526 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightNullopt) { 2527 ExpectDiagnosticsFor( 2528 R"( 2529 #include "unchecked_optional_access_test.h" 2530 2531 void target() { 2532 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2533 2534 if (opt == $ns::nullopt) { 2535 opt.value(); // [[unsafe]] 2536 } else { 2537 opt.value(); 2538 } 2539 } 2540 )"); 2541 } 2542 2543 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftNullopt) { 2544 ExpectDiagnosticsFor( 2545 R"( 2546 #include "unchecked_optional_access_test.h" 2547 2548 void target() { 2549 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2550 2551 if ($ns::nullopt == opt) { 2552 opt.value(); // [[unsafe]] 2553 } else { 2554 opt.value(); 2555 } 2556 } 2557 )"); 2558 } 2559 2560 TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightValue) { 2561 ExpectDiagnosticsFor( 2562 R"( 2563 #include "unchecked_optional_access_test.h" 2564 2565 void target() { 2566 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2567 2568 if (opt == 3) { 2569 opt.value(); 2570 } else { 2571 opt.value(); // [[unsafe]] 2572 } 2573 } 2574 )"); 2575 } 2576 2577 TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftValue) { 2578 ExpectDiagnosticsFor( 2579 R"( 2580 #include "unchecked_optional_access_test.h" 2581 2582 void target() { 2583 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2584 2585 if (3 == opt) { 2586 opt.value(); 2587 } else { 2588 opt.value(); // [[unsafe]] 2589 } 2590 } 2591 )"); 2592 } 2593 2594 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftSet) { 2595 ExpectDiagnosticsFor( 2596 R"( 2597 #include "unchecked_optional_access_test.h" 2598 2599 void target() { 2600 $ns::$optional<int> opt1 = 3; 2601 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2602 2603 if (opt1 != opt2) { 2604 opt2.value(); // [[unsafe]] 2605 } else { 2606 opt2.value(); 2607 } 2608 } 2609 )"); 2610 } 2611 2612 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightSet) { 2613 ExpectDiagnosticsFor( 2614 R"( 2615 #include "unchecked_optional_access_test.h" 2616 2617 void target() { 2618 $ns::$optional<int> opt1 = 3; 2619 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2620 2621 if (opt2 != opt1) { 2622 opt2.value(); // [[unsafe]] 2623 } else { 2624 opt2.value(); 2625 } 2626 } 2627 )"); 2628 } 2629 2630 TEST_P(UncheckedOptionalAccessTest, InequalityCheckVerifySetAfterEq) { 2631 ExpectDiagnosticsFor( 2632 R"( 2633 #include "unchecked_optional_access_test.h" 2634 2635 void target() { 2636 $ns::$optional<int> opt1 = Make<$ns::$optional<int>>(); 2637 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2638 2639 if (opt1 != opt2) { 2640 if (opt1.has_value()) 2641 opt2.value(); // [[unsafe]] 2642 if (opt2.has_value()) 2643 opt1.value(); // [[unsafe]] 2644 } 2645 } 2646 )"); 2647 } 2648 2649 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftUnset) { 2650 ExpectDiagnosticsFor( 2651 R"( 2652 #include "unchecked_optional_access_test.h" 2653 2654 void target() { 2655 $ns::$optional<int> opt1 = $ns::nullopt; 2656 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2657 2658 if (opt1 != opt2) { 2659 opt2.value(); 2660 } else { 2661 opt2.value(); // [[unsafe]] 2662 } 2663 } 2664 )"); 2665 } 2666 2667 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightUnset) { 2668 ExpectDiagnosticsFor( 2669 R"( 2670 #include "unchecked_optional_access_test.h" 2671 2672 void target() { 2673 $ns::$optional<int> opt1 = $ns::nullopt; 2674 $ns::$optional<int> opt2 = Make<$ns::$optional<int>>(); 2675 2676 if (opt2 != opt1) { 2677 opt2.value(); 2678 } else { 2679 opt2.value(); // [[unsafe]] 2680 } 2681 } 2682 )"); 2683 } 2684 2685 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightNullopt) { 2686 ExpectDiagnosticsFor( 2687 R"( 2688 #include "unchecked_optional_access_test.h" 2689 2690 void target() { 2691 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2692 2693 if (opt != $ns::nullopt) { 2694 opt.value(); 2695 } else { 2696 opt.value(); // [[unsafe]] 2697 } 2698 } 2699 )"); 2700 } 2701 2702 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftNullopt) { 2703 ExpectDiagnosticsFor( 2704 R"( 2705 #include "unchecked_optional_access_test.h" 2706 2707 void target() { 2708 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2709 2710 if ($ns::nullopt != opt) { 2711 opt.value(); 2712 } else { 2713 opt.value(); // [[unsafe]] 2714 } 2715 } 2716 )"); 2717 } 2718 2719 TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightValue) { 2720 ExpectDiagnosticsFor( 2721 R"( 2722 #include "unchecked_optional_access_test.h" 2723 2724 void target() { 2725 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2726 2727 if (opt != 3) { 2728 opt.value(); // [[unsafe]] 2729 } else { 2730 opt.value(); 2731 } 2732 } 2733 )"); 2734 } 2735 2736 TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftValue) { 2737 ExpectDiagnosticsFor( 2738 R"( 2739 #include "unchecked_optional_access_test.h" 2740 2741 void target() { 2742 $ns::$optional<int> opt = Make<$ns::$optional<int>>(); 2743 2744 if (3 != opt) { 2745 opt.value(); // [[unsafe]] 2746 } else { 2747 opt.value(); 2748 } 2749 } 2750 )"); 2751 } 2752 2753 // Verifies that the model sees through aliases. 2754 TEST_P(UncheckedOptionalAccessTest, WithAlias) { 2755 ExpectDiagnosticsFor( 2756 R"( 2757 #include "unchecked_optional_access_test.h" 2758 2759 template <typename T> 2760 using MyOptional = $ns::$optional<T>; 2761 2762 void target(MyOptional<int> opt) { 2763 opt.value(); // [[unsafe]] 2764 } 2765 )"); 2766 } 2767 2768 TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) { 2769 // Basic test that nested values are populated. We nest an optional because 2770 // its easy to use in a test, but the type of the nested value shouldn't 2771 // matter. 2772 ExpectDiagnosticsFor( 2773 R"( 2774 #include "unchecked_optional_access_test.h" 2775 2776 using Foo = $ns::$optional<std::string>; 2777 2778 void target($ns::$optional<Foo> foo) { 2779 if (foo && *foo) { 2780 foo->value(); 2781 } 2782 } 2783 )"); 2784 2785 // Mutation is supported for nested values. 2786 ExpectDiagnosticsFor( 2787 R"( 2788 #include "unchecked_optional_access_test.h" 2789 2790 using Foo = $ns::$optional<std::string>; 2791 2792 void target($ns::$optional<Foo> foo) { 2793 if (foo && *foo) { 2794 foo->reset(); 2795 foo->value(); // [[unsafe]] 2796 } 2797 } 2798 )"); 2799 } 2800 2801 // Tests that structs can be nested. We use an optional field because its easy 2802 // to use in a test, but the type of the field shouldn't matter. 2803 TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) { 2804 ExpectDiagnosticsFor( 2805 R"( 2806 #include "unchecked_optional_access_test.h" 2807 2808 struct Foo { 2809 $ns::$optional<std::string> opt; 2810 }; 2811 2812 void target($ns::$optional<Foo> foo) { 2813 if (foo && foo->opt) { 2814 foo->opt.value(); 2815 } 2816 } 2817 )"); 2818 } 2819 2820 TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) { 2821 ExpectDiagnosticsFor( 2822 R"( 2823 #include "unchecked_optional_access_test.h" 2824 2825 using Foo = $ns::$optional<std::string>; 2826 2827 void target($ns::$optional<Foo> foo, bool b) { 2828 if (!foo.has_value()) return; 2829 if (b) { 2830 if (!foo->has_value()) return; 2831 // We have created `foo.value()`. 2832 foo->value(); 2833 } else { 2834 if (!foo->has_value()) return; 2835 // We have created `foo.value()` again, in a different environment. 2836 foo->value(); 2837 } 2838 // Now we merge the two values. UncheckedOptionalAccessModel::merge() will 2839 // throw away the "value" property. 2840 foo->value(); 2841 } 2842 )"); 2843 } 2844 2845 // This test is aimed at the core model, not the diagnostic. It is a regression 2846 // test against a crash when using non-trivial smart pointers, like 2847 // `std::unique_ptr`. As such, it doesn't test the access itself, which would be 2848 // ignored regardless because of `IgnoreSmartPointerDereference = true`, above. 2849 TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) { 2850 ExpectDiagnosticsFor( 2851 R"( 2852 #include "unchecked_optional_access_test.h" 2853 2854 template <typename T> 2855 struct smart_ptr { 2856 typename std::add_lvalue_reference<T>::type operator*() &; 2857 }; 2858 2859 void target() { 2860 smart_ptr<$ns::$optional<int>> x; 2861 // Verify that this assignment does not crash. 2862 *x = 3; 2863 } 2864 )"); 2865 } 2866 2867 TEST_P(UncheckedOptionalAccessTest, CorrelatedBranches) { 2868 ExpectDiagnosticsFor(R"code( 2869 #include "unchecked_optional_access_test.h" 2870 2871 void target(bool b, $ns::$optional<int> opt) { 2872 if (b || opt.has_value()) { 2873 if (!b) { 2874 opt.value(); 2875 } 2876 } 2877 } 2878 )code"); 2879 2880 ExpectDiagnosticsFor(R"code( 2881 #include "unchecked_optional_access_test.h" 2882 2883 void target(bool b, $ns::$optional<int> opt) { 2884 if (b && !opt.has_value()) return; 2885 if (b) { 2886 opt.value(); 2887 } 2888 } 2889 )code"); 2890 2891 ExpectDiagnosticsFor( 2892 R"code( 2893 #include "unchecked_optional_access_test.h" 2894 2895 void target(bool b, $ns::$optional<int> opt) { 2896 if (opt.has_value()) b = true; 2897 if (b) { 2898 opt.value(); // [[unsafe]] 2899 } 2900 } 2901 )code"); 2902 2903 ExpectDiagnosticsFor(R"code( 2904 #include "unchecked_optional_access_test.h" 2905 2906 void target(bool b, $ns::$optional<int> opt) { 2907 if (b) return; 2908 if (opt.has_value()) b = true; 2909 if (b) { 2910 opt.value(); 2911 } 2912 } 2913 )code"); 2914 2915 ExpectDiagnosticsFor(R"( 2916 #include "unchecked_optional_access_test.h" 2917 2918 void target(bool b, $ns::$optional<int> opt) { 2919 if (opt.has_value() == b) { 2920 if (b) { 2921 opt.value(); 2922 } 2923 } 2924 } 2925 )"); 2926 2927 ExpectDiagnosticsFor(R"( 2928 #include "unchecked_optional_access_test.h" 2929 2930 void target(bool b, $ns::$optional<int> opt) { 2931 if (opt.has_value() != b) { 2932 if (!b) { 2933 opt.value(); 2934 } 2935 } 2936 } 2937 )"); 2938 2939 ExpectDiagnosticsFor(R"( 2940 #include "unchecked_optional_access_test.h" 2941 2942 void target(bool b) { 2943 $ns::$optional<int> opt1 = $ns::nullopt; 2944 $ns::$optional<int> opt2; 2945 if (b) { 2946 opt2 = $ns::nullopt; 2947 } else { 2948 opt2 = $ns::nullopt; 2949 } 2950 if (opt2.has_value()) { 2951 opt1.value(); 2952 } 2953 } 2954 )"); 2955 } 2956 2957 TEST_P(UncheckedOptionalAccessTest, JoinDistinctValues) { 2958 ExpectDiagnosticsFor( 2959 R"code( 2960 #include "unchecked_optional_access_test.h" 2961 2962 void target(bool b) { 2963 $ns::$optional<int> opt; 2964 if (b) { 2965 opt = Make<$ns::$optional<int>>(); 2966 } else { 2967 opt = Make<$ns::$optional<int>>(); 2968 } 2969 if (opt.has_value()) { 2970 opt.value(); 2971 } else { 2972 opt.value(); // [[unsafe]] 2973 } 2974 } 2975 )code"); 2976 2977 ExpectDiagnosticsFor(R"code( 2978 #include "unchecked_optional_access_test.h" 2979 2980 void target(bool b) { 2981 $ns::$optional<int> opt; 2982 if (b) { 2983 opt = Make<$ns::$optional<int>>(); 2984 if (!opt.has_value()) return; 2985 } else { 2986 opt = Make<$ns::$optional<int>>(); 2987 if (!opt.has_value()) return; 2988 } 2989 opt.value(); 2990 } 2991 )code"); 2992 2993 ExpectDiagnosticsFor( 2994 R"code( 2995 #include "unchecked_optional_access_test.h" 2996 2997 void target(bool b) { 2998 $ns::$optional<int> opt; 2999 if (b) { 3000 opt = Make<$ns::$optional<int>>(); 3001 if (!opt.has_value()) return; 3002 } else { 3003 opt = Make<$ns::$optional<int>>(); 3004 } 3005 opt.value(); // [[unsafe]] 3006 } 3007 )code"); 3008 3009 ExpectDiagnosticsFor( 3010 R"code( 3011 #include "unchecked_optional_access_test.h" 3012 3013 void target(bool b) { 3014 $ns::$optional<int> opt; 3015 if (b) { 3016 opt = 1; 3017 } else { 3018 opt = 2; 3019 } 3020 opt.value(); 3021 } 3022 )code"); 3023 3024 ExpectDiagnosticsFor( 3025 R"code( 3026 #include "unchecked_optional_access_test.h" 3027 3028 void target(bool b) { 3029 $ns::$optional<int> opt; 3030 if (b) { 3031 opt = 1; 3032 } else { 3033 opt = Make<$ns::$optional<int>>(); 3034 } 3035 opt.value(); // [[unsafe]] 3036 } 3037 )code"); 3038 } 3039 3040 TEST_P(UncheckedOptionalAccessTest, AccessValueInLoop) { 3041 ExpectDiagnosticsFor(R"( 3042 #include "unchecked_optional_access_test.h" 3043 3044 void target() { 3045 $ns::$optional<int> opt = 3; 3046 while (Make<bool>()) { 3047 opt.value(); 3048 } 3049 } 3050 )"); 3051 } 3052 3053 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopWithCheckSafe) { 3054 ExpectDiagnosticsFor(R"( 3055 #include "unchecked_optional_access_test.h" 3056 3057 void target() { 3058 $ns::$optional<int> opt = 3; 3059 while (Make<bool>()) { 3060 opt.value(); 3061 3062 opt = Make<$ns::$optional<int>>(); 3063 if (!opt.has_value()) return; 3064 } 3065 } 3066 )"); 3067 } 3068 3069 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopNoCheckUnsafe) { 3070 ExpectDiagnosticsFor( 3071 R"( 3072 #include "unchecked_optional_access_test.h" 3073 3074 void target() { 3075 $ns::$optional<int> opt = 3; 3076 while (Make<bool>()) { 3077 opt.value(); // [[unsafe]] 3078 3079 opt = Make<$ns::$optional<int>>(); 3080 } 3081 } 3082 )"); 3083 } 3084 3085 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnsetUnsafe) { 3086 ExpectDiagnosticsFor( 3087 R"( 3088 #include "unchecked_optional_access_test.h" 3089 3090 void target() { 3091 $ns::$optional<int> opt = 3; 3092 while (Make<bool>()) 3093 opt = $ns::nullopt; 3094 $ns::$optional<int> opt2 = $ns::nullopt; 3095 if (opt.has_value()) 3096 opt2 = $ns::$optional<int>(3); 3097 opt2.value(); // [[unsafe]] 3098 } 3099 )"); 3100 } 3101 3102 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToSetUnsafe) { 3103 ExpectDiagnosticsFor( 3104 R"( 3105 #include "unchecked_optional_access_test.h" 3106 3107 void target() { 3108 $ns::$optional<int> opt = $ns::nullopt; 3109 while (Make<bool>()) 3110 opt = $ns::$optional<int>(3); 3111 $ns::$optional<int> opt2 = $ns::nullopt; 3112 if (!opt.has_value()) 3113 opt2 = $ns::$optional<int>(3); 3114 opt2.value(); // [[unsafe]] 3115 } 3116 )"); 3117 } 3118 3119 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnknownUnsafe) { 3120 ExpectDiagnosticsFor( 3121 R"( 3122 #include "unchecked_optional_access_test.h" 3123 3124 void target() { 3125 $ns::$optional<int> opt = $ns::nullopt; 3126 while (Make<bool>()) 3127 opt = Make<$ns::$optional<int>>(); 3128 $ns::$optional<int> opt2 = $ns::nullopt; 3129 if (!opt.has_value()) 3130 opt2 = $ns::$optional<int>(3); 3131 opt2.value(); // [[unsafe]] 3132 } 3133 )"); 3134 } 3135 3136 TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopBadConditionUnsafe) { 3137 ExpectDiagnosticsFor( 3138 R"( 3139 #include "unchecked_optional_access_test.h" 3140 3141 void target() { 3142 $ns::$optional<int> opt = 3; 3143 while (Make<bool>()) { 3144 opt.value(); // [[unsafe]] 3145 3146 opt = Make<$ns::$optional<int>>(); 3147 if (!opt.has_value()) continue; 3148 } 3149 } 3150 )"); 3151 } 3152 3153 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromStruct) { 3154 ExpectDiagnosticsFor(R"( 3155 #include "unchecked_optional_access_test.h" 3156 3157 struct kv { $ns::$optional<int> opt; int x; }; 3158 int target() { 3159 auto [contents, x] = Make<kv>(); 3160 return contents ? *contents : x; 3161 } 3162 )"); 3163 3164 ExpectDiagnosticsFor(R"( 3165 #include "unchecked_optional_access_test.h" 3166 3167 template <typename T1, typename T2> 3168 struct pair { T1 fst; T2 snd; }; 3169 int target() { 3170 auto [contents, x] = Make<pair<$ns::$optional<int>, int>>(); 3171 return contents ? *contents : x; 3172 } 3173 )"); 3174 } 3175 3176 TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromTupleLikeType) { 3177 ExpectDiagnosticsFor(R"( 3178 #include "unchecked_optional_access_test.h" 3179 3180 namespace std { 3181 template <class> struct tuple_size; 3182 template <size_t, class> struct tuple_element; 3183 template <class...> class tuple; 3184 3185 template <class... T> 3186 struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {}; 3187 3188 template <size_t I, class... T> 3189 struct tuple_element<I, tuple<T...>> { 3190 using type = __type_pack_element<I, T...>; 3191 }; 3192 3193 template <class...> class tuple {}; 3194 template <size_t I, class... T> 3195 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 3196 } // namespace std 3197 3198 std::tuple<$ns::$optional<const char *>, int> get_opt(); 3199 void target() { 3200 auto [content, ck] = get_opt(); 3201 content ? *content : ""; 3202 } 3203 )"); 3204 } 3205 3206 TEST_P(UncheckedOptionalAccessTest, CtorInitializerNullopt) { 3207 using namespace ast_matchers; 3208 ExpectDiagnosticsFor( 3209 R"( 3210 #include "unchecked_optional_access_test.h" 3211 3212 struct Target { 3213 Target(): opt($ns::nullopt) { 3214 opt.value(); // [[unsafe]] 3215 } 3216 $ns::$optional<int> opt; 3217 }; 3218 )", 3219 cxxConstructorDecl(ofClass(hasName("Target")))); 3220 } 3221 3222 TEST_P(UncheckedOptionalAccessTest, CtorInitializerValue) { 3223 using namespace ast_matchers; 3224 ExpectDiagnosticsFor( 3225 R"( 3226 #include "unchecked_optional_access_test.h" 3227 3228 struct Target { 3229 Target(): opt(3) { 3230 opt.value(); 3231 } 3232 $ns::$optional<int> opt; 3233 }; 3234 )", 3235 cxxConstructorDecl(ofClass(hasName("Target")))); 3236 } 3237 3238 // This is regression test, it shouldn't crash. 3239 TEST_P(UncheckedOptionalAccessTest, Bitfield) { 3240 using namespace ast_matchers; 3241 ExpectDiagnosticsFor( 3242 R"( 3243 #include "unchecked_optional_access_test.h" 3244 struct Dst { 3245 unsigned int n : 1; 3246 }; 3247 void target() { 3248 $ns::$optional<bool> v; 3249 Dst d; 3250 if (v.has_value()) 3251 d.n = v.value(); 3252 } 3253 )"); 3254 } 3255 3256 TEST_P(UncheckedOptionalAccessTest, LambdaParam) { 3257 ExpectDiagnosticsForLambda(R"( 3258 #include "unchecked_optional_access_test.h" 3259 3260 void target() { 3261 []($ns::$optional<int> opt) { 3262 if (opt.has_value()) { 3263 opt.value(); 3264 } else { 3265 opt.value(); // [[unsafe]] 3266 } 3267 }(Make<$ns::$optional<int>>()); 3268 } 3269 )"); 3270 } 3271 3272 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopy) { 3273 ExpectDiagnosticsForLambda(R"( 3274 #include "unchecked_optional_access_test.h" 3275 3276 void target($ns::$optional<int> opt) { 3277 [opt]() { 3278 if (opt.has_value()) { 3279 opt.value(); 3280 } else { 3281 opt.value(); // [[unsafe]] 3282 } 3283 }(); 3284 } 3285 )"); 3286 } 3287 3288 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReference) { 3289 ExpectDiagnosticsForLambda(R"( 3290 #include "unchecked_optional_access_test.h" 3291 3292 void target($ns::$optional<int> opt) { 3293 [&opt]() { 3294 if (opt.has_value()) { 3295 opt.value(); 3296 } else { 3297 opt.value(); // [[unsafe]] 3298 } 3299 }(); 3300 } 3301 )"); 3302 } 3303 3304 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureWithInitializer) { 3305 ExpectDiagnosticsForLambda(R"( 3306 #include "unchecked_optional_access_test.h" 3307 3308 void target($ns::$optional<int> opt) { 3309 [opt2=opt]() { 3310 if (opt2.has_value()) { 3311 opt2.value(); 3312 } else { 3313 opt2.value(); // [[unsafe]] 3314 } 3315 }(); 3316 } 3317 )"); 3318 } 3319 3320 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopyImplicit) { 3321 ExpectDiagnosticsForLambda(R"( 3322 #include "unchecked_optional_access_test.h" 3323 3324 void target($ns::$optional<int> opt) { 3325 [=]() { 3326 if (opt.has_value()) { 3327 opt.value(); 3328 } else { 3329 opt.value(); // [[unsafe]] 3330 } 3331 }(); 3332 } 3333 )"); 3334 } 3335 3336 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReferenceImplicit) { 3337 ExpectDiagnosticsForLambda(R"( 3338 #include "unchecked_optional_access_test.h" 3339 3340 void target($ns::$optional<int> opt) { 3341 [&]() { 3342 if (opt.has_value()) { 3343 opt.value(); 3344 } else { 3345 opt.value(); // [[unsafe]] 3346 } 3347 }(); 3348 } 3349 )"); 3350 } 3351 3352 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureThis) { 3353 ExpectDiagnosticsForLambda(R"( 3354 #include "unchecked_optional_access_test.h" 3355 3356 struct Foo { 3357 $ns::$optional<int> opt; 3358 3359 void target() { 3360 [this]() { 3361 if (opt.has_value()) { 3362 opt.value(); 3363 } else { 3364 opt.value(); // [[unsafe]] 3365 } 3366 }(); 3367 } 3368 }; 3369 )"); 3370 } 3371 3372 TEST_P(UncheckedOptionalAccessTest, LambdaCaptureStateNotPropagated) { 3373 // We can't propagate information from the surrounding context. 3374 ExpectDiagnosticsForLambda(R"( 3375 #include "unchecked_optional_access_test.h" 3376 3377 void target($ns::$optional<int> opt) { 3378 if (opt.has_value()) { 3379 [&opt]() { 3380 opt.value(); // [[unsafe]] 3381 }(); 3382 } 3383 } 3384 )"); 3385 } 3386 3387 TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptional) { 3388 ExpectDiagnosticsFor(R"( 3389 #include "unchecked_optional_access_test.h" 3390 3391 struct Derived : public $ns::$optional<int> {}; 3392 3393 void target(Derived opt) { 3394 *opt; // [[unsafe]] 3395 if (opt.has_value()) 3396 *opt; 3397 3398 // The same thing, but with a pointer receiver. 3399 Derived *popt = &opt; 3400 **popt; // [[unsafe]] 3401 if (popt->has_value()) 3402 **popt; 3403 } 3404 )"); 3405 } 3406 3407 TEST_P(UncheckedOptionalAccessTest, ClassTemplateDerivedFromOptional) { 3408 ExpectDiagnosticsFor(R"( 3409 #include "unchecked_optional_access_test.h" 3410 3411 template <class T> 3412 struct Derived : public $ns::$optional<T> {}; 3413 3414 void target(Derived<int> opt) { 3415 *opt; // [[unsafe]] 3416 if (opt.has_value()) 3417 *opt; 3418 3419 // The same thing, but with a pointer receiver. 3420 Derived<int> *popt = &opt; 3421 **popt; // [[unsafe]] 3422 if (popt->has_value()) 3423 **popt; 3424 } 3425 )"); 3426 } 3427 3428 TEST_P(UncheckedOptionalAccessTest, ClassDerivedPrivatelyFromOptional) { 3429 // Classes that derive privately from optional can themselves still call 3430 // member functions of optional. Check that we model the optional correctly 3431 // in this situation. 3432 ExpectDiagnosticsFor(R"( 3433 #include "unchecked_optional_access_test.h" 3434 3435 struct Derived : private $ns::$optional<int> { 3436 void Method() { 3437 **this; // [[unsafe]] 3438 if (this->has_value()) 3439 **this; 3440 } 3441 }; 3442 )", 3443 ast_matchers::hasName("Method")); 3444 } 3445 3446 // FIXME: Add support for: 3447 // - constructors (copy, move) 3448 // - assignment operators (default, copy, move) 3449 // - invalidation (passing optional by non-const reference/pointer) 3450