mirror of
https://github.com/google/googletest.git
synced 2025-12-06 08:46:50 +08:00
In MatcherCast, store the input value as its own type rather than as the Matcher type, to avoid dangling references
PiperOrigin-RevId: 769240838 Change-Id: I7b1ac23a0a88ba90b5d1ae6e20b97f679f381f31
This commit is contained in:
parent
28e9d1f267
commit
6230d316e1
@ -376,11 +376,16 @@ class MatcherCastImpl {
|
|||||||
|
|
||||||
// M can't be implicitly converted to Matcher<T>, so M isn't a polymorphic
|
// M can't be implicitly converted to Matcher<T>, so M isn't a polymorphic
|
||||||
// matcher. It's a value of a type implicitly convertible to T. Use direct
|
// matcher. It's a value of a type implicitly convertible to T. Use direct
|
||||||
// initialization to create a matcher.
|
// initialization or `ImplicitCastEqMatcher` to create a matcher.
|
||||||
static Matcher<T> CastImpl(const M& value,
|
static Matcher<T> CastImpl(const M& value,
|
||||||
std::false_type /* convertible_to_matcher */,
|
std::false_type /* convertible_to_matcher */,
|
||||||
std::true_type /* convertible_to_T */) {
|
std::true_type /* convertible_to_T */) {
|
||||||
return Matcher<T>(ImplicitCast_<T>(value));
|
using NoRefT = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||||
|
if constexpr (std::is_same_v<M, NoRefT>) {
|
||||||
|
return Matcher<T>(value);
|
||||||
|
} else {
|
||||||
|
return ImplicitCastEqMatcher<NoRefT, std::decay_t<const M&>>(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// M can't be implicitly converted to either Matcher<T> or T. Attempt to use
|
// M can't be implicitly converted to either Matcher<T> or T. Attempt to use
|
||||||
@ -391,11 +396,11 @@ class MatcherCastImpl {
|
|||||||
// latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end
|
// latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end
|
||||||
// which might be undefined even when Rhs is implicitly convertible to Lhs
|
// which might be undefined even when Rhs is implicitly convertible to Lhs
|
||||||
// (e.g. std::pair<const int, int> vs. std::pair<int, int>).
|
// (e.g. std::pair<const int, int> vs. std::pair<int, int>).
|
||||||
//
|
|
||||||
// We don't define this method inline as we need the declaration of Eq().
|
|
||||||
static Matcher<T> CastImpl(const M& value,
|
static Matcher<T> CastImpl(const M& value,
|
||||||
std::false_type /* convertible_to_matcher */,
|
std::false_type /* convertible_to_matcher */,
|
||||||
std::false_type /* convertible_to_T */);
|
std::false_type /* convertible_to_T */) {
|
||||||
|
return Eq(value);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This more specialized version is used when MatcherCast()'s argument
|
// This more specialized version is used when MatcherCast()'s argument
|
||||||
@ -4483,13 +4488,6 @@ inline Matcher<T> An() {
|
|||||||
return _;
|
return _;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename M>
|
|
||||||
Matcher<T> internal::MatcherCastImpl<T, M>::CastImpl(
|
|
||||||
const M& value, std::false_type /* convertible_to_matcher */,
|
|
||||||
std::false_type /* convertible_to_T */) {
|
|
||||||
return Eq(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a polymorphic matcher that matches any NULL pointer.
|
// Creates a polymorphic matcher that matches any NULL pointer.
|
||||||
inline PolymorphicMatcher<internal::IsNullMatcher> IsNull() {
|
inline PolymorphicMatcher<internal::IsNullMatcher> IsNull() {
|
||||||
return MakePolymorphicMatcher(internal::IsNullMatcher());
|
return MakePolymorphicMatcher(internal::IsNullMatcher());
|
||||||
|
|||||||
@ -622,15 +622,42 @@ struct IntReferenceWrapper {
|
|||||||
const int* value;
|
const int* value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Compared the contained values
|
||||||
bool operator==(const IntReferenceWrapper& a, const IntReferenceWrapper& b) {
|
bool operator==(const IntReferenceWrapper& a, const IntReferenceWrapper& b) {
|
||||||
return a.value == b.value;
|
return *a.value == *b.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MatcherCastTest, ValueIsNotCopied) {
|
TEST(MatcherCastTest, ValueIsCopied) {
|
||||||
int n = 42;
|
{
|
||||||
Matcher<IntReferenceWrapper> m = MatcherCast<IntReferenceWrapper>(n);
|
// When an IntReferenceWrapper is passed.
|
||||||
// Verify that the matcher holds a reference to n, not to its temporary copy.
|
int n = 42;
|
||||||
EXPECT_TRUE(m.Matches(n));
|
Matcher<IntReferenceWrapper> m =
|
||||||
|
MatcherCast<IntReferenceWrapper>(IntReferenceWrapper(n));
|
||||||
|
{
|
||||||
|
int value = 42;
|
||||||
|
EXPECT_TRUE(m.Matches(value));
|
||||||
|
value = 10;
|
||||||
|
EXPECT_FALSE(m.Matches(value));
|
||||||
|
// This changes the stored reference.
|
||||||
|
n = 10;
|
||||||
|
EXPECT_TRUE(m.Matches(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// When an int is passed.
|
||||||
|
int n = 42;
|
||||||
|
Matcher<IntReferenceWrapper> m = MatcherCast<IntReferenceWrapper>(n);
|
||||||
|
{
|
||||||
|
int value = 42;
|
||||||
|
EXPECT_TRUE(m.Matches(value));
|
||||||
|
value = 10;
|
||||||
|
EXPECT_FALSE(m.Matches(value));
|
||||||
|
// This does not change the stored int.
|
||||||
|
n = 10;
|
||||||
|
EXPECT_FALSE(m.Matches(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Base {
|
class Base {
|
||||||
|
|||||||
@ -773,6 +773,35 @@ class GeMatcher
|
|||||||
static const char* NegatedDesc() { return "isn't >="; }
|
static const char* NegatedDesc() { return "isn't >="; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Same as `EqMatcher<Rhs>`, except that the `rhs` is stored as `StoredRhs` and
|
||||||
|
// must be implicitly convertible to `Rhs`.
|
||||||
|
template <typename Rhs, typename StoredRhs>
|
||||||
|
class ImplicitCastEqMatcher {
|
||||||
|
public:
|
||||||
|
explicit ImplicitCastEqMatcher(const StoredRhs& rhs) : stored_rhs_(rhs) {}
|
||||||
|
|
||||||
|
using is_gtest_matcher = void;
|
||||||
|
|
||||||
|
template <typename Lhs>
|
||||||
|
bool MatchAndExplain(const Lhs& lhs, std::ostream*) const {
|
||||||
|
return lhs == rhs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescribeTo(std::ostream* os) const {
|
||||||
|
*os << "is equal to ";
|
||||||
|
UniversalPrint(rhs(), os);
|
||||||
|
}
|
||||||
|
void DescribeNegationTo(std::ostream* os) const {
|
||||||
|
*os << "isn't equal to ";
|
||||||
|
UniversalPrint(rhs(), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Rhs rhs() const { return ImplicitCast_<Rhs>(stored_rhs_); }
|
||||||
|
|
||||||
|
StoredRhs stored_rhs_;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<
|
template <typename T, typename = typename std::enable_if<
|
||||||
std::is_constructible<std::string, T>::value>::type>
|
std::is_constructible<std::string, T>::value>::type>
|
||||||
using StringLike = T;
|
using StringLike = T;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user