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