| 1 | //===-- MemberwiseConstructorTests.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 | |
| 9 | #include "TweakTesting.h" |
| 10 | #include "gmock/gmock-matchers.h" |
| 11 | #include "gmock/gmock.h" |
| 12 | #include "gtest/gtest.h" |
| 13 | |
| 14 | namespace clang { |
| 15 | namespace clangd { |
| 16 | namespace { |
| 17 | using testing::AllOf; |
| 18 | using testing::Eq; |
| 19 | using testing::HasSubstr; |
| 20 | using testing::Not; |
| 21 | |
| 22 | TWEAK_TEST(MemberwiseConstructor); |
| 23 | |
| 24 | TEST_F(MemberwiseConstructorTest, Availability) { |
| 25 | EXPECT_AVAILABLE("^struct ^S ^{ int x, y; };" ); |
| 26 | // Verify no crashes on incomplete member fields. |
| 27 | EXPECT_UNAVAILABLE("/*error-ok*/class Forward; class ^A { Forward f;}" ); |
| 28 | EXPECT_UNAVAILABLE("struct S { ^int ^x, y; }; struct ^S;" ); |
| 29 | EXPECT_UNAVAILABLE("struct ^S {};" ); |
| 30 | EXPECT_UNAVAILABLE("union ^S { int x; };" ); |
| 31 | EXPECT_UNAVAILABLE("struct ^S { int x = 0; };" ); |
| 32 | EXPECT_UNAVAILABLE("struct ^S { struct { int x; }; };" ); |
| 33 | EXPECT_UNAVAILABLE("struct ^{ int x; } e;" ); |
| 34 | } |
| 35 | |
| 36 | TEST_F(MemberwiseConstructorTest, Edits) { |
| 37 | Header = R"cpp( |
| 38 | struct Move { |
| 39 | Move(Move&&) = default; |
| 40 | Move(const Move&) = delete; |
| 41 | }; |
| 42 | struct Copy { |
| 43 | Copy(Copy&&) = delete; |
| 44 | Copy(const Copy&); |
| 45 | }; |
| 46 | )cpp" ; |
| 47 | EXPECT_EQ(apply("struct ^S{Move M; Copy C; int I; int J=4;};" ), |
| 48 | "struct S{" |
| 49 | "S(Move M, const Copy &C, int I) : M(std::move(M)), C(C), I(I) {}\n" |
| 50 | "Move M; Copy C; int I; int J=4;};" ); |
| 51 | } |
| 52 | |
| 53 | TEST_F(MemberwiseConstructorTest, FieldTreatment) { |
| 54 | Header = R"cpp( |
| 55 | struct MoveOnly { |
| 56 | MoveOnly(MoveOnly&&) = default; |
| 57 | MoveOnly(const MoveOnly&) = delete; |
| 58 | }; |
| 59 | struct CopyOnly { |
| 60 | CopyOnly(CopyOnly&&) = delete; |
| 61 | CopyOnly(const CopyOnly&); |
| 62 | }; |
| 63 | struct CopyTrivial { |
| 64 | CopyTrivial(CopyTrivial&&) = default; |
| 65 | CopyTrivial(const CopyTrivial&) = default; |
| 66 | }; |
| 67 | struct Immovable { |
| 68 | Immovable(Immovable&&) = delete; |
| 69 | Immovable(const Immovable&) = delete; |
| 70 | }; |
| 71 | template <typename T> |
| 72 | struct Traits { using Type = typename T::Type; }; |
| 73 | using IntAlias = int; |
| 74 | )cpp" ; |
| 75 | |
| 76 | auto Fail = Eq(x: "unavailable" ); |
| 77 | auto Move = HasSubstr(substring: ": Member(std::move(Member))" ); |
| 78 | auto CopyRef = AllOf(matchers: HasSubstr(substring: "S(const " ), matchers: HasSubstr(substring: ": Member(Member)" )); |
| 79 | auto Copy = AllOf(matchers: Not(m: HasSubstr(substring: "S(const " )), matchers: HasSubstr(substring: ": Member(Member)" )); |
| 80 | auto With = [](llvm::StringRef Type) { |
| 81 | return ("struct ^S { " + Type + " Member; };" ).str(); |
| 82 | }; |
| 83 | |
| 84 | EXPECT_THAT(apply(With("Immovable" )), Fail); |
| 85 | EXPECT_THAT(apply(With("MoveOnly" )), Move); |
| 86 | EXPECT_THAT(apply(With("CopyOnly" )), CopyRef); |
| 87 | EXPECT_THAT(apply(With("CopyTrivial" )), Copy); |
| 88 | EXPECT_THAT(apply(With("int" )), Copy); |
| 89 | EXPECT_THAT(apply(With("IntAlias" )), Copy); |
| 90 | EXPECT_THAT(apply(With("Immovable*" )), Copy); |
| 91 | EXPECT_THAT(apply(With("Immovable&" )), Copy); |
| 92 | |
| 93 | EXPECT_THAT(apply("template <typename T>" + With("T" )), Move); |
| 94 | EXPECT_THAT(apply("template <typename T>" + With("typename Traits<T>::Type" )), |
| 95 | Move); |
| 96 | EXPECT_THAT(apply("template <typename T>" + With("T*" )), Copy); |
| 97 | } |
| 98 | |
| 99 | } // namespace |
| 100 | } // namespace clangd |
| 101 | } // namespace clang |
| 102 | |