[pulse] A new issue type OPTIONAL_EMPTY_ACCESS for trying to access folly::Optional when it is folly::none
Summary: We need to check if `folly::Optional` is not `folly::none` if we want to retrieve the value, otherwise a runtime exception is thrown: ``` folly::Optional<int> foo{folly::none}; return foo.value(); // bad ``` ``` folly::Optional<int> foo{folly::none}; if (foo) { return foo.value(); // ok } ``` This diff adds a new issue type that reports if we try to access `folly::Optional` value when it is known to be `folly::none`. Reviewed By: ezgicicek Differential Revision: D22053352 fbshipit-source-id: 32cb00a99master
parent
d8a3c4c2a3
commit
2c48e61031
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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 <vector>
|
||||
|
||||
namespace folly {
|
||||
|
||||
template <class Value>
|
||||
class Optional;
|
||||
|
||||
struct None {
|
||||
enum class _secret { _token };
|
||||
explicit constexpr None(_secret) {}
|
||||
};
|
||||
constexpr None none{None::_secret::_token};
|
||||
|
||||
template <class Value>
|
||||
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 <class... Args>
|
||||
Value& emplace(Args&&... args);
|
||||
|
||||
void reset() noexcept;
|
||||
|
||||
constexpr Value& value() &;
|
||||
|
||||
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(); }
|
||||
};
|
||||
} // namespace folly
|
||||
|
||||
int not_none_ok() {
|
||||
folly::Optional<int> foo{5};
|
||||
return foo.value();
|
||||
}
|
||||
|
||||
int none_check_ok() {
|
||||
folly::Optional<int> foo{folly::none};
|
||||
if (foo) {
|
||||
return foo.value();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int none_no_check_bad() {
|
||||
folly::Optional<int> foo{folly::none};
|
||||
return foo.value();
|
||||
}
|
||||
|
||||
int none_copy_ok() {
|
||||
folly::Optional<int> foo{5};
|
||||
folly::Optional<int> bar{foo};
|
||||
return bar.value();
|
||||
}
|
||||
|
||||
int none_copy_bad() {
|
||||
folly::Optional<int> foo{folly::none};
|
||||
folly::Optional<int> bar{foo};
|
||||
return bar.value();
|
||||
}
|
||||
|
||||
int assign_ok() {
|
||||
folly::Optional<int> foo{5};
|
||||
folly::Optional<int> bar{foo};
|
||||
foo = folly::none;
|
||||
return bar.value();
|
||||
}
|
||||
|
||||
int assign_bad() {
|
||||
folly::Optional<int> foo{folly::none};
|
||||
folly::Optional<int> bar{5};
|
||||
int sum = bar.value();
|
||||
bar = foo;
|
||||
sum += bar.value();
|
||||
return sum;
|
||||
}
|
||||
|
||||
int assign2_bad() {
|
||||
folly::Optional<int> foo{5};
|
||||
int sum = foo.value();
|
||||
foo = folly::none;
|
||||
sum += foo.value();
|
||||
return sum;
|
||||
}
|
||||
|
||||
struct State {
|
||||
std::vector<int> vec;
|
||||
};
|
||||
|
||||
void emplace(folly::Optional<State> state) {
|
||||
if (state) {
|
||||
state.emplace();
|
||||
}
|
||||
auto pos = state->vec.begin();
|
||||
}
|
||||
|
||||
void operator_arrow_bad() { emplace(folly::none); }
|
Loading…
Reference in new issue