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/Analysis/FlowSensitive/SourceLocationsLattice.h" 15 #include "clang/Tooling/Tooling.h" 16 #include "llvm/ADT/ArrayRef.h" 17 #include "llvm/ADT/StringExtras.h" 18 #include "llvm/Support/Error.h" 19 #include "gmock/gmock.h" 20 #include "gtest/gtest.h" 21 #include <string> 22 #include <utility> 23 #include <vector> 24 25 using namespace clang; 26 using namespace dataflow; 27 using namespace test; 28 29 using ::testing::Pair; 30 using ::testing::UnorderedElementsAre; 31 32 // FIXME: Move header definitions in separate file(s). 33 static constexpr char CSDtdDefHeader[] = R"( 34 #ifndef CSTDDEF_H 35 #define CSTDDEF_H 36 37 namespace std { 38 39 typedef decltype(sizeof(char)) size_t; 40 41 using nullptr_t = decltype(nullptr); 42 43 } // namespace std 44 45 #endif // CSTDDEF_H 46 )"; 47 48 static constexpr char StdTypeTraitsHeader[] = R"( 49 #ifndef STD_TYPE_TRAITS_H 50 #define STD_TYPE_TRAITS_H 51 52 #include "cstddef.h" 53 54 namespace std { 55 56 template <typename T, T V> 57 struct integral_constant { 58 static constexpr T value = V; 59 }; 60 61 using true_type = integral_constant<bool, true>; 62 using false_type = integral_constant<bool, false>; 63 64 template< class T > struct remove_reference {typedef T type;}; 65 template< class T > struct remove_reference<T&> {typedef T type;}; 66 template< class T > struct remove_reference<T&&> {typedef T type;}; 67 68 template <class T> 69 using remove_reference_t = typename remove_reference<T>::type; 70 71 template <class T> 72 struct remove_extent { 73 typedef T type; 74 }; 75 76 template <class T> 77 struct remove_extent<T[]> { 78 typedef T type; 79 }; 80 81 template <class T, size_t N> 82 struct remove_extent<T[N]> { 83 typedef T type; 84 }; 85 86 template <class T> 87 struct is_array : false_type {}; 88 89 template <class T> 90 struct is_array<T[]> : true_type {}; 91 92 template <class T, size_t N> 93 struct is_array<T[N]> : true_type {}; 94 95 template <class> 96 struct is_function : false_type {}; 97 98 template <class Ret, class... Args> 99 struct is_function<Ret(Args...)> : true_type {}; 100 101 namespace detail { 102 103 template <class T> 104 struct type_identity { 105 using type = T; 106 }; // or use type_identity (since C++20) 107 108 template <class T> 109 auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>; 110 template <class T> 111 auto try_add_pointer(...) -> type_identity<T>; 112 113 } // namespace detail 114 115 template <class T> 116 struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {}; 117 118 template <bool B, class T, class F> 119 struct conditional { 120 typedef T type; 121 }; 122 123 template <class T, class F> 124 struct conditional<false, T, F> { 125 typedef F type; 126 }; 127 128 template <class T> 129 struct remove_cv { 130 typedef T type; 131 }; 132 template <class T> 133 struct remove_cv<const T> { 134 typedef T type; 135 }; 136 template <class T> 137 struct remove_cv<volatile T> { 138 typedef T type; 139 }; 140 template <class T> 141 struct remove_cv<const volatile T> { 142 typedef T type; 143 }; 144 145 template <class T> 146 using remove_cv_t = typename remove_cv<T>::type; 147 148 template <class T> 149 struct decay { 150 private: 151 typedef typename remove_reference<T>::type U; 152 153 public: 154 typedef typename conditional< 155 is_array<U>::value, typename remove_extent<U>::type*, 156 typename conditional<is_function<U>::value, typename add_pointer<U>::type, 157 typename remove_cv<U>::type>::type>::type type; 158 }; 159 160 template <bool B, class T = void> 161 struct enable_if {}; 162 163 template <class T> 164 struct enable_if<true, T> { 165 typedef T type; 166 }; 167 168 template <bool B, class T = void> 169 using enable_if_t = typename enable_if<B, T>::type; 170 171 template <class T, class U> 172 struct is_same : false_type {}; 173 174 template <class T> 175 struct is_same<T, T> : true_type {}; 176 177 template <class T> 178 struct is_void : is_same<void, typename remove_cv<T>::type> {}; 179 180 namespace detail { 181 182 template <class T> 183 auto try_add_rvalue_reference(int) -> type_identity<T&&>; 184 template <class T> 185 auto try_add_rvalue_reference(...) -> type_identity<T>; 186 187 } // namespace detail 188 189 template <class T> 190 struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) { 191 }; 192 193 template <class T> 194 typename add_rvalue_reference<T>::type declval() noexcept; 195 196 namespace detail { 197 198 template <class T> 199 auto test_returnable(int) 200 -> decltype(void(static_cast<T (*)()>(nullptr)), true_type{}); 201 template <class> 202 auto test_returnable(...) -> false_type; 203 204 template <class From, class To> 205 auto test_implicitly_convertible(int) 206 -> decltype(void(declval<void (&)(To)>()(declval<From>())), true_type{}); 207 template <class, class> 208 auto test_implicitly_convertible(...) -> false_type; 209 210 } // namespace detail 211 212 template <class From, class To> 213 struct is_convertible 214 : integral_constant<bool, 215 (decltype(detail::test_returnable<To>(0))::value && 216 decltype(detail::test_implicitly_convertible<From, To>( 217 0))::value) || 218 (is_void<From>::value && is_void<To>::value)> {}; 219 220 template <class From, class To> 221 inline constexpr bool is_convertible_v = is_convertible<From, To>::value; 222 223 template <class...> 224 using void_t = void; 225 226 template <class, class T, class... Args> 227 struct is_constructible_ : false_type {}; 228 229 template <class T, class... Args> 230 struct is_constructible_<void_t<decltype(T(declval<Args>()...))>, T, Args...> 231 : true_type {}; 232 233 template <class T, class... Args> 234 using is_constructible = is_constructible_<void_t<>, T, Args...>; 235 236 template <class T, class... Args> 237 inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value; 238 239 template <class _Tp> 240 struct __uncvref { 241 typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type; 242 }; 243 244 template <class _Tp> 245 using __uncvref_t = typename __uncvref<_Tp>::type; 246 247 template <bool _Val> 248 using _BoolConstant = integral_constant<bool, _Val>; 249 250 template <class _Tp, class _Up> 251 using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>; 252 253 template <class _Tp, class _Up> 254 using _IsNotSame = _BoolConstant<!__is_same(_Tp, _Up)>; 255 256 template <bool> 257 struct _MetaBase; 258 template <> 259 struct _MetaBase<true> { 260 template <class _Tp, class _Up> 261 using _SelectImpl = _Tp; 262 template <template <class...> class _FirstFn, template <class...> class, 263 class... _Args> 264 using _SelectApplyImpl = _FirstFn<_Args...>; 265 template <class _First, class...> 266 using _FirstImpl = _First; 267 template <class, class _Second, class...> 268 using _SecondImpl = _Second; 269 template <class _Result, class _First, class... _Rest> 270 using _OrImpl = 271 typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>:: 272 template _OrImpl<_First, _Rest...>; 273 }; 274 275 template <> 276 struct _MetaBase<false> { 277 template <class _Tp, class _Up> 278 using _SelectImpl = _Up; 279 template <template <class...> class, template <class...> class _SecondFn, 280 class... _Args> 281 using _SelectApplyImpl = _SecondFn<_Args...>; 282 template <class _Result, class...> 283 using _OrImpl = _Result; 284 }; 285 286 template <bool _Cond, class _IfRes, class _ElseRes> 287 using _If = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>; 288 289 template <class... _Rest> 290 using _Or = typename _MetaBase<sizeof...(_Rest) != 291 0>::template _OrImpl<false_type, _Rest...>; 292 293 template <bool _Bp, class _Tp = void> 294 using __enable_if_t = typename enable_if<_Bp, _Tp>::type; 295 296 template <class...> 297 using __expand_to_true = true_type; 298 template <class... _Pred> 299 __expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int); 300 template <class...> 301 false_type __and_helper(...); 302 template <class... _Pred> 303 using _And = decltype(__and_helper<_Pred...>(0)); 304 305 template <class _Pred> 306 struct _Not : _BoolConstant<!_Pred::value> {}; 307 308 struct __check_tuple_constructor_fail { 309 static constexpr bool __enable_explicit_default() { return false; } 310 static constexpr bool __enable_implicit_default() { return false; } 311 template <class...> 312 static constexpr bool __enable_explicit() { 313 return false; 314 } 315 template <class...> 316 static constexpr bool __enable_implicit() { 317 return false; 318 } 319 }; 320 321 template <typename, typename _Tp> 322 struct __select_2nd { 323 typedef _Tp type; 324 }; 325 template <class _Tp, class _Arg> 326 typename __select_2nd<decltype((declval<_Tp>() = declval<_Arg>())), 327 true_type>::type 328 __is_assignable_test(int); 329 template <class, class> 330 false_type __is_assignable_test(...); 331 template <class _Tp, class _Arg, 332 bool = is_void<_Tp>::value || is_void<_Arg>::value> 333 struct __is_assignable_imp 334 : public decltype((__is_assignable_test<_Tp, _Arg>(0))) {}; 335 template <class _Tp, class _Arg> 336 struct __is_assignable_imp<_Tp, _Arg, true> : public false_type {}; 337 template <class _Tp, class _Arg> 338 struct is_assignable : public __is_assignable_imp<_Tp, _Arg> {}; 339 340 template <class _Tp> 341 struct __libcpp_is_integral : public false_type {}; 342 template <> 343 struct __libcpp_is_integral<bool> : public true_type {}; 344 template <> 345 struct __libcpp_is_integral<char> : public true_type {}; 346 template <> 347 struct __libcpp_is_integral<signed char> : public true_type {}; 348 template <> 349 struct __libcpp_is_integral<unsigned char> : public true_type {}; 350 template <> 351 struct __libcpp_is_integral<wchar_t> : public true_type {}; 352 template <> 353 struct __libcpp_is_integral<short> : public true_type {}; // NOLINT 354 template <> 355 struct __libcpp_is_integral<unsigned short> : public true_type {}; // NOLINT 356 template <> 357 struct __libcpp_is_integral<int> : public true_type {}; 358 template <> 359 struct __libcpp_is_integral<unsigned int> : public true_type {}; 360 template <> 361 struct __libcpp_is_integral<long> : public true_type {}; // NOLINT 362 template <> 363 struct __libcpp_is_integral<unsigned long> : public true_type {}; // NOLINT 364 template <> 365 struct __libcpp_is_integral<long long> : public true_type {}; // NOLINT 366 template <> // NOLINTNEXTLINE 367 struct __libcpp_is_integral<unsigned long long> : public true_type {}; 368 template <class _Tp> 369 struct is_integral 370 : public __libcpp_is_integral<typename remove_cv<_Tp>::type> {}; 371 372 template <class _Tp> 373 struct __libcpp_is_floating_point : public false_type {}; 374 template <> 375 struct __libcpp_is_floating_point<float> : public true_type {}; 376 template <> 377 struct __libcpp_is_floating_point<double> : public true_type {}; 378 template <> 379 struct __libcpp_is_floating_point<long double> : public true_type {}; 380 template <class _Tp> 381 struct is_floating_point 382 : public __libcpp_is_floating_point<typename remove_cv<_Tp>::type> {}; 383 384 template <class _Tp> 385 struct is_arithmetic 386 : public integral_constant<bool, is_integral<_Tp>::value || 387 is_floating_point<_Tp>::value> {}; 388 389 template <class _Tp> 390 struct __libcpp_is_pointer : public false_type {}; 391 template <class _Tp> 392 struct __libcpp_is_pointer<_Tp*> : public true_type {}; 393 template <class _Tp> 394 struct is_pointer : public __libcpp_is_pointer<typename remove_cv<_Tp>::type> { 395 }; 396 397 template <class _Tp> 398 struct __libcpp_is_member_pointer : public false_type {}; 399 template <class _Tp, class _Up> 400 struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type {}; 401 template <class _Tp> 402 struct is_member_pointer 403 : public __libcpp_is_member_pointer<typename remove_cv<_Tp>::type> {}; 404 405 template <class _Tp> 406 struct __libcpp_union : public false_type {}; 407 template <class _Tp> 408 struct is_union : public __libcpp_union<typename remove_cv<_Tp>::type> {}; 409 410 template <class T> 411 struct is_reference : false_type {}; 412 template <class T> 413 struct is_reference<T&> : true_type {}; 414 template <class T> 415 struct is_reference<T&&> : true_type {}; 416 417 template <class T> 418 inline constexpr bool is_reference_v = is_reference<T>::value; 419 420 struct __two { 421 char __lx[2]; 422 }; 423 424 namespace __is_class_imp { 425 template <class _Tp> 426 char __test(int _Tp::*); 427 template <class _Tp> 428 __two __test(...); 429 } // namespace __is_class_imp 430 template <class _Tp> 431 struct is_class 432 : public integral_constant<bool, 433 sizeof(__is_class_imp::__test<_Tp>(0)) == 1 && 434 !is_union<_Tp>::value> {}; 435 436 template <class _Tp> 437 struct __is_nullptr_t_impl : public false_type {}; 438 template <> 439 struct __is_nullptr_t_impl<nullptr_t> : public true_type {}; 440 template <class _Tp> 441 struct __is_nullptr_t 442 : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {}; 443 template <class _Tp> 444 struct is_null_pointer 445 : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {}; 446 447 template <class _Tp> 448 struct is_enum 449 : public integral_constant< 450 bool, !is_void<_Tp>::value && !is_integral<_Tp>::value && 451 !is_floating_point<_Tp>::value && !is_array<_Tp>::value && 452 !is_pointer<_Tp>::value && !is_reference<_Tp>::value && 453 !is_member_pointer<_Tp>::value && !is_union<_Tp>::value && 454 !is_class<_Tp>::value && !is_function<_Tp>::value> {}; 455 456 template <class _Tp> 457 struct is_scalar 458 : public integral_constant< 459 bool, is_arithmetic<_Tp>::value || is_member_pointer<_Tp>::value || 460 is_pointer<_Tp>::value || __is_nullptr_t<_Tp>::value || 461 is_enum<_Tp>::value> {}; 462 template <> 463 struct is_scalar<nullptr_t> : public true_type {}; 464 465 } // namespace std 466 467 #endif // STD_TYPE_TRAITS_H 468 )"; 469 470 static constexpr char AbslTypeTraitsHeader[] = R"( 471 #ifndef ABSL_TYPE_TRAITS_H 472 #define ABSL_TYPE_TRAITS_H 473 474 #include "std_type_traits.h" 475 476 namespace absl { 477 478 template <typename... Ts> 479 struct conjunction : std::true_type {}; 480 481 template <typename T, typename... Ts> 482 struct conjunction<T, Ts...> 483 : std::conditional<T::value, conjunction<Ts...>, T>::type {}; 484 485 template <typename T> 486 struct conjunction<T> : T {}; 487 488 template <typename T> 489 struct negation : std::integral_constant<bool, !T::value> {}; 490 491 template <bool B, typename T = void> 492 using enable_if_t = typename std::enable_if<B, T>::type; 493 494 } // namespace absl 495 496 #endif // ABSL_TYPE_TRAITS_H 497 )"; 498 499 static constexpr char StdUtilityHeader[] = R"( 500 #ifndef UTILITY_H 501 #define UTILITY_H 502 503 #include "std_type_traits.h" 504 505 namespace std { 506 507 template <typename T> 508 constexpr remove_reference_t<T>&& move(T&& x); 509 510 template <typename T> 511 void swap(T& a, T& b) noexcept; 512 513 } // namespace std 514 515 #endif // UTILITY_H 516 )"; 517 518 static constexpr char StdInitializerListHeader[] = R"( 519 #ifndef INITIALIZER_LIST_H 520 #define INITIALIZER_LIST_H 521 522 namespace std { 523 524 template <typename T> 525 class initializer_list { 526 public: 527 initializer_list() noexcept; 528 }; 529 530 } // namespace std 531 532 #endif // INITIALIZER_LIST_H 533 )"; 534 535 static constexpr char StdOptionalHeader[] = R"( 536 #include "std_initializer_list.h" 537 #include "std_type_traits.h" 538 #include "std_utility.h" 539 540 namespace std { 541 542 struct in_place_t {}; 543 constexpr in_place_t in_place; 544 545 struct nullopt_t { 546 constexpr explicit nullopt_t() {} 547 }; 548 constexpr nullopt_t nullopt; 549 550 template <class _Tp> 551 struct __optional_destruct_base { 552 constexpr void reset() noexcept; 553 }; 554 555 template <class _Tp> 556 struct __optional_storage_base : __optional_destruct_base<_Tp> { 557 constexpr bool has_value() const noexcept; 558 }; 559 560 template <typename _Tp> 561 class optional : private __optional_storage_base<_Tp> { 562 using __base = __optional_storage_base<_Tp>; 563 564 public: 565 using value_type = _Tp; 566 567 private: 568 struct _CheckOptionalArgsConstructor { 569 template <class _Up> 570 static constexpr bool __enable_implicit() { 571 return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>; 572 } 573 574 template <class _Up> 575 static constexpr bool __enable_explicit() { 576 return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>; 577 } 578 }; 579 template <class _Up> 580 using _CheckOptionalArgsCtor = 581 _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value && 582 _IsNotSame<__uncvref_t<_Up>, optional>::value, 583 _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>; 584 template <class _QualUp> 585 struct _CheckOptionalLikeConstructor { 586 template <class _Up, class _Opt = optional<_Up>> 587 using __check_constructible_from_opt = 588 _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>, 589 is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>, 590 is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>, 591 is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>; 592 template <class _Up, class _QUp = _QualUp> 593 static constexpr bool __enable_implicit() { 594 return is_convertible<_QUp, _Tp>::value && 595 !__check_constructible_from_opt<_Up>::value; 596 } 597 template <class _Up, class _QUp = _QualUp> 598 static constexpr bool __enable_explicit() { 599 return !is_convertible<_QUp, _Tp>::value && 600 !__check_constructible_from_opt<_Up>::value; 601 } 602 }; 603 604 template <class _Up, class _QualUp> 605 using _CheckOptionalLikeCtor = 606 _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value, 607 _CheckOptionalLikeConstructor<_QualUp>, 608 __check_tuple_constructor_fail>; 609 610 611 template <class _Up, class _QualUp> 612 using _CheckOptionalLikeAssign = _If< 613 _And< 614 _IsNotSame<_Up, _Tp>, 615 is_constructible<_Tp, _QualUp>, 616 is_assignable<_Tp&, _QualUp> 617 >::value, 618 _CheckOptionalLikeConstructor<_QualUp>, 619 __check_tuple_constructor_fail 620 >; 621 622 public: 623 constexpr optional() noexcept {} 624 constexpr optional(const optional&) = default; 625 constexpr optional(optional&&) = default; 626 constexpr optional(nullopt_t) noexcept {} 627 628 template < 629 class _InPlaceT, class... _Args, 630 class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>, 631 is_constructible<value_type, _Args...>>::value>> 632 constexpr explicit optional(_InPlaceT, _Args&&... __args); 633 634 template <class _Up, class... _Args, 635 class = enable_if_t<is_constructible_v< 636 value_type, initializer_list<_Up>&, _Args...>>> 637 constexpr explicit optional(in_place_t, initializer_list<_Up> __il, 638 _Args&&... __args); 639 640 template < 641 class _Up = value_type, 642 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), 643 int> = 0> 644 constexpr optional(_Up&& __v); 645 646 template < 647 class _Up, 648 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), 649 int> = 0> 650 constexpr explicit optional(_Up&& __v); 651 652 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>:: 653 template __enable_implicit<_Up>(), 654 int> = 0> 655 constexpr optional(const optional<_Up>& __v); 656 657 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>:: 658 template __enable_explicit<_Up>(), 659 int> = 0> 660 constexpr explicit optional(const optional<_Up>& __v); 661 662 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>:: 663 template __enable_implicit<_Up>(), 664 int> = 0> 665 constexpr optional(optional<_Up>&& __v); 666 667 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>:: 668 template __enable_explicit<_Up>(), 669 int> = 0> 670 constexpr explicit optional(optional<_Up>&& __v); 671 672 constexpr optional& operator=(nullopt_t) noexcept; 673 674 optional& operator=(const optional&); 675 676 optional& operator=(optional&&); 677 678 template <class _Up = value_type, 679 class = enable_if_t<_And<_IsNotSame<__uncvref_t<_Up>, optional>, 680 _Or<_IsNotSame<__uncvref_t<_Up>, value_type>, 681 _Not<is_scalar<value_type>>>, 682 is_constructible<value_type, _Up>, 683 is_assignable<value_type&, _Up>>::value>> 684 constexpr optional& operator=(_Up&& __v); 685 686 template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>:: 687 template __enable_assign<_Up>(), 688 int> = 0> 689 constexpr optional& operator=(const optional<_Up>& __v); 690 691 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>:: 692 template __enable_assign<_Up>(), 693 int> = 0> 694 constexpr optional& operator=(optional<_Up>&& __v); 695 696 const _Tp& operator*() const&; 697 _Tp& operator*() &; 698 const _Tp&& operator*() const&&; 699 _Tp&& operator*() &&; 700 701 const _Tp* operator->() const; 702 _Tp* operator->(); 703 704 const _Tp& value() const&; 705 _Tp& value() &; 706 const _Tp&& value() const&&; 707 _Tp&& value() &&; 708 709 template <typename U> 710 constexpr _Tp value_or(U&& v) const&; 711 template <typename U> 712 _Tp value_or(U&& v) &&; 713 714 template <typename... Args> 715 _Tp& emplace(Args&&... args); 716 717 template <typename U, typename... Args> 718 _Tp& emplace(std::initializer_list<U> ilist, Args&&... args); 719 720 using __base::reset; 721 722 constexpr explicit operator bool() const noexcept; 723 using __base::has_value; 724 725 constexpr void swap(optional& __opt) noexcept; 726 }; 727 728 template <typename T> 729 constexpr optional<typename std::decay<T>::type> make_optional(T&& v); 730 731 template <typename T, typename... Args> 732 constexpr optional<T> make_optional(Args&&... args); 733 734 template <typename T, typename U, typename... Args> 735 constexpr optional<T> make_optional(std::initializer_list<U> il, 736 Args&&... args); 737 738 } // namespace std 739 )"; 740 741 static constexpr char AbslOptionalHeader[] = R"( 742 #include "absl_type_traits.h" 743 #include "std_initializer_list.h" 744 #include "std_type_traits.h" 745 #include "std_utility.h" 746 747 namespace absl { 748 749 struct nullopt_t { 750 constexpr explicit nullopt_t() {} 751 }; 752 constexpr nullopt_t nullopt; 753 754 struct in_place_t {}; 755 constexpr in_place_t in_place; 756 757 template <typename T> 758 class optional; 759 760 namespace optional_internal { 761 762 template <typename T, typename U> 763 struct is_constructible_convertible_from_optional 764 : std::integral_constant< 765 bool, std::is_constructible<T, optional<U>&>::value || 766 std::is_constructible<T, optional<U>&&>::value || 767 std::is_constructible<T, const optional<U>&>::value || 768 std::is_constructible<T, const optional<U>&&>::value || 769 std::is_convertible<optional<U>&, T>::value || 770 std::is_convertible<optional<U>&&, T>::value || 771 std::is_convertible<const optional<U>&, T>::value || 772 std::is_convertible<const optional<U>&&, T>::value> {}; 773 774 template <typename T, typename U> 775 struct is_constructible_convertible_assignable_from_optional 776 : std::integral_constant< 777 bool, is_constructible_convertible_from_optional<T, U>::value || 778 std::is_assignable<T&, optional<U>&>::value || 779 std::is_assignable<T&, optional<U>&&>::value || 780 std::is_assignable<T&, const optional<U>&>::value || 781 std::is_assignable<T&, const optional<U>&&>::value> {}; 782 783 } // namespace optional_internal 784 785 template <typename T> 786 class optional { 787 public: 788 constexpr optional() noexcept; 789 790 constexpr optional(nullopt_t) noexcept; 791 792 optional(const optional&) = default; 793 794 optional(optional&&) = default; 795 796 template <typename InPlaceT, typename... Args, 797 absl::enable_if_t<absl::conjunction< 798 std::is_same<InPlaceT, in_place_t>, 799 std::is_constructible<T, Args&&...>>::value>* = nullptr> 800 constexpr explicit optional(InPlaceT, Args&&... args); 801 802 template <typename U, typename... Args, 803 typename = typename std::enable_if<std::is_constructible< 804 T, std::initializer_list<U>&, Args&&...>::value>::type> 805 constexpr explicit optional(in_place_t, std::initializer_list<U> il, 806 Args&&... args); 807 808 template < 809 typename U = T, 810 typename std::enable_if< 811 absl::conjunction<absl::negation<std::is_same< 812 in_place_t, typename std::decay<U>::type>>, 813 absl::negation<std::is_same< 814 optional<T>, typename std::decay<U>::type>>, 815 std::is_convertible<U&&, T>, 816 std::is_constructible<T, U&&>>::value, 817 bool>::type = false> 818 constexpr optional(U&& v); 819 820 template < 821 typename U = T, 822 typename std::enable_if< 823 absl::conjunction<absl::negation<std::is_same< 824 in_place_t, typename std::decay<U>::type>>, 825 absl::negation<std::is_same< 826 optional<T>, typename std::decay<U>::type>>, 827 absl::negation<std::is_convertible<U&&, T>>, 828 std::is_constructible<T, U&&>>::value, 829 bool>::type = false> 830 explicit constexpr optional(U&& v); 831 832 template <typename U, 833 typename std::enable_if< 834 absl::conjunction< 835 absl::negation<std::is_same<T, U>>, 836 std::is_constructible<T, const U&>, 837 absl::negation< 838 optional_internal:: 839 is_constructible_convertible_from_optional<T, U>>, 840 std::is_convertible<const U&, T>>::value, 841 bool>::type = false> 842 optional(const optional<U>& rhs); 843 844 template <typename U, 845 typename std::enable_if< 846 absl::conjunction< 847 absl::negation<std::is_same<T, U>>, 848 std::is_constructible<T, const U&>, 849 absl::negation< 850 optional_internal:: 851 is_constructible_convertible_from_optional<T, U>>, 852 absl::negation<std::is_convertible<const U&, T>>>::value, 853 bool>::type = false> 854 explicit optional(const optional<U>& rhs); 855 856 template < 857 typename U, 858 typename std::enable_if< 859 absl::conjunction< 860 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, 861 absl::negation< 862 optional_internal::is_constructible_convertible_from_optional< 863 T, U>>, 864 std::is_convertible<U&&, T>>::value, 865 bool>::type = false> 866 optional(optional<U>&& rhs); 867 868 template < 869 typename U, 870 typename std::enable_if< 871 absl::conjunction< 872 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, 873 absl::negation< 874 optional_internal::is_constructible_convertible_from_optional< 875 T, U>>, 876 absl::negation<std::is_convertible<U&&, T>>>::value, 877 bool>::type = false> 878 explicit optional(optional<U>&& rhs); 879 880 optional& operator=(nullopt_t) noexcept; 881 882 optional& operator=(const optional& src); 883 884 optional& operator=(optional&& src); 885 886 template < 887 typename U = T, 888 typename = typename std::enable_if<absl::conjunction< 889 absl::negation< 890 std::is_same<optional<T>, typename std::decay<U>::type>>, 891 absl::negation< 892 absl::conjunction<std::is_scalar<T>, 893 std::is_same<T, typename std::decay<U>::type>>>, 894 std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type> 895 optional& operator=(U&& v); 896 897 template < 898 typename U, 899 typename = typename std::enable_if<absl::conjunction< 900 absl::negation<std::is_same<T, U>>, 901 std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>, 902 absl::negation< 903 optional_internal:: 904 is_constructible_convertible_assignable_from_optional< 905 T, U>>>::value>::type> 906 optional& operator=(const optional<U>& rhs); 907 908 template <typename U, 909 typename = typename std::enable_if<absl::conjunction< 910 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>, 911 std::is_assignable<T&, U>, 912 absl::negation< 913 optional_internal:: 914 is_constructible_convertible_assignable_from_optional< 915 T, U>>>::value>::type> 916 optional& operator=(optional<U>&& rhs); 917 918 const T& operator*() const&; 919 T& operator*() &; 920 const T&& operator*() const&&; 921 T&& operator*() &&; 922 923 const T* operator->() const; 924 T* operator->(); 925 926 const T& value() const&; 927 T& value() &; 928 const T&& value() const&&; 929 T&& value() &&; 930 931 template <typename U> 932 constexpr T value_or(U&& v) const&; 933 template <typename U> 934 T value_or(U&& v) &&; 935 936 template <typename... Args> 937 T& emplace(Args&&... args); 938 939 template <typename U, typename... Args> 940 T& emplace(std::initializer_list<U> ilist, Args&&... args); 941 942 void reset() noexcept; 943 944 constexpr explicit operator bool() const noexcept; 945 constexpr bool has_value() const noexcept; 946 947 void swap(optional& rhs) noexcept; 948 }; 949 950 template <typename T> 951 constexpr optional<typename std::decay<T>::type> make_optional(T&& v); 952 953 template <typename T, typename... Args> 954 constexpr optional<T> make_optional(Args&&... args); 955 956 template <typename T, typename U, typename... Args> 957 constexpr optional<T> make_optional(std::initializer_list<U> il, 958 Args&&... args); 959 960 } // namespace absl 961 )"; 962 963 static constexpr char BaseOptionalHeader[] = R"( 964 #include "std_initializer_list.h" 965 #include "std_type_traits.h" 966 #include "std_utility.h" 967 968 namespace base { 969 970 struct in_place_t {}; 971 constexpr in_place_t in_place; 972 973 struct nullopt_t { 974 constexpr explicit nullopt_t() {} 975 }; 976 constexpr nullopt_t nullopt; 977 978 template <typename T> 979 class Optional; 980 981 namespace internal { 982 983 template <typename T> 984 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>; 985 986 template <typename T, typename U> 987 struct IsConvertibleFromOptional 988 : std::integral_constant< 989 bool, std::is_constructible<T, Optional<U>&>::value || 990 std::is_constructible<T, const Optional<U>&>::value || 991 std::is_constructible<T, Optional<U>&&>::value || 992 std::is_constructible<T, const Optional<U>&&>::value || 993 std::is_convertible<Optional<U>&, T>::value || 994 std::is_convertible<const Optional<U>&, T>::value || 995 std::is_convertible<Optional<U>&&, T>::value || 996 std::is_convertible<const Optional<U>&&, T>::value> {}; 997 998 template <typename T, typename U> 999 struct IsAssignableFromOptional 1000 : std::integral_constant< 1001 bool, IsConvertibleFromOptional<T, U>::value || 1002 std::is_assignable<T&, Optional<U>&>::value || 1003 std::is_assignable<T&, const Optional<U>&>::value || 1004 std::is_assignable<T&, Optional<U>&&>::value || 1005 std::is_assignable<T&, const Optional<U>&&>::value> {}; 1006 1007 } // namespace internal 1008 1009 template <typename T> 1010 class Optional { 1011 public: 1012 using value_type = T; 1013 1014 constexpr Optional() = default; 1015 constexpr Optional(const Optional& other) noexcept = default; 1016 constexpr Optional(Optional&& other) noexcept = default; 1017 1018 constexpr Optional(nullopt_t); 1019 1020 template <typename U, 1021 typename std::enable_if< 1022 std::is_constructible<T, const U&>::value && 1023 !internal::IsConvertibleFromOptional<T, U>::value && 1024 std::is_convertible<const U&, T>::value, 1025 bool>::type = false> 1026 Optional(const Optional<U>& other) noexcept; 1027 1028 template <typename U, 1029 typename std::enable_if< 1030 std::is_constructible<T, const U&>::value && 1031 !internal::IsConvertibleFromOptional<T, U>::value && 1032 !std::is_convertible<const U&, T>::value, 1033 bool>::type = false> 1034 explicit Optional(const Optional<U>& other) noexcept; 1035 1036 template <typename U, 1037 typename std::enable_if< 1038 std::is_constructible<T, U&&>::value && 1039 !internal::IsConvertibleFromOptional<T, U>::value && 1040 std::is_convertible<U&&, T>::value, 1041 bool>::type = false> 1042 Optional(Optional<U>&& other) noexcept; 1043 1044 template <typename U, 1045 typename std::enable_if< 1046 std::is_constructible<T, U&&>::value && 1047 !internal::IsConvertibleFromOptional<T, U>::value && 1048 !std::is_convertible<U&&, T>::value, 1049 bool>::type = false> 1050 explicit Optional(Optional<U>&& other) noexcept; 1051 1052 template <class... Args> 1053 constexpr explicit Optional(in_place_t, Args&&... args); 1054 1055 template <class U, class... Args, 1056 class = typename std::enable_if<std::is_constructible< 1057 value_type, std::initializer_list<U>&, Args...>::value>::type> 1058 constexpr explicit Optional(in_place_t, std::initializer_list<U> il, 1059 Args&&... args); 1060 1061 template < 1062 typename U = value_type, 1063 typename std::enable_if< 1064 std::is_constructible<T, U&&>::value && 1065 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value && 1066 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value && 1067 std::is_convertible<U&&, T>::value, 1068 bool>::type = false> 1069 constexpr Optional(U&& value); 1070 1071 template < 1072 typename U = value_type, 1073 typename std::enable_if< 1074 std::is_constructible<T, U&&>::value && 1075 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value && 1076 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value && 1077 !std::is_convertible<U&&, T>::value, 1078 bool>::type = false> 1079 constexpr explicit Optional(U&& value); 1080 1081 Optional& operator=(const Optional& other) noexcept; 1082 1083 Optional& operator=(Optional&& other) noexcept; 1084 1085 Optional& operator=(nullopt_t); 1086 1087 template <typename U> 1088 typename std::enable_if< 1089 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value && 1090 std::is_constructible<T, U>::value && 1091 std::is_assignable<T&, U>::value && 1092 (!std::is_scalar<T>::value || 1093 !std::is_same<typename std::decay<U>::type, T>::value), 1094 Optional&>::type 1095 operator=(U&& value) noexcept; 1096 1097 template <typename U> 1098 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value && 1099 std::is_constructible<T, const U&>::value && 1100 std::is_assignable<T&, const U&>::value, 1101 Optional&>::type 1102 operator=(const Optional<U>& other) noexcept; 1103 1104 template <typename U> 1105 typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value && 1106 std::is_constructible<T, U>::value && 1107 std::is_assignable<T&, U>::value, 1108 Optional&>::type 1109 operator=(Optional<U>&& other) noexcept; 1110 1111 const T& operator*() const&; 1112 T& operator*() &; 1113 const T&& operator*() const&&; 1114 T&& operator*() &&; 1115 1116 const T* operator->() const; 1117 T* operator->(); 1118 1119 const T& value() const&; 1120 T& value() &; 1121 const T&& value() const&&; 1122 T&& value() &&; 1123 1124 template <typename U> 1125 constexpr T value_or(U&& v) const&; 1126 template <typename U> 1127 T value_or(U&& v) &&; 1128 1129 template <typename... Args> 1130 T& emplace(Args&&... args); 1131 1132 template <typename U, typename... Args> 1133 T& emplace(std::initializer_list<U> ilist, Args&&... args); 1134 1135 void reset() noexcept; 1136 1137 constexpr explicit operator bool() const noexcept; 1138 constexpr bool has_value() const noexcept; 1139 1140 void swap(Optional& other); 1141 }; 1142 1143 template <typename T> 1144 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v); 1145 1146 template <typename T, typename... Args> 1147 constexpr Optional<T> make_optional(Args&&... args); 1148 1149 template <typename T, typename U, typename... Args> 1150 constexpr Optional<T> make_optional(std::initializer_list<U> il, 1151 Args&&... args); 1152 1153 } // namespace base 1154 )"; 1155 1156 /// Converts `L` to string. 1157 static std::string ConvertToString(const SourceLocationsLattice &L, 1158 const ASTContext &Ctx) { 1159 return L.getSourceLocations().empty() ? "safe" 1160 : "unsafe: " + DebugString(L, Ctx); 1161 } 1162 1163 /// Replaces all occurrences of `Pattern` in `S` with `Replacement`. 1164 static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern, 1165 const std::string &Replacement) { 1166 size_t Pos = 0; 1167 while (true) { 1168 Pos = S.find(Pattern, Pos); 1169 if (Pos == std::string::npos) 1170 break; 1171 S.replace(Pos, Pattern.size(), Replacement); 1172 } 1173 } 1174 1175 struct OptionalTypeIdentifier { 1176 std::string NamespaceName; 1177 std::string TypeName; 1178 }; 1179 1180 class UncheckedOptionalAccessTest 1181 : public ::testing::TestWithParam<OptionalTypeIdentifier> { 1182 protected: 1183 template <typename LatticeChecksMatcher> 1184 void ExpectLatticeChecksFor(std::string SourceCode, 1185 LatticeChecksMatcher MatchesLatticeChecks) { 1186 ExpectLatticeChecksFor(SourceCode, ast_matchers::hasName("target"), 1187 MatchesLatticeChecks); 1188 } 1189 1190 private: 1191 template <typename FuncDeclMatcher, typename LatticeChecksMatcher> 1192 void ExpectLatticeChecksFor(std::string SourceCode, 1193 FuncDeclMatcher FuncMatcher, 1194 LatticeChecksMatcher MatchesLatticeChecks) { 1195 ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName); 1196 ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName); 1197 1198 std::vector<std::pair<std::string, std::string>> Headers; 1199 Headers.emplace_back("cstddef.h", CSDtdDefHeader); 1200 Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader); 1201 Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader); 1202 Headers.emplace_back("std_utility.h", StdUtilityHeader); 1203 Headers.emplace_back("std_optional.h", StdOptionalHeader); 1204 Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader); 1205 Headers.emplace_back("absl_optional.h", AbslOptionalHeader); 1206 Headers.emplace_back("base_optional.h", BaseOptionalHeader); 1207 Headers.emplace_back("unchecked_optional_access_test.h", R"( 1208 #include "absl_optional.h" 1209 #include "base_optional.h" 1210 #include "std_initializer_list.h" 1211 #include "std_optional.h" 1212 #include "std_utility.h" 1213 1214 template <typename T> 1215 T Make(); 1216 )"); 1217 const tooling::FileContentMappings FileContents(Headers.begin(), 1218 Headers.end()); 1219 llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>( 1220 SourceCode, FuncMatcher, 1221 [](ASTContext &Ctx, Environment &) { 1222 return UncheckedOptionalAccessModel(Ctx); 1223 }, 1224 [&MatchesLatticeChecks]( 1225 llvm::ArrayRef<std::pair< 1226 std::string, DataflowAnalysisState<SourceLocationsLattice>>> 1227 CheckToLatticeMap, 1228 ASTContext &Ctx) { 1229 // FIXME: Consider using a matcher instead of translating 1230 // `CheckToLatticeMap` to `CheckToStringifiedLatticeMap`. 1231 std::vector<std::pair<std::string, std::string>> 1232 CheckToStringifiedLatticeMap; 1233 for (const auto &E : CheckToLatticeMap) { 1234 CheckToStringifiedLatticeMap.emplace_back( 1235 E.first, ConvertToString(E.second.Lattice, Ctx)); 1236 } 1237 EXPECT_THAT(CheckToStringifiedLatticeMap, MatchesLatticeChecks); 1238 }, 1239 {"-fsyntax-only", "-std=c++17", "-Wno-undefined-inline"}, FileContents); 1240 if (Error) 1241 FAIL() << llvm::toString(std::move(Error)); 1242 } 1243 }; 1244 1245 INSTANTIATE_TEST_SUITE_P( 1246 UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest, 1247 ::testing::Values(OptionalTypeIdentifier{"std", "optional"}, 1248 OptionalTypeIdentifier{"absl", "optional"}, 1249 OptionalTypeIdentifier{"base", "Optional"}), 1250 [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) { 1251 return Info.param.NamespaceName; 1252 }); 1253 1254 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) { 1255 ExpectLatticeChecksFor(R"( 1256 void target() { 1257 (void)0; 1258 /*[[check]]*/ 1259 } 1260 )", 1261 UnorderedElementsAre(Pair("check", "safe"))); 1262 } 1263 1264 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) { 1265 ExpectLatticeChecksFor( 1266 R"( 1267 #include "unchecked_optional_access_test.h" 1268 1269 void target($ns::$optional<int> opt) { 1270 opt.value(); 1271 /*[[check]]*/ 1272 } 1273 )", 1274 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7"))); 1275 1276 ExpectLatticeChecksFor( 1277 R"( 1278 #include "unchecked_optional_access_test.h" 1279 1280 void target($ns::$optional<int> opt) { 1281 std::move(opt).value(); 1282 /*[[check]]*/ 1283 } 1284 )", 1285 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7"))); 1286 } 1287 1288 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) { 1289 ExpectLatticeChecksFor( 1290 R"( 1291 #include "unchecked_optional_access_test.h" 1292 1293 void target($ns::$optional<int> opt) { 1294 *opt; 1295 /*[[check]]*/ 1296 } 1297 )", 1298 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8"))); 1299 1300 ExpectLatticeChecksFor( 1301 R"( 1302 #include "unchecked_optional_access_test.h" 1303 1304 void target($ns::$optional<int> opt) { 1305 *std::move(opt); 1306 /*[[check]]*/ 1307 } 1308 )", 1309 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8"))); 1310 } 1311 1312 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) { 1313 ExpectLatticeChecksFor( 1314 R"( 1315 #include "unchecked_optional_access_test.h" 1316 1317 struct Foo { 1318 void foo(); 1319 }; 1320 1321 void target($ns::$optional<Foo> opt) { 1322 opt->foo(); 1323 /*[[check]]*/ 1324 } 1325 )", 1326 UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7"))); 1327 1328 ExpectLatticeChecksFor( 1329 R"( 1330 #include "unchecked_optional_access_test.h" 1331 1332 struct Foo { 1333 void foo(); 1334 }; 1335 1336 void target($ns::$optional<Foo> opt) { 1337 std::move(opt)->foo(); 1338 /*[[check]]*/ 1339 } 1340 )", 1341 UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7"))); 1342 } 1343 1344 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) { 1345 ExpectLatticeChecksFor(R"( 1346 #include "unchecked_optional_access_test.h" 1347 1348 void target($ns::$optional<int> opt) { 1349 if (opt.has_value()) { 1350 opt.value(); 1351 /*[[check]]*/ 1352 } 1353 } 1354 )", 1355 UnorderedElementsAre(Pair("check", "safe"))); 1356 } 1357 1358 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) { 1359 ExpectLatticeChecksFor(R"( 1360 #include "unchecked_optional_access_test.h" 1361 1362 void target($ns::$optional<int> opt) { 1363 if (opt) { 1364 opt.value(); 1365 /*[[check]]*/ 1366 } 1367 } 1368 )", 1369 UnorderedElementsAre(Pair("check", "safe"))); 1370 } 1371 1372 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) { 1373 ExpectLatticeChecksFor( 1374 R"( 1375 #include "unchecked_optional_access_test.h" 1376 1377 void target() { 1378 Make<$ns::$optional<int>>().value(); 1379 (void)0; 1380 /*[[check]]*/ 1381 } 1382 )", 1383 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7"))); 1384 1385 ExpectLatticeChecksFor( 1386 R"( 1387 #include "unchecked_optional_access_test.h" 1388 1389 void target($ns::$optional<int> opt) { 1390 std::move(opt).value(); 1391 /*[[check]]*/ 1392 } 1393 )", 1394 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7"))); 1395 } 1396 1397 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) { 1398 ExpectLatticeChecksFor( 1399 R"( 1400 #include "unchecked_optional_access_test.h" 1401 1402 void target() { 1403 $ns::$optional<int> opt; 1404 opt.value(); 1405 /*[[check]]*/ 1406 } 1407 )", 1408 UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7"))); 1409 } 1410 1411 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) { 1412 ExpectLatticeChecksFor( 1413 R"( 1414 #include "unchecked_optional_access_test.h" 1415 1416 void target() { 1417 $ns::$optional<int> opt($ns::nullopt); 1418 opt.value(); 1419 /*[[check]]*/ 1420 } 1421 )", 1422 UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7"))); 1423 } 1424 1425 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) { 1426 ExpectLatticeChecksFor(R"( 1427 #include "unchecked_optional_access_test.h" 1428 1429 void target() { 1430 $ns::$optional<int> opt($ns::in_place, 3); 1431 opt.value(); 1432 /*[[check]]*/ 1433 } 1434 )", 1435 UnorderedElementsAre(Pair("check", "safe"))); 1436 1437 ExpectLatticeChecksFor(R"( 1438 #include "unchecked_optional_access_test.h" 1439 1440 struct Foo {}; 1441 1442 void target() { 1443 $ns::$optional<Foo> opt($ns::in_place); 1444 opt.value(); 1445 /*[[check]]*/ 1446 } 1447 )", 1448 UnorderedElementsAre(Pair("check", "safe"))); 1449 1450 ExpectLatticeChecksFor(R"( 1451 #include "unchecked_optional_access_test.h" 1452 1453 struct Foo { 1454 explicit Foo(int, bool); 1455 }; 1456 1457 void target() { 1458 $ns::$optional<Foo> opt($ns::in_place, 3, false); 1459 opt.value(); 1460 /*[[check]]*/ 1461 } 1462 )", 1463 UnorderedElementsAre(Pair("check", "safe"))); 1464 1465 ExpectLatticeChecksFor(R"( 1466 #include "unchecked_optional_access_test.h" 1467 1468 struct Foo { 1469 explicit Foo(std::initializer_list<int>); 1470 }; 1471 1472 void target() { 1473 $ns::$optional<Foo> opt($ns::in_place, {3}); 1474 opt.value(); 1475 /*[[check]]*/ 1476 } 1477 )", 1478 UnorderedElementsAre(Pair("check", "safe"))); 1479 } 1480 1481 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) { 1482 ExpectLatticeChecksFor(R"( 1483 #include "unchecked_optional_access_test.h" 1484 1485 void target() { 1486 $ns::$optional<int> opt(21); 1487 opt.value(); 1488 /*[[check]]*/ 1489 } 1490 )", 1491 UnorderedElementsAre(Pair("check", "safe"))); 1492 1493 ExpectLatticeChecksFor(R"( 1494 #include "unchecked_optional_access_test.h" 1495 1496 void target() { 1497 $ns::$optional<int> opt = $ns::$optional<int>(21); 1498 opt.value(); 1499 /*[[check]]*/ 1500 } 1501 )", 1502 UnorderedElementsAre(Pair("check", "safe"))); 1503 ExpectLatticeChecksFor(R"( 1504 #include "unchecked_optional_access_test.h" 1505 1506 void target() { 1507 $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>()); 1508 opt.value(); 1509 /*[[check]]*/ 1510 } 1511 )", 1512 UnorderedElementsAre(Pair("check", "safe"))); 1513 1514 ExpectLatticeChecksFor(R"( 1515 #include "unchecked_optional_access_test.h" 1516 1517 struct MyString { 1518 MyString(const char*); 1519 }; 1520 1521 void target() { 1522 $ns::$optional<MyString> opt("foo"); 1523 opt.value(); 1524 /*[[check]]*/ 1525 } 1526 )", 1527 UnorderedElementsAre(Pair("check", "safe"))); 1528 1529 ExpectLatticeChecksFor(R"( 1530 #include "unchecked_optional_access_test.h" 1531 1532 struct Foo {}; 1533 1534 struct Bar { 1535 Bar(const Foo&); 1536 }; 1537 1538 void target() { 1539 $ns::$optional<Bar> opt(Make<Foo>()); 1540 opt.value(); 1541 /*[[check]]*/ 1542 } 1543 )", 1544 UnorderedElementsAre(Pair("check", "safe"))); 1545 1546 ExpectLatticeChecksFor(R"( 1547 #include "unchecked_optional_access_test.h" 1548 1549 struct Foo { 1550 explicit Foo(int); 1551 }; 1552 1553 void target() { 1554 $ns::$optional<Foo> opt(3); 1555 opt.value(); 1556 /*[[check]]*/ 1557 } 1558 )", 1559 UnorderedElementsAre(Pair("check", "safe"))); 1560 } 1561 1562 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) { 1563 ExpectLatticeChecksFor( 1564 R"( 1565 #include "unchecked_optional_access_test.h" 1566 1567 struct Foo {}; 1568 1569 struct Bar { 1570 Bar(const Foo&); 1571 }; 1572 1573 void target() { 1574 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>()); 1575 opt.value(); 1576 /*[[check]]*/ 1577 } 1578 )", 1579 UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7"))); 1580 1581 ExpectLatticeChecksFor( 1582 R"( 1583 #include "unchecked_optional_access_test.h" 1584 1585 struct Foo {}; 1586 1587 struct Bar { 1588 explicit Bar(const Foo&); 1589 }; 1590 1591 void target() { 1592 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>()); 1593 opt.value(); 1594 /*[[check]]*/ 1595 } 1596 )", 1597 UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7"))); 1598 1599 ExpectLatticeChecksFor( 1600 R"( 1601 #include "unchecked_optional_access_test.h" 1602 1603 struct Foo {}; 1604 1605 struct Bar { 1606 Bar(const Foo&); 1607 }; 1608 1609 void target() { 1610 $ns::$optional<Foo> opt1 = $ns::nullopt; 1611 $ns::$optional<Bar> opt2(opt1); 1612 opt2.value(); 1613 /*[[check]]*/ 1614 } 1615 )", 1616 UnorderedElementsAre(Pair("check", "unsafe: input.cc:13:7"))); 1617 1618 ExpectLatticeChecksFor(R"( 1619 #include "unchecked_optional_access_test.h" 1620 1621 struct Foo {}; 1622 1623 struct Bar { 1624 Bar(const Foo&); 1625 }; 1626 1627 void target() { 1628 $ns::$optional<Foo> opt1(Make<Foo>()); 1629 $ns::$optional<Bar> opt2(opt1); 1630 opt2.value(); 1631 /*[[check]]*/ 1632 } 1633 )", 1634 UnorderedElementsAre(Pair("check", "safe"))); 1635 1636 ExpectLatticeChecksFor(R"( 1637 #include "unchecked_optional_access_test.h" 1638 1639 struct Foo {}; 1640 1641 struct Bar { 1642 explicit Bar(const Foo&); 1643 }; 1644 1645 void target() { 1646 $ns::$optional<Foo> opt1(Make<Foo>()); 1647 $ns::$optional<Bar> opt2(opt1); 1648 opt2.value(); 1649 /*[[check]]*/ 1650 } 1651 )", 1652 UnorderedElementsAre(Pair("check", "safe"))); 1653 } 1654 1655 TEST_P(UncheckedOptionalAccessTest, MakeOptional) { 1656 ExpectLatticeChecksFor(R"( 1657 #include "unchecked_optional_access_test.h" 1658 1659 void target() { 1660 $ns::$optional<int> opt = $ns::make_optional(0); 1661 opt.value(); 1662 /*[[check]]*/ 1663 } 1664 )", 1665 UnorderedElementsAre(Pair("check", "safe"))); 1666 1667 ExpectLatticeChecksFor(R"( 1668 #include "unchecked_optional_access_test.h" 1669 1670 struct Foo { 1671 Foo(int, int); 1672 }; 1673 1674 void target() { 1675 $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22); 1676 opt.value(); 1677 /*[[check]]*/ 1678 } 1679 )", 1680 UnorderedElementsAre(Pair("check", "safe"))); 1681 1682 ExpectLatticeChecksFor(R"( 1683 #include "unchecked_optional_access_test.h" 1684 1685 struct Foo { 1686 constexpr Foo(std::initializer_list<char>); 1687 }; 1688 1689 void target() { 1690 char a = 'a'; 1691 $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a}); 1692 opt.value(); 1693 /*[[check]]*/ 1694 } 1695 )", 1696 UnorderedElementsAre(Pair("check", "safe"))); 1697 } 1698 1699 TEST_P(UncheckedOptionalAccessTest, ValueOr) { 1700 ExpectLatticeChecksFor(R"( 1701 #include "unchecked_optional_access_test.h" 1702 1703 void target() { 1704 $ns::$optional<int> opt; 1705 opt.value_or(0); 1706 (void)0; 1707 /*[[check]]*/ 1708 } 1709 )", 1710 UnorderedElementsAre(Pair("check", "safe"))); 1711 } 1712 1713 TEST_P(UncheckedOptionalAccessTest, Emplace) { 1714 ExpectLatticeChecksFor(R"( 1715 #include "unchecked_optional_access_test.h" 1716 1717 void target() { 1718 $ns::$optional<int> opt; 1719 opt.emplace(0); 1720 opt.value(); 1721 /*[[check]]*/ 1722 } 1723 )", 1724 UnorderedElementsAre(Pair("check", "safe"))); 1725 1726 ExpectLatticeChecksFor(R"( 1727 #include "unchecked_optional_access_test.h" 1728 1729 void target($ns::$optional<int> *opt) { 1730 opt->emplace(0); 1731 opt->value(); 1732 /*[[check]]*/ 1733 } 1734 )", 1735 UnorderedElementsAre(Pair("check", "safe"))); 1736 1737 // FIXME: Add tests that call `emplace` in conditional branches. 1738 } 1739 1740 TEST_P(UncheckedOptionalAccessTest, Reset) { 1741 ExpectLatticeChecksFor( 1742 R"( 1743 #include "unchecked_optional_access_test.h" 1744 1745 void target() { 1746 $ns::$optional<int> opt = $ns::make_optional(0); 1747 opt.reset(); 1748 opt.value(); 1749 /*[[check]]*/ 1750 } 1751 )", 1752 UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7"))); 1753 1754 ExpectLatticeChecksFor( 1755 R"( 1756 #include "unchecked_optional_access_test.h" 1757 1758 void target($ns::$optional<int> &opt) { 1759 if (opt.has_value()) { 1760 opt.reset(); 1761 opt.value(); 1762 /*[[check]]*/ 1763 } 1764 } 1765 )", 1766 UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:9"))); 1767 1768 // FIXME: Add tests that call `reset` in conditional branches. 1769 } 1770 1771 TEST_P(UncheckedOptionalAccessTest, ValueAssignment) { 1772 ExpectLatticeChecksFor(R"( 1773 #include "unchecked_optional_access_test.h" 1774 1775 struct Foo {}; 1776 1777 void target() { 1778 $ns::$optional<Foo> opt; 1779 opt = Foo(); 1780 opt.value(); 1781 /*[[check]]*/ 1782 } 1783 )", 1784 UnorderedElementsAre(Pair("check", "safe"))); 1785 1786 ExpectLatticeChecksFor(R"( 1787 #include "unchecked_optional_access_test.h" 1788 1789 struct Foo {}; 1790 1791 void target() { 1792 $ns::$optional<Foo> opt; 1793 (opt = Foo()).value(); 1794 (void)0; 1795 /*[[check]]*/ 1796 } 1797 )", 1798 UnorderedElementsAre(Pair("check", "safe"))); 1799 1800 ExpectLatticeChecksFor(R"( 1801 #include "unchecked_optional_access_test.h" 1802 1803 struct MyString { 1804 MyString(const char*); 1805 }; 1806 1807 void target() { 1808 $ns::$optional<MyString> opt; 1809 opt = "foo"; 1810 opt.value(); 1811 /*[[check]]*/ 1812 } 1813 )", 1814 UnorderedElementsAre(Pair("check", "safe"))); 1815 1816 ExpectLatticeChecksFor(R"( 1817 #include "unchecked_optional_access_test.h" 1818 1819 struct MyString { 1820 MyString(const char*); 1821 }; 1822 1823 void target() { 1824 $ns::$optional<MyString> opt; 1825 (opt = "foo").value(); 1826 /*[[check]]*/ 1827 } 1828 )", 1829 UnorderedElementsAre(Pair("check", "safe"))); 1830 } 1831 1832 TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) { 1833 ExpectLatticeChecksFor( 1834 R"( 1835 #include "unchecked_optional_access_test.h" 1836 1837 struct Foo {}; 1838 1839 struct Bar { 1840 Bar(const Foo&); 1841 }; 1842 1843 void target() { 1844 $ns::$optional<Foo> opt1 = Foo(); 1845 $ns::$optional<Bar> opt2; 1846 opt2 = opt1; 1847 opt2.value(); 1848 /*[[check]]*/ 1849 } 1850 )", 1851 UnorderedElementsAre(Pair("check", "safe"))); 1852 1853 ExpectLatticeChecksFor( 1854 R"( 1855 #include "unchecked_optional_access_test.h" 1856 1857 struct Foo {}; 1858 1859 struct Bar { 1860 Bar(const Foo&); 1861 }; 1862 1863 void target() { 1864 $ns::$optional<Foo> opt1; 1865 $ns::$optional<Bar> opt2; 1866 if (opt2.has_value()) { 1867 opt2 = opt1; 1868 opt2.value(); 1869 /*[[check]]*/ 1870 } 1871 } 1872 )", 1873 UnorderedElementsAre(Pair("check", "unsafe: input.cc:15:9"))); 1874 1875 ExpectLatticeChecksFor( 1876 R"( 1877 #include "unchecked_optional_access_test.h" 1878 1879 struct Foo {}; 1880 1881 struct Bar { 1882 Bar(const Foo&); 1883 }; 1884 1885 void target() { 1886 $ns::$optional<Foo> opt1 = Foo(); 1887 $ns::$optional<Bar> opt2; 1888 (opt2 = opt1).value(); 1889 (void)0; 1890 /*[[check]]*/ 1891 } 1892 )", 1893 UnorderedElementsAre(Pair("check", "safe"))); 1894 } 1895 1896 TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) { 1897 ExpectLatticeChecksFor( 1898 R"( 1899 #include "unchecked_optional_access_test.h" 1900 1901 void target() { 1902 $ns::$optional<int> opt = 3; 1903 opt = $ns::nullopt; 1904 opt.value(); 1905 /*[[check]]*/ 1906 } 1907 )", 1908 UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7"))); 1909 1910 ExpectLatticeChecksFor( 1911 R"( 1912 #include "unchecked_optional_access_test.h" 1913 1914 void target() { 1915 $ns::$optional<int> opt = 3; 1916 (opt = $ns::nullopt).value(); 1917 /*[[check]]*/ 1918 } 1919 )", 1920 UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7"))); 1921 } 1922 1923 TEST_P(UncheckedOptionalAccessTest, OptionalSwap) { 1924 ExpectLatticeChecksFor( 1925 R"( 1926 #include "unchecked_optional_access_test.h" 1927 1928 void target() { 1929 $ns::$optional<int> opt1 = $ns::nullopt; 1930 $ns::$optional<int> opt2 = 3; 1931 1932 opt1.swap(opt2); 1933 1934 opt1.value(); 1935 /*[[check-1]]*/ 1936 1937 opt2.value(); 1938 /*[[check-2]]*/ 1939 } 1940 )", 1941 UnorderedElementsAre(Pair("check-1", "safe"), 1942 Pair("check-2", "unsafe: input.cc:13:7"))); 1943 1944 ExpectLatticeChecksFor( 1945 R"( 1946 #include "unchecked_optional_access_test.h" 1947 1948 void target() { 1949 $ns::$optional<int> opt1 = $ns::nullopt; 1950 $ns::$optional<int> opt2 = 3; 1951 1952 opt2.swap(opt1); 1953 1954 opt1.value(); 1955 /*[[check-3]]*/ 1956 1957 opt2.value(); 1958 /*[[check-4]]*/ 1959 } 1960 )", 1961 UnorderedElementsAre(Pair("check-3", "safe"), 1962 Pair("check-4", "unsafe: input.cc:13:7"))); 1963 } 1964 1965 TEST_P(UncheckedOptionalAccessTest, StdSwap) { 1966 ExpectLatticeChecksFor( 1967 R"( 1968 #include "unchecked_optional_access_test.h" 1969 1970 void target() { 1971 $ns::$optional<int> opt1 = $ns::nullopt; 1972 $ns::$optional<int> opt2 = 3; 1973 1974 std::swap(opt1, opt2); 1975 1976 opt1.value(); 1977 /*[[check-1]]*/ 1978 1979 opt2.value(); 1980 /*[[check-2]]*/ 1981 } 1982 )", 1983 UnorderedElementsAre(Pair("check-1", "safe"), 1984 Pair("check-2", "unsafe: input.cc:13:7"))); 1985 1986 ExpectLatticeChecksFor( 1987 R"( 1988 #include "unchecked_optional_access_test.h" 1989 1990 void target() { 1991 $ns::$optional<int> opt1 = $ns::nullopt; 1992 $ns::$optional<int> opt2 = 3; 1993 1994 std::swap(opt2, opt1); 1995 1996 opt1.value(); 1997 /*[[check-3]]*/ 1998 1999 opt2.value(); 2000 /*[[check-4]]*/ 2001 } 2002 )", 2003 UnorderedElementsAre(Pair("check-3", "safe"), 2004 Pair("check-4", "unsafe: input.cc:13:7"))); 2005 } 2006 2007 // FIXME: Add support for: 2008 // - constructors (copy, move) 2009 // - assignment operators (default, copy, move) 2010 // - invalidation (passing optional by non-const reference/pointer) 2011 // - `value_or(nullptr) != nullptr`, `value_or(0) != 0`, `value_or("").empty()` 2012 // - nested `optional` values 2013