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 StdTypeTraitsHeader[] = R"( 34 #ifndef STD_TYPE_TRAITS_H 35 #define STD_TYPE_TRAITS_H 36 37 namespace std { 38 39 typedef decltype(sizeof(char)) size_t; 40 41 template <typename T, T V> 42 struct integral_constant { 43 static constexpr T value = V; 44 }; 45 46 using true_type = integral_constant<bool, true>; 47 using false_type = integral_constant<bool, false>; 48 49 template< class T > struct remove_reference {typedef T type;}; 50 template< class T > struct remove_reference<T&> {typedef T type;}; 51 template< class T > struct remove_reference<T&&> {typedef T type;}; 52 53 template <class T> 54 using remove_reference_t = typename remove_reference<T>::type; 55 56 template <class T> 57 struct remove_extent { 58 typedef T type; 59 }; 60 61 template <class T> 62 struct remove_extent<T[]> { 63 typedef T type; 64 }; 65 66 template <class T, size_t N> 67 struct remove_extent<T[N]> { 68 typedef T type; 69 }; 70 71 template <class T> 72 struct is_array : false_type {}; 73 74 template <class T> 75 struct is_array<T[]> : true_type {}; 76 77 template <class T, size_t N> 78 struct is_array<T[N]> : true_type {}; 79 80 template <class> 81 struct is_function : false_type {}; 82 83 template <class Ret, class... Args> 84 struct is_function<Ret(Args...)> : true_type {}; 85 86 namespace detail { 87 88 template <class T> 89 struct type_identity { 90 using type = T; 91 }; // or use type_identity (since C++20) 92 93 template <class T> 94 auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>; 95 template <class T> 96 auto try_add_pointer(...) -> type_identity<T>; 97 98 } // namespace detail 99 100 template <class T> 101 struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {}; 102 103 template <bool B, class T, class F> 104 struct conditional { 105 typedef T type; 106 }; 107 108 template <class T, class F> 109 struct conditional<false, T, F> { 110 typedef F type; 111 }; 112 113 template <class T> 114 struct remove_cv { 115 typedef T type; 116 }; 117 template <class T> 118 struct remove_cv<const T> { 119 typedef T type; 120 }; 121 template <class T> 122 struct remove_cv<volatile T> { 123 typedef T type; 124 }; 125 template <class T> 126 struct remove_cv<const volatile T> { 127 typedef T type; 128 }; 129 130 template <class T> 131 using remove_cv_t = typename remove_cv<T>::type; 132 133 template <class T> 134 struct decay { 135 private: 136 typedef typename remove_reference<T>::type U; 137 138 public: 139 typedef typename conditional< 140 is_array<U>::value, typename remove_extent<U>::type*, 141 typename conditional<is_function<U>::value, typename add_pointer<U>::type, 142 typename remove_cv<U>::type>::type>::type type; 143 }; 144 145 template <bool B, class T = void> 146 struct enable_if {}; 147 148 template <class T> 149 struct enable_if<true, T> { 150 typedef T type; 151 }; 152 153 template <bool B, class T = void> 154 using enable_if_t = typename enable_if<B, T>::type; 155 156 template <class T, class U> 157 struct is_same : false_type {}; 158 159 template <class T> 160 struct is_same<T, T> : true_type {}; 161 162 template <class T> 163 struct is_void : is_same<void, typename remove_cv<T>::type> {}; 164 165 namespace detail { 166 167 template <class T> 168 auto try_add_rvalue_reference(int) -> type_identity<T&&>; 169 template <class T> 170 auto try_add_rvalue_reference(...) -> type_identity<T>; 171 172 } // namespace detail 173 174 template <class T> 175 struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) { 176 }; 177 178 template <class T> 179 typename add_rvalue_reference<T>::type declval() noexcept; 180 181 namespace detail { 182 183 template <class T> 184 auto test_returnable(int) 185 -> decltype(void(static_cast<T (*)()>(nullptr)), true_type{}); 186 template <class> 187 auto test_returnable(...) -> false_type; 188 189 template <class From, class To> 190 auto test_implicitly_convertible(int) 191 -> decltype(void(declval<void (&)(To)>()(declval<From>())), true_type{}); 192 template <class, class> 193 auto test_implicitly_convertible(...) -> false_type; 194 195 } // namespace detail 196 197 template <class From, class To> 198 struct is_convertible 199 : integral_constant<bool, 200 (decltype(detail::test_returnable<To>(0))::value && 201 decltype(detail::test_implicitly_convertible<From, To>( 202 0))::value) || 203 (is_void<From>::value && is_void<To>::value)> {}; 204 205 template <class From, class To> 206 inline constexpr bool is_convertible_v = is_convertible<From, To>::value; 207 208 template <class...> 209 using void_t = void; 210 211 template <class, class T, class... Args> 212 struct is_constructible_ : false_type {}; 213 214 template <class T, class... Args> 215 struct is_constructible_<void_t<decltype(T(declval<Args>()...))>, T, Args...> 216 : true_type {}; 217 218 template <class T, class... Args> 219 using is_constructible = is_constructible_<void_t<>, T, Args...>; 220 221 template <class T, class... Args> 222 inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value; 223 224 template <class _Tp> 225 struct __uncvref { 226 typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type; 227 }; 228 229 template <class _Tp> 230 using __uncvref_t = typename __uncvref<_Tp>::type; 231 232 template <bool _Val> 233 using _BoolConstant = integral_constant<bool, _Val>; 234 235 template <class _Tp, class _Up> 236 using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>; 237 238 template <class _Tp, class _Up> 239 using _IsNotSame = _BoolConstant<!__is_same(_Tp, _Up)>; 240 241 template <bool> 242 struct _MetaBase; 243 template <> 244 struct _MetaBase<true> { 245 template <class _Tp, class _Up> 246 using _SelectImpl = _Tp; 247 template <template <class...> class _FirstFn, template <class...> class, 248 class... _Args> 249 using _SelectApplyImpl = _FirstFn<_Args...>; 250 template <class _First, class...> 251 using _FirstImpl = _First; 252 template <class, class _Second, class...> 253 using _SecondImpl = _Second; 254 template <class _Result, class _First, class... _Rest> 255 using _OrImpl = 256 typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>:: 257 template _OrImpl<_First, _Rest...>; 258 }; 259 260 template <> 261 struct _MetaBase<false> { 262 template <class _Tp, class _Up> 263 using _SelectImpl = _Up; 264 template <template <class...> class, template <class...> class _SecondFn, 265 class... _Args> 266 using _SelectApplyImpl = _SecondFn<_Args...>; 267 template <class _Result, class...> 268 using _OrImpl = _Result; 269 }; 270 271 template <bool _Cond, class _IfRes, class _ElseRes> 272 using _If = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>; 273 274 template <class... _Rest> 275 using _Or = typename _MetaBase<sizeof...(_Rest) != 276 0>::template _OrImpl<false_type, _Rest...>; 277 278 template <bool _Bp, class _Tp = void> 279 using __enable_if_t = typename enable_if<_Bp, _Tp>::type; 280 281 template <class...> 282 using __expand_to_true = true_type; 283 template <class... _Pred> 284 __expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int); 285 template <class...> 286 false_type __and_helper(...); 287 template <class... _Pred> 288 using _And = decltype(__and_helper<_Pred...>(0)); 289 290 struct __check_tuple_constructor_fail { 291 static constexpr bool __enable_explicit_default() { return false; } 292 static constexpr bool __enable_implicit_default() { return false; } 293 template <class...> 294 static constexpr bool __enable_explicit() { 295 return false; 296 } 297 template <class...> 298 static constexpr bool __enable_implicit() { 299 return false; 300 } 301 }; 302 303 } // namespace std 304 305 #endif // STD_TYPE_TRAITS_H 306 )"; 307 308 static constexpr char AbslTypeTraitsHeader[] = R"( 309 #ifndef ABSL_TYPE_TRAITS_H 310 #define ABSL_TYPE_TRAITS_H 311 312 #include "std_type_traits.h" 313 314 namespace absl { 315 316 template <typename... Ts> 317 struct conjunction : std::true_type {}; 318 319 template <typename T, typename... Ts> 320 struct conjunction<T, Ts...> 321 : std::conditional<T::value, conjunction<Ts...>, T>::type {}; 322 323 template <typename T> 324 struct conjunction<T> : T {}; 325 326 template <typename T> 327 struct negation : std::integral_constant<bool, !T::value> {}; 328 329 template <bool B, typename T = void> 330 using enable_if_t = typename std::enable_if<B, T>::type; 331 332 } // namespace absl 333 334 #endif // ABSL_TYPE_TRAITS_H 335 )"; 336 337 static constexpr char StdUtilityHeader[] = R"( 338 #ifndef UTILITY_H 339 #define UTILITY_H 340 341 #include "std_type_traits.h" 342 343 namespace std { 344 345 template <typename T> 346 constexpr remove_reference_t<T>&& move(T&& x); 347 348 } // namespace std 349 350 #endif // UTILITY_H 351 )"; 352 353 static constexpr char StdInitializerListHeader[] = R"( 354 #ifndef INITIALIZER_LIST_H 355 #define INITIALIZER_LIST_H 356 357 namespace std { 358 359 template <typename T> 360 class initializer_list { 361 public: 362 initializer_list() noexcept; 363 }; 364 365 } // namespace std 366 367 #endif // INITIALIZER_LIST_H 368 )"; 369 370 static constexpr char StdOptionalHeader[] = R"( 371 #include "std_initializer_list.h" 372 #include "std_type_traits.h" 373 #include "std_utility.h" 374 375 namespace std { 376 377 struct in_place_t {}; 378 constexpr in_place_t in_place; 379 380 struct nullopt_t { 381 constexpr explicit nullopt_t() {} 382 }; 383 constexpr nullopt_t nullopt; 384 385 template <class _Tp> 386 struct __optional_destruct_base { 387 constexpr void reset() noexcept; 388 }; 389 390 template <class _Tp> 391 struct __optional_storage_base : __optional_destruct_base<_Tp> { 392 constexpr bool has_value() const noexcept; 393 }; 394 395 template <typename _Tp> 396 class optional : private __optional_storage_base<_Tp> { 397 using __base = __optional_storage_base<_Tp>; 398 399 public: 400 using value_type = _Tp; 401 402 private: 403 struct _CheckOptionalArgsConstructor { 404 template <class _Up> 405 static constexpr bool __enable_implicit() { 406 return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>; 407 } 408 409 template <class _Up> 410 static constexpr bool __enable_explicit() { 411 return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>; 412 } 413 }; 414 template <class _Up> 415 using _CheckOptionalArgsCtor = 416 _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value && 417 _IsNotSame<__uncvref_t<_Up>, optional>::value, 418 _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>; 419 template <class _QualUp> 420 struct _CheckOptionalLikeConstructor { 421 template <class _Up, class _Opt = optional<_Up>> 422 using __check_constructible_from_opt = 423 _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>, 424 is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>, 425 is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>, 426 is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>; 427 template <class _Up, class _QUp = _QualUp> 428 static constexpr bool __enable_implicit() { 429 return is_convertible<_QUp, _Tp>::value && 430 !__check_constructible_from_opt<_Up>::value; 431 } 432 template <class _Up, class _QUp = _QualUp> 433 static constexpr bool __enable_explicit() { 434 return !is_convertible<_QUp, _Tp>::value && 435 !__check_constructible_from_opt<_Up>::value; 436 } 437 }; 438 439 template <class _Up, class _QualUp> 440 using _CheckOptionalLikeCtor = 441 _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value, 442 _CheckOptionalLikeConstructor<_QualUp>, 443 __check_tuple_constructor_fail>; 444 445 public: 446 constexpr optional() noexcept {} 447 constexpr optional(const optional&) = default; 448 constexpr optional(optional&&) = default; 449 constexpr optional(nullopt_t) noexcept {} 450 451 template < 452 class _InPlaceT, class... _Args, 453 class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>, 454 is_constructible<value_type, _Args...>>::value>> 455 constexpr explicit optional(_InPlaceT, _Args&&... __args); 456 457 template <class _Up, class... _Args, 458 class = enable_if_t<is_constructible_v< 459 value_type, initializer_list<_Up>&, _Args...>>> 460 constexpr explicit optional(in_place_t, initializer_list<_Up> __il, 461 _Args&&... __args); 462 463 template < 464 class _Up = value_type, 465 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), 466 int> = 0> 467 constexpr optional(_Up&& __v); 468 469 template < 470 class _Up, 471 enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), 472 int> = 0> 473 constexpr explicit optional(_Up&& __v); 474 475 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>:: 476 template __enable_implicit<_Up>(), 477 int> = 0> 478 constexpr optional(const optional<_Up>& __v); 479 480 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>:: 481 template __enable_explicit<_Up>(), 482 int> = 0> 483 constexpr explicit optional(const optional<_Up>& __v); 484 485 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>:: 486 template __enable_implicit<_Up>(), 487 int> = 0> 488 constexpr optional(optional<_Up>&& __v); 489 490 template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>:: 491 template __enable_explicit<_Up>(), 492 int> = 0> 493 constexpr explicit optional(optional<_Up>&& __v); 494 495 const _Tp& operator*() const&; 496 _Tp& operator*() &; 497 const _Tp&& operator*() const&&; 498 _Tp&& operator*() &&; 499 500 const _Tp* operator->() const; 501 _Tp* operator->(); 502 503 const _Tp& value() const&; 504 _Tp& value() &; 505 const _Tp&& value() const&&; 506 _Tp&& value() &&; 507 508 template <typename U> 509 constexpr _Tp value_or(U&& v) const&; 510 template <typename U> 511 _Tp value_or(U&& v) &&; 512 513 template <typename... Args> 514 _Tp& emplace(Args&&... args); 515 516 template <typename U, typename... Args> 517 _Tp& emplace(std::initializer_list<U> ilist, Args&&... args); 518 519 using __base::reset; 520 521 constexpr explicit operator bool() const noexcept; 522 using __base::has_value; 523 }; 524 525 template <typename T> 526 constexpr optional<typename std::decay<T>::type> make_optional(T&& v); 527 528 template <typename T, typename... Args> 529 constexpr optional<T> make_optional(Args&&... args); 530 531 template <typename T, typename U, typename... Args> 532 constexpr optional<T> make_optional(std::initializer_list<U> il, 533 Args&&... args); 534 535 } // namespace std 536 )"; 537 538 static constexpr char AbslOptionalHeader[] = R"( 539 #include "absl_type_traits.h" 540 #include "std_initializer_list.h" 541 #include "std_type_traits.h" 542 #include "std_utility.h" 543 544 namespace absl { 545 546 struct nullopt_t { 547 constexpr explicit nullopt_t() {} 548 }; 549 constexpr nullopt_t nullopt; 550 551 struct in_place_t {}; 552 constexpr in_place_t in_place; 553 554 template <typename T> 555 class optional; 556 557 namespace optional_internal { 558 559 // Whether T is constructible or convertible from optional<U>. 560 template <typename T, typename U> 561 struct is_constructible_convertible_from_optional 562 : std::integral_constant< 563 bool, std::is_constructible<T, optional<U>&>::value || 564 std::is_constructible<T, optional<U>&&>::value || 565 std::is_constructible<T, const optional<U>&>::value || 566 std::is_constructible<T, const optional<U>&&>::value || 567 std::is_convertible<optional<U>&, T>::value || 568 std::is_convertible<optional<U>&&, T>::value || 569 std::is_convertible<const optional<U>&, T>::value || 570 std::is_convertible<const optional<U>&&, T>::value> {}; 571 572 } // namespace optional_internal 573 574 template <typename T> 575 class optional { 576 public: 577 constexpr optional() noexcept; 578 579 constexpr optional(nullopt_t) noexcept; 580 581 optional(const optional&) = default; 582 583 optional(optional&&) = default; 584 585 template <typename InPlaceT, typename... Args, 586 absl::enable_if_t<absl::conjunction< 587 std::is_same<InPlaceT, in_place_t>, 588 std::is_constructible<T, Args&&...>>::value>* = nullptr> 589 constexpr explicit optional(InPlaceT, Args&&... args); 590 591 template <typename U, typename... Args, 592 typename = typename std::enable_if<std::is_constructible< 593 T, std::initializer_list<U>&, Args&&...>::value>::type> 594 constexpr explicit optional(in_place_t, std::initializer_list<U> il, 595 Args&&... args); 596 597 template < 598 typename U = T, 599 typename std::enable_if< 600 absl::conjunction<absl::negation<std::is_same< 601 in_place_t, typename std::decay<U>::type>>, 602 absl::negation<std::is_same< 603 optional<T>, typename std::decay<U>::type>>, 604 std::is_convertible<U&&, T>, 605 std::is_constructible<T, U&&>>::value, 606 bool>::type = false> 607 constexpr optional(U&& v); 608 609 template < 610 typename U = T, 611 typename std::enable_if< 612 absl::conjunction<absl::negation<std::is_same< 613 in_place_t, typename std::decay<U>::type>>, 614 absl::negation<std::is_same< 615 optional<T>, typename std::decay<U>::type>>, 616 absl::negation<std::is_convertible<U&&, T>>, 617 std::is_constructible<T, U&&>>::value, 618 bool>::type = false> 619 explicit constexpr optional(U&& v); 620 621 template <typename U, 622 typename std::enable_if< 623 absl::conjunction< 624 absl::negation<std::is_same<T, U>>, 625 std::is_constructible<T, const U&>, 626 absl::negation< 627 optional_internal:: 628 is_constructible_convertible_from_optional<T, U>>, 629 std::is_convertible<const U&, T>>::value, 630 bool>::type = false> 631 optional(const optional<U>& rhs); 632 633 template <typename U, 634 typename std::enable_if< 635 absl::conjunction< 636 absl::negation<std::is_same<T, U>>, 637 std::is_constructible<T, const U&>, 638 absl::negation< 639 optional_internal:: 640 is_constructible_convertible_from_optional<T, U>>, 641 absl::negation<std::is_convertible<const U&, T>>>::value, 642 bool>::type = false> 643 explicit optional(const optional<U>& rhs); 644 645 template < 646 typename U, 647 typename std::enable_if< 648 absl::conjunction< 649 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, 650 absl::negation< 651 optional_internal::is_constructible_convertible_from_optional< 652 T, U>>, 653 std::is_convertible<U&&, T>>::value, 654 bool>::type = false> 655 optional(optional<U>&& rhs); 656 657 template < 658 typename U, 659 typename std::enable_if< 660 absl::conjunction< 661 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, 662 absl::negation< 663 optional_internal::is_constructible_convertible_from_optional< 664 T, U>>, 665 absl::negation<std::is_convertible<U&&, T>>>::value, 666 bool>::type = false> 667 explicit optional(optional<U>&& rhs); 668 669 const T& operator*() const&; 670 T& operator*() &; 671 const T&& operator*() const&&; 672 T&& operator*() &&; 673 674 const T* operator->() const; 675 T* operator->(); 676 677 const T& value() const&; 678 T& value() &; 679 const T&& value() const&&; 680 T&& value() &&; 681 682 template <typename U> 683 constexpr T value_or(U&& v) const&; 684 template <typename U> 685 T value_or(U&& v) &&; 686 687 template <typename... Args> 688 T& emplace(Args&&... args); 689 690 template <typename U, typename... Args> 691 T& emplace(std::initializer_list<U> ilist, Args&&... args); 692 693 void reset() noexcept; 694 695 constexpr explicit operator bool() const noexcept; 696 constexpr bool has_value() const noexcept; 697 }; 698 699 template <typename T> 700 constexpr optional<typename std::decay<T>::type> make_optional(T&& v); 701 702 template <typename T, typename... Args> 703 constexpr optional<T> make_optional(Args&&... args); 704 705 template <typename T, typename U, typename... Args> 706 constexpr optional<T> make_optional(std::initializer_list<U> il, 707 Args&&... args); 708 709 } // namespace absl 710 )"; 711 712 static constexpr char BaseOptionalHeader[] = R"( 713 #include "std_initializer_list.h" 714 #include "std_type_traits.h" 715 #include "std_utility.h" 716 717 namespace base { 718 719 struct in_place_t {}; 720 constexpr in_place_t in_place; 721 722 struct nullopt_t { 723 constexpr explicit nullopt_t() {} 724 }; 725 constexpr nullopt_t nullopt; 726 727 template <typename T> 728 class Optional; 729 730 namespace internal { 731 732 template <typename T> 733 using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>; 734 735 template <typename T, typename U> 736 struct IsConvertibleFromOptional 737 : std::integral_constant< 738 bool, std::is_constructible<T, Optional<U>&>::value || 739 std::is_constructible<T, const Optional<U>&>::value || 740 std::is_constructible<T, Optional<U>&&>::value || 741 std::is_constructible<T, const Optional<U>&&>::value || 742 std::is_convertible<Optional<U>&, T>::value || 743 std::is_convertible<const Optional<U>&, T>::value || 744 std::is_convertible<Optional<U>&&, T>::value || 745 std::is_convertible<const Optional<U>&&, T>::value> {}; 746 747 } // namespace internal 748 749 template <typename T> 750 class Optional { 751 public: 752 using value_type = T; 753 754 constexpr Optional() = default; 755 constexpr Optional(const Optional& other) noexcept = default; 756 constexpr Optional(Optional&& other) noexcept = default; 757 758 constexpr Optional(nullopt_t); 759 760 template <typename U, 761 typename std::enable_if< 762 std::is_constructible<T, const U&>::value && 763 !internal::IsConvertibleFromOptional<T, U>::value && 764 std::is_convertible<const U&, T>::value, 765 bool>::type = false> 766 Optional(const Optional<U>& other) noexcept; 767 768 template <typename U, 769 typename std::enable_if< 770 std::is_constructible<T, const U&>::value && 771 !internal::IsConvertibleFromOptional<T, U>::value && 772 !std::is_convertible<const U&, T>::value, 773 bool>::type = false> 774 explicit Optional(const Optional<U>& other) noexcept; 775 776 template <typename U, 777 typename std::enable_if< 778 std::is_constructible<T, U&&>::value && 779 !internal::IsConvertibleFromOptional<T, U>::value && 780 std::is_convertible<U&&, T>::value, 781 bool>::type = false> 782 Optional(Optional<U>&& other) noexcept; 783 784 template <typename U, 785 typename std::enable_if< 786 std::is_constructible<T, U&&>::value && 787 !internal::IsConvertibleFromOptional<T, U>::value && 788 !std::is_convertible<U&&, T>::value, 789 bool>::type = false> 790 explicit Optional(Optional<U>&& other) noexcept; 791 792 template <class... Args> 793 constexpr explicit Optional(in_place_t, Args&&... args); 794 795 template <class U, class... Args, 796 class = typename std::enable_if<std::is_constructible< 797 value_type, std::initializer_list<U>&, Args...>::value>::type> 798 constexpr explicit Optional(in_place_t, std::initializer_list<U> il, 799 Args&&... args); 800 801 template < 802 typename U = value_type, 803 typename std::enable_if< 804 std::is_constructible<T, U&&>::value && 805 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value && 806 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value && 807 std::is_convertible<U&&, T>::value, 808 bool>::type = false> 809 constexpr Optional(U&& value); 810 811 template < 812 typename U = value_type, 813 typename std::enable_if< 814 std::is_constructible<T, U&&>::value && 815 !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value && 816 !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value && 817 !std::is_convertible<U&&, T>::value, 818 bool>::type = false> 819 constexpr explicit Optional(U&& value); 820 821 const T& operator*() const&; 822 T& operator*() &; 823 const T&& operator*() const&&; 824 T&& operator*() &&; 825 826 const T* operator->() const; 827 T* operator->(); 828 829 const T& value() const&; 830 T& value() &; 831 const T&& value() const&&; 832 T&& value() &&; 833 834 template <typename U> 835 constexpr T value_or(U&& v) const&; 836 template <typename U> 837 T value_or(U&& v) &&; 838 839 template <typename... Args> 840 T& emplace(Args&&... args); 841 842 template <typename U, typename... Args> 843 T& emplace(std::initializer_list<U> ilist, Args&&... args); 844 845 void reset() noexcept; 846 847 constexpr explicit operator bool() const noexcept; 848 constexpr bool has_value() const noexcept; 849 }; 850 851 template <typename T> 852 constexpr Optional<typename std::decay<T>::type> make_optional(T&& v); 853 854 template <typename T, typename... Args> 855 constexpr Optional<T> make_optional(Args&&... args); 856 857 template <typename T, typename U, typename... Args> 858 constexpr Optional<T> make_optional(std::initializer_list<U> il, 859 Args&&... args); 860 861 } // namespace base 862 )"; 863 864 /// Converts `L` to string. 865 static std::string ConvertToString(const SourceLocationsLattice &L, 866 const ASTContext &Ctx) { 867 return L.getSourceLocations().empty() ? "safe" 868 : "unsafe: " + DebugString(L, Ctx); 869 } 870 871 /// Replaces all occurrences of `Pattern` in `S` with `Replacement`. 872 static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern, 873 const std::string &Replacement) { 874 size_t Pos = 0; 875 while (true) { 876 Pos = S.find(Pattern, Pos); 877 if (Pos == std::string::npos) 878 break; 879 S.replace(Pos, Pattern.size(), Replacement); 880 } 881 } 882 883 struct OptionalTypeIdentifier { 884 std::string NamespaceName; 885 std::string TypeName; 886 }; 887 888 class UncheckedOptionalAccessTest 889 : public ::testing::TestWithParam<OptionalTypeIdentifier> { 890 protected: 891 template <typename LatticeChecksMatcher> 892 void ExpectLatticeChecksFor(std::string SourceCode, 893 LatticeChecksMatcher MatchesLatticeChecks) { 894 ExpectLatticeChecksFor(SourceCode, ast_matchers::hasName("target"), 895 MatchesLatticeChecks); 896 } 897 898 private: 899 template <typename FuncDeclMatcher, typename LatticeChecksMatcher> 900 void ExpectLatticeChecksFor(std::string SourceCode, 901 FuncDeclMatcher FuncMatcher, 902 LatticeChecksMatcher MatchesLatticeChecks) { 903 ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName); 904 ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName); 905 906 std::vector<std::pair<std::string, std::string>> Headers; 907 Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader); 908 Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader); 909 Headers.emplace_back("std_utility.h", StdUtilityHeader); 910 Headers.emplace_back("std_optional.h", StdOptionalHeader); 911 Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader); 912 Headers.emplace_back("absl_optional.h", AbslOptionalHeader); 913 Headers.emplace_back("base_optional.h", BaseOptionalHeader); 914 Headers.emplace_back("unchecked_optional_access_test.h", R"( 915 #include "absl_optional.h" 916 #include "base_optional.h" 917 #include "std_initializer_list.h" 918 #include "std_optional.h" 919 #include "std_utility.h" 920 921 template <typename T> 922 T Make(); 923 )"); 924 const tooling::FileContentMappings FileContents(Headers.begin(), 925 Headers.end()); 926 llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>( 927 SourceCode, FuncMatcher, 928 [](ASTContext &Ctx, Environment &) { 929 return UncheckedOptionalAccessModel(Ctx); 930 }, 931 [&MatchesLatticeChecks]( 932 llvm::ArrayRef<std::pair< 933 std::string, DataflowAnalysisState<SourceLocationsLattice>>> 934 CheckToLatticeMap, 935 ASTContext &Ctx) { 936 // FIXME: Consider using a matcher instead of translating 937 // `CheckToLatticeMap` to `CheckToStringifiedLatticeMap`. 938 std::vector<std::pair<std::string, std::string>> 939 CheckToStringifiedLatticeMap; 940 for (const auto &E : CheckToLatticeMap) { 941 CheckToStringifiedLatticeMap.emplace_back( 942 E.first, ConvertToString(E.second.Lattice, Ctx)); 943 } 944 EXPECT_THAT(CheckToStringifiedLatticeMap, MatchesLatticeChecks); 945 }, 946 {"-fsyntax-only", "-std=c++17", "-Wno-undefined-inline"}, FileContents); 947 if (Error) 948 FAIL() << llvm::toString(std::move(Error)); 949 } 950 }; 951 952 INSTANTIATE_TEST_SUITE_P( 953 UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest, 954 ::testing::Values(OptionalTypeIdentifier{"std", "optional"}, 955 OptionalTypeIdentifier{"absl", "optional"}, 956 OptionalTypeIdentifier{"base", "Optional"}), 957 [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) { 958 return Info.param.NamespaceName; 959 }); 960 961 TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) { 962 ExpectLatticeChecksFor(R"( 963 void target() { 964 (void)0; 965 /*[[check]]*/ 966 } 967 )", 968 UnorderedElementsAre(Pair("check", "safe"))); 969 } 970 971 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) { 972 ExpectLatticeChecksFor( 973 R"( 974 #include "unchecked_optional_access_test.h" 975 976 void target($ns::$optional<int> opt) { 977 opt.value(); 978 /*[[check]]*/ 979 } 980 )", 981 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7"))); 982 983 ExpectLatticeChecksFor( 984 R"( 985 #include "unchecked_optional_access_test.h" 986 987 void target($ns::$optional<int> opt) { 988 std::move(opt).value(); 989 /*[[check]]*/ 990 } 991 )", 992 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7"))); 993 } 994 995 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) { 996 ExpectLatticeChecksFor( 997 R"( 998 #include "unchecked_optional_access_test.h" 999 1000 void target($ns::$optional<int> opt) { 1001 *opt; 1002 /*[[check]]*/ 1003 } 1004 )", 1005 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8"))); 1006 1007 ExpectLatticeChecksFor( 1008 R"( 1009 #include "unchecked_optional_access_test.h" 1010 1011 void target($ns::$optional<int> opt) { 1012 *std::move(opt); 1013 /*[[check]]*/ 1014 } 1015 )", 1016 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:8"))); 1017 } 1018 1019 TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) { 1020 ExpectLatticeChecksFor( 1021 R"( 1022 #include "unchecked_optional_access_test.h" 1023 1024 struct Foo { 1025 void foo(); 1026 }; 1027 1028 void target($ns::$optional<Foo> opt) { 1029 opt->foo(); 1030 /*[[check]]*/ 1031 } 1032 )", 1033 UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7"))); 1034 1035 ExpectLatticeChecksFor( 1036 R"( 1037 #include "unchecked_optional_access_test.h" 1038 1039 struct Foo { 1040 void foo(); 1041 }; 1042 1043 void target($ns::$optional<Foo> opt) { 1044 std::move(opt)->foo(); 1045 /*[[check]]*/ 1046 } 1047 )", 1048 UnorderedElementsAre(Pair("check", "unsafe: input.cc:9:7"))); 1049 } 1050 1051 TEST_P(UncheckedOptionalAccessTest, HasValueCheck) { 1052 ExpectLatticeChecksFor(R"( 1053 #include "unchecked_optional_access_test.h" 1054 1055 void target($ns::$optional<int> opt) { 1056 if (opt.has_value()) { 1057 opt.value(); 1058 /*[[check]]*/ 1059 } 1060 } 1061 )", 1062 UnorderedElementsAre(Pair("check", "safe"))); 1063 } 1064 1065 TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) { 1066 ExpectLatticeChecksFor(R"( 1067 #include "unchecked_optional_access_test.h" 1068 1069 void target($ns::$optional<int> opt) { 1070 if (opt) { 1071 opt.value(); 1072 /*[[check]]*/ 1073 } 1074 } 1075 )", 1076 UnorderedElementsAre(Pair("check", "safe"))); 1077 } 1078 1079 TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) { 1080 ExpectLatticeChecksFor( 1081 R"( 1082 #include "unchecked_optional_access_test.h" 1083 1084 void target() { 1085 Make<$ns::$optional<int>>().value(); 1086 (void)0; 1087 /*[[check]]*/ 1088 } 1089 )", 1090 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7"))); 1091 1092 ExpectLatticeChecksFor( 1093 R"( 1094 #include "unchecked_optional_access_test.h" 1095 1096 void target($ns::$optional<int> opt) { 1097 std::move(opt).value(); 1098 /*[[check]]*/ 1099 } 1100 )", 1101 UnorderedElementsAre(Pair("check", "unsafe: input.cc:5:7"))); 1102 } 1103 1104 TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) { 1105 ExpectLatticeChecksFor( 1106 R"( 1107 #include "unchecked_optional_access_test.h" 1108 1109 void target() { 1110 $ns::$optional<int> opt; 1111 opt.value(); 1112 /*[[check]]*/ 1113 } 1114 )", 1115 UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7"))); 1116 } 1117 1118 TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) { 1119 ExpectLatticeChecksFor( 1120 R"( 1121 #include "unchecked_optional_access_test.h" 1122 1123 void target() { 1124 $ns::$optional<int> opt($ns::nullopt); 1125 opt.value(); 1126 /*[[check]]*/ 1127 } 1128 )", 1129 UnorderedElementsAre(Pair("check", "unsafe: input.cc:6:7"))); 1130 } 1131 1132 TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) { 1133 ExpectLatticeChecksFor(R"( 1134 #include "unchecked_optional_access_test.h" 1135 1136 void target() { 1137 $ns::$optional<int> opt($ns::in_place, 3); 1138 opt.value(); 1139 /*[[check]]*/ 1140 } 1141 )", 1142 UnorderedElementsAre(Pair("check", "safe"))); 1143 1144 ExpectLatticeChecksFor(R"( 1145 #include "unchecked_optional_access_test.h" 1146 1147 struct Foo {}; 1148 1149 void target() { 1150 $ns::$optional<Foo> opt($ns::in_place); 1151 opt.value(); 1152 /*[[check]]*/ 1153 } 1154 )", 1155 UnorderedElementsAre(Pair("check", "safe"))); 1156 1157 ExpectLatticeChecksFor(R"( 1158 #include "unchecked_optional_access_test.h" 1159 1160 struct Foo { 1161 explicit Foo(int, bool); 1162 }; 1163 1164 void target() { 1165 $ns::$optional<Foo> opt($ns::in_place, 3, false); 1166 opt.value(); 1167 /*[[check]]*/ 1168 } 1169 )", 1170 UnorderedElementsAre(Pair("check", "safe"))); 1171 1172 ExpectLatticeChecksFor(R"( 1173 #include "unchecked_optional_access_test.h" 1174 1175 struct Foo { 1176 explicit Foo(std::initializer_list<int>); 1177 }; 1178 1179 void target() { 1180 $ns::$optional<Foo> opt($ns::in_place, {3}); 1181 opt.value(); 1182 /*[[check]]*/ 1183 } 1184 )", 1185 UnorderedElementsAre(Pair("check", "safe"))); 1186 } 1187 1188 TEST_P(UncheckedOptionalAccessTest, ValueConstructor) { 1189 ExpectLatticeChecksFor(R"( 1190 #include "unchecked_optional_access_test.h" 1191 1192 void target() { 1193 $ns::$optional<int> opt(21); 1194 opt.value(); 1195 /*[[check]]*/ 1196 } 1197 )", 1198 UnorderedElementsAre(Pair("check", "safe"))); 1199 1200 ExpectLatticeChecksFor(R"( 1201 #include "unchecked_optional_access_test.h" 1202 1203 void target() { 1204 $ns::$optional<int> opt = $ns::$optional<int>(21); 1205 opt.value(); 1206 /*[[check]]*/ 1207 } 1208 )", 1209 UnorderedElementsAre(Pair("check", "safe"))); 1210 ExpectLatticeChecksFor(R"( 1211 #include "unchecked_optional_access_test.h" 1212 1213 void target() { 1214 $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>()); 1215 opt.value(); 1216 /*[[check]]*/ 1217 } 1218 )", 1219 UnorderedElementsAre(Pair("check", "safe"))); 1220 1221 ExpectLatticeChecksFor(R"( 1222 #include "unchecked_optional_access_test.h" 1223 1224 struct MyString { 1225 MyString(const char*); 1226 }; 1227 1228 void target() { 1229 $ns::$optional<MyString> opt("foo"); 1230 opt.value(); 1231 /*[[check]]*/ 1232 } 1233 )", 1234 UnorderedElementsAre(Pair("check", "safe"))); 1235 1236 ExpectLatticeChecksFor(R"( 1237 #include "unchecked_optional_access_test.h" 1238 1239 struct Foo {}; 1240 1241 struct Bar { 1242 Bar(const Foo&); 1243 }; 1244 1245 void target() { 1246 $ns::$optional<Bar> opt(Make<Foo>()); 1247 opt.value(); 1248 /*[[check]]*/ 1249 } 1250 )", 1251 UnorderedElementsAre(Pair("check", "safe"))); 1252 1253 ExpectLatticeChecksFor(R"( 1254 #include "unchecked_optional_access_test.h" 1255 1256 struct Foo { 1257 explicit Foo(int); 1258 }; 1259 1260 void target() { 1261 $ns::$optional<Foo> opt(3); 1262 opt.value(); 1263 /*[[check]]*/ 1264 } 1265 )", 1266 UnorderedElementsAre(Pair("check", "safe"))); 1267 } 1268 1269 TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) { 1270 ExpectLatticeChecksFor( 1271 R"( 1272 #include "unchecked_optional_access_test.h" 1273 1274 struct Foo {}; 1275 1276 struct Bar { 1277 Bar(const Foo&); 1278 }; 1279 1280 void target() { 1281 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>()); 1282 opt.value(); 1283 /*[[check]]*/ 1284 } 1285 )", 1286 UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7"))); 1287 1288 ExpectLatticeChecksFor( 1289 R"( 1290 #include "unchecked_optional_access_test.h" 1291 1292 struct Foo {}; 1293 1294 struct Bar { 1295 explicit Bar(const Foo&); 1296 }; 1297 1298 void target() { 1299 $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>()); 1300 opt.value(); 1301 /*[[check]]*/ 1302 } 1303 )", 1304 UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7"))); 1305 1306 ExpectLatticeChecksFor( 1307 R"( 1308 #include "unchecked_optional_access_test.h" 1309 1310 struct Foo {}; 1311 1312 struct Bar { 1313 Bar(const Foo&); 1314 }; 1315 1316 void target() { 1317 $ns::$optional<Foo> opt1 = $ns::nullopt; 1318 $ns::$optional<Bar> opt2(opt1); 1319 opt2.value(); 1320 /*[[check]]*/ 1321 } 1322 )", 1323 UnorderedElementsAre(Pair("check", "unsafe: input.cc:13:7"))); 1324 1325 ExpectLatticeChecksFor(R"( 1326 #include "unchecked_optional_access_test.h" 1327 1328 struct Foo {}; 1329 1330 struct Bar { 1331 Bar(const Foo&); 1332 }; 1333 1334 void target() { 1335 $ns::$optional<Foo> opt1(Make<Foo>()); 1336 $ns::$optional<Bar> opt2(opt1); 1337 opt2.value(); 1338 /*[[check]]*/ 1339 } 1340 )", 1341 UnorderedElementsAre(Pair("check", "safe"))); 1342 1343 ExpectLatticeChecksFor(R"( 1344 #include "unchecked_optional_access_test.h" 1345 1346 struct Foo {}; 1347 1348 struct Bar { 1349 explicit Bar(const Foo&); 1350 }; 1351 1352 void target() { 1353 $ns::$optional<Foo> opt1(Make<Foo>()); 1354 $ns::$optional<Bar> opt2(opt1); 1355 opt2.value(); 1356 /*[[check]]*/ 1357 } 1358 )", 1359 UnorderedElementsAre(Pair("check", "safe"))); 1360 } 1361 1362 TEST_P(UncheckedOptionalAccessTest, MakeOptional) { 1363 ExpectLatticeChecksFor(R"( 1364 #include "unchecked_optional_access_test.h" 1365 1366 void target() { 1367 $ns::$optional<int> opt = $ns::make_optional(0); 1368 opt.value(); 1369 /*[[check]]*/ 1370 } 1371 )", 1372 UnorderedElementsAre(Pair("check", "safe"))); 1373 1374 ExpectLatticeChecksFor(R"( 1375 #include "unchecked_optional_access_test.h" 1376 1377 struct Foo { 1378 Foo(int, int); 1379 }; 1380 1381 void target() { 1382 $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22); 1383 opt.value(); 1384 /*[[check]]*/ 1385 } 1386 )", 1387 UnorderedElementsAre(Pair("check", "safe"))); 1388 1389 ExpectLatticeChecksFor(R"( 1390 #include "unchecked_optional_access_test.h" 1391 1392 struct Foo { 1393 constexpr Foo(std::initializer_list<char>); 1394 }; 1395 1396 void target() { 1397 char a = 'a'; 1398 $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a}); 1399 opt.value(); 1400 /*[[check]]*/ 1401 } 1402 )", 1403 UnorderedElementsAre(Pair("check", "safe"))); 1404 } 1405 1406 TEST_P(UncheckedOptionalAccessTest, ValueOr) { 1407 ExpectLatticeChecksFor(R"( 1408 #include "unchecked_optional_access_test.h" 1409 1410 void target() { 1411 $ns::$optional<int> opt; 1412 opt.value_or(0); 1413 (void)0; 1414 /*[[check]]*/ 1415 } 1416 )", 1417 UnorderedElementsAre(Pair("check", "safe"))); 1418 } 1419 1420 TEST_P(UncheckedOptionalAccessTest, Emplace) { 1421 ExpectLatticeChecksFor(R"( 1422 #include "unchecked_optional_access_test.h" 1423 1424 void target() { 1425 $ns::$optional<int> opt; 1426 opt.emplace(0); 1427 opt.value(); 1428 /*[[check]]*/ 1429 } 1430 )", 1431 UnorderedElementsAre(Pair("check", "safe"))); 1432 1433 ExpectLatticeChecksFor(R"( 1434 #include "unchecked_optional_access_test.h" 1435 1436 void target($ns::$optional<int> *opt) { 1437 opt->emplace(0); 1438 opt->value(); 1439 /*[[check]]*/ 1440 } 1441 )", 1442 UnorderedElementsAre(Pair("check", "safe"))); 1443 1444 // FIXME: Add tests that call `emplace` in conditional branches. 1445 } 1446 1447 TEST_P(UncheckedOptionalAccessTest, Reset) { 1448 ExpectLatticeChecksFor( 1449 R"( 1450 #include "unchecked_optional_access_test.h" 1451 1452 void target() { 1453 $ns::$optional<int> opt = $ns::make_optional(0); 1454 opt.reset(); 1455 opt.value(); 1456 /*[[check]]*/ 1457 } 1458 )", 1459 UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:7"))); 1460 1461 ExpectLatticeChecksFor( 1462 R"( 1463 #include "unchecked_optional_access_test.h" 1464 1465 void target($ns::$optional<int> &opt) { 1466 if (opt.has_value()) { 1467 opt.reset(); 1468 opt.value(); 1469 /*[[check]]*/ 1470 } 1471 } 1472 )", 1473 UnorderedElementsAre(Pair("check", "unsafe: input.cc:7:9"))); 1474 1475 // FIXME: Add tests that call `reset` in conditional branches. 1476 } 1477 1478 // FIXME: Add support for: 1479 // - constructors (copy, move) 1480 // - assignment operators (default, copy, move, non-standard) 1481 // - swap 1482 // - invalidation (passing optional by non-const reference/pointer) 1483 // - `value_or(nullptr) != nullptr`, `value_or(0) != 0`, `value_or("").empty()` 1484 // - nested `optional` values 1485