/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include #include #include #include namespace folly { template class Optional; struct None { enum class _secret { _token }; explicit constexpr None(_secret) {} }; constexpr None none{None::_secret::_token}; template class Optional { public: typedef Value value_type; constexpr Optional(); Optional(const Optional& src); constexpr Optional(const None&) noexcept; constexpr Optional(const Value& newValue); void assign(const None&); void assign(const Optional& src); Optional& operator=(None) noexcept { reset(); return *this; } Optional& operator=(const Optional& other) { assign(other); return *this; } template Value& emplace(Args&&... args); void reset() noexcept; constexpr Value& value() &; constexpr const Value& value() const&; constexpr bool has_value() const noexcept; constexpr explicit operator bool() const noexcept { return has_value(); } constexpr const Value* operator->() const { return &value(); } constexpr Value* operator->() { return &value(); } Value* get_pointer(); template constexpr Value value_or(U&& dflt) const&; }; } // namespace folly int not_none_ok() { folly::Optional foo{5}; return foo.value(); } // missing a more precise model for // constructing an optional from a value int not_none_check_value_ok_FP() { folly::Optional foo{5}; int x = foo.value(); if (x != 5) { folly::Optional foo{folly::none}; return foo.value(); } return x; } int none_check_ok() { folly::Optional foo{folly::none}; if (foo) { return foo.value(); } return -1; } int none_no_check_bad() { folly::Optional foo{folly::none}; return foo.value(); } int none_copy_ok() { folly::Optional foo{5}; folly::Optional bar{foo}; return bar.value(); } int none_copy_bad() { folly::Optional foo{folly::none}; folly::Optional bar{foo}; return bar.value(); } int assign_ok() { folly::Optional foo{5}; folly::Optional bar{foo}; foo = folly::none; return bar.value(); } int assign_bad() { folly::Optional foo{folly::none}; folly::Optional bar{5}; int sum = bar.value(); bar = foo; sum += bar.value(); return sum; } int assign2_bad() { folly::Optional foo{5}; int sum = foo.value(); foo = folly::none; sum += foo.value(); return sum; } struct State { std::vector vec; }; void emplace(folly::Optional state) { if (state) { state.emplace(); } auto pos = state->vec.begin(); } /* There is a bug in the frontend T89443328 */ void operator_arrow_bad_FN() { emplace(folly::none); } void get_pointer_check_none_check_ok() { folly::Optional foo{folly::none}; if (int* v = foo.get_pointer()) { *v = 42; } } void get_pointer_check_value_check_ok() { folly::Optional foo{5}; if (int* ptr = foo.get_pointer()) { *ptr = 42; } } void get_pointer_no_check_none_check_bad() { folly::Optional foo{folly::none}; int* ptr = foo.get_pointer(); *ptr = 42; } void get_pointer_no_check_value_check_ok() { folly::Optional foo{5}; int* ptr = foo.get_pointer(); *ptr = 42; } int value_or_check_empty_ok() { folly::Optional foo{folly::none}; if (foo.value_or(0) > 0) { return foo.value(); } return -1; } // missing a more precise model for constructing an optional from a // value, which could cause an FP but doesn't at the moment int value_or_check_value_ok() { folly::Optional foo{5}; int x = foo.value_or(0); if (x != 5) { folly::Optional foo{folly::none}; return foo.value(); } return -1; } int test_trace_ref() { folly::Optional foo{5}; int sum = foo.value(); foo = folly::none; int& x = foo.value(); sum += x; return sum; } struct StringWrapper { static folly::Optional get_optional() { return StringWrapper(); }; std::string x; }; std::string get_optional_string_wrapper_ok() { return StringWrapper::get_optional().value().x.data(); } int std_not_none_ok() { std::optional foo{5}; return foo.value(); } int std_not_none_check_value_ok_FP() { std::optional foo{5}; int x = foo.value(); if (x != 5) { std::optional foo{std::nullopt}; return foo.value(); } return x; } int std_none_check_ok() { std::optional foo{std::nullopt}; if (foo) { return foo.value(); } return -1; } int std_none_check_has_value_ok() { std::optional foo{std::nullopt}; if (foo.has_value()) { return foo.value(); } return -1; } int std_none_no_check_bad() { std::optional foo{std::nullopt}; return foo.value(); } int std_none_copy_ok() { std::optional foo{5}; std::optional bar{foo}; return bar.value(); } int std_none_copy_bad() { std::optional foo{std::nullopt}; std::optional bar{foo}; return bar.value(); } int std_assign_ok() { std::optional foo{5}; std::optional bar{foo}; foo = std::nullopt; return bar.value(); } int std_assign_bad() { std::optional foo{std::nullopt}; std::optional bar{5}; int sum = bar.value(); bar = foo; sum += bar.value(); return sum; } int std_assign2_bad() { std::optional foo{5}; int sum = foo.value(); foo = std::nullopt; sum += foo.value(); return sum; } void std_emplace(std::optional state) { if (state) { state.emplace(); } auto pos = state->vec.begin(); } void FN_std_operator_arrow_bad() { std_emplace(std::nullopt); } int std_value_or_check_empty_ok() { std::optional foo{std::nullopt}; if (foo.value_or(0) > 0) { return foo.value(); } return -1; } int std_value_or_check_value_ok() { std::optional foo{5}; int x = foo.value_or(0); if (x != 5) { std::optional foo{std::nullopt}; return foo.value(); } return -1; } struct Container final { std::vector _vec; Container() : _vec(std::vector{}) {} folly::Optional getFirst() const { if (_vec.empty()) { return folly::none; } return _vec.front(); } int optional_check_ok(const Container& c) { if (!c._vec.empty()) { return c.getFirst().value(); } return -1; } }; std::optional might_return_none(bool b, std::string x) { if (b) { return std::nullopt; } return x; } std::string reassing_non_empty_ok(const std::string& x) { std::optional foo = might_return_none(true, x); if (!foo.has_value()) { foo = x; } return foo.value(); } constexpr const char* envVar = "ENV_VAR"; enum E { OP1, OP2 }; std::optional getOptionalValue() { auto value = std::getenv(envVar); if (value) { return std::string{value}; } return std::nullopt; } E getEnum() { auto value = std::getenv(envVar); if (value) { return E::OP1; } return E::OP2; } std::optional cannot_be_empty() { if (getEnum() == E::OP1) { return getOptionalValue().value(); } return std::nullopt; } std::string inside_try_catch_FP(const std::string& x) { std::optional foo = might_return_none(true, x); try { return foo.value(); } catch (...) { return ""; } } struct Node { std::shared_ptr shared; folly::Optional> getShared() const { if (shared == nullptr) { return folly::none; } return shared; } }; int smart_pointer(const Node& node) { if (node.getShared().has_value()) { return *(node.getShared().value()); } return -1; }