kbobyrev created this revision. kbobyrev added a reviewer: hokein. Herald added subscribers: cfe-commits, usaxena95, arphaman. Herald added a project: clang. kbobyrev requested review of this revision. Herald added subscribers: MaskRay, ilya-biryukov.
Tests can not be adopted 1:1 (e.g. Clang-Rename modifies namespace for some symbols) and some tests appear to not be working due to our selection/other factors. However, this helps us expose some unexpected bugs and prepares for the decl canonicalization fix. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D91240 Files: clang-tools-extra/clangd/unittests/RenameTests.cpp
Index: clang-tools-extra/clangd/unittests/RenameTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/RenameTests.cpp +++ clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -608,6 +608,222 @@ } } +struct Case { + std::string Before; + std::string After; + std::string NewName; +}; + +// FIXME: Unfortunately, we can not have actual header + source file for +// within-file rename (all references to renamed symbol must be within the +// file). The workaround is to have the "header" finish with --END--\n and split +// the "source" and "header" within the test. Is there a better way to do that? +class ComplicatedRenameTest : public testing::Test, + public testing::WithParamInterface<Case> { +protected: + void appendToHeader(StringRef AdditionalCode) { + HeaderCode += AdditionalCode.str(); + } + + void runRenameOnCode(llvm::StringRef Before, llvm::StringRef After, + llvm::StringRef NewName) { + SCOPED_TRACE(Before); + Annotations Code((HeaderCode + Before).str()); + auto TU = TestTU::withCode(Code.code()); + TU.ExtraArgs.push_back("-fno-delayed-template-parsing"); + auto AST = TU.build(); + for (const auto &RenamePos : Code.points()) { + auto RenameResult = + rename({RenamePos, NewName, AST, testPath(TU.Filename)}); + ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError(); + ASSERT_EQ(1u, RenameResult->GlobalChanges.size()); + const auto Result = + applyEdits(std::move(RenameResult->GlobalChanges)).front().second; + const std::string Delimiter = "---END---\n"; + EXPECT_EQ(Result.substr(Result.find(Delimiter) + Delimiter.size()), + After); + } + } + + std::string HeaderCode; +}; + +class RenameAliasTest : public ComplicatedRenameTest { +public: + RenameAliasTest() { + appendToHeader(R"( + #define MACRO(x) x + namespace some_ns { + class A { + public: + void foo() {} + struct Nested { + enum NestedEnum { + E1, E2, + }; + }; + }; + } // namespace some_ns + namespace a { + typedef some_ns::A TA; + using UA = some_ns::A; + } // namespace a + namespace b { + typedef some_ns::A TA; + using UA = some_ns::A; + } + template <typename T> class ptr {}; + template <typename T> + + using TPtr = ptr<int>; + + // ---END--- +)"); + } +}; + +INSTANTIATE_TEST_CASE_P( + RenameAliasTests, RenameAliasTest, + testing::ValuesIn(std::vector<Case>({ + // basic functions + {"void f(a::[[T^A]] a1) {}", "void f(a::TB a1) {}", "TB"}, + {"void f(a::[[U^A]] a1) {}", "void f(a::UB a1) {}", "UB"}, + {"void f(a::[[T^A]]* a1) {}", "void f(a::TB* a1) {}", "TB"}, + {"void f(a::[[T^A]]** a1) {}", "void f(a::TB** a1) {}", "TB"}, + {"a::[[T^A]] f() { return a::[[T^A]](); }", + "a::TB f() { return a::TB(); }", "TB"}, + {"a::[[T^A]] f() { return a::UA(); }", "a::TB f() { return a::UA(); }", + "TB"}, + {"a::TA f() { return a::[[U^A]](); }", "a::TA f() { return a::UB(); }", + "UB"}, + {"void f() { a::[[T^A]] a; }", "void f() { a::TB a; }", "TB"}, + {"void f(const a::[[T^A]]& a1) {}", "void f(const a::TB& a1) {}", "TB"}, + {"void f(const a::[[U^A]]& a1) {}", "void f(const a::UB& a1) {}", "UB"}, + {"void f(const a::[[T^A]]* a1) {}", "void f(const a::TB* a1) {}", "TB"}, + {"namespace a { void f([[T^A]] a1) {} }", + "namespace a { void f(TB a1) {} }", "TB"}, + {"void f(MACRO(a::[[T^A]]) a1) {}", "void f(MACRO(a::TB) a1) {}", "TB"}, + {"void f(MACRO(a::[[T^A]] a1)) {}", "void f(MACRO(a::TB a1)) {}", "TB"}, + + // use namespace and typedefs + {"struct S { using T = a::[[T^A]]; T a_; };", + "struct S { using T = a::TB; T a_; };", "TB"}, + {"using T = a::[[T^A]]; T gA;", "using T = a::TB; T gA;", "TB"}, + {"using T = a::[[U^A]]; T gA;", "using T = a::UB; T gA;", "UB"}, + {"typedef a::[[T^A]] T; T gA;", "typedef a::TB T; T gA;", "TB"}, + {"typedef a::[[U^A]] T; T gA;", "typedef a::UB T; T gA;", "UB"}, + {"typedef MACRO(a::[[T^A]]) T; T gA;", "typedef MACRO(a::TB) T; T gA;", + "TB"}, + + // struct members and other oddities + {"struct S : public a::[[T^A]] {};", "struct S : public a::TB {};", + "TB"}, + {"struct S : public a::[[U^A]] {};", "struct S : public a::UB {};", + "UB"}, + {"struct F { void f(a::[[T^A]] a1) {} };", + "struct F { void f(a::TB a1) {} };", "TB"}, + {"struct F { a::[[T^A]] a_; };", "struct F { a::TB a_; };", "TB"}, + {"struct F { ptr<a::[[T^A]]> a_; };", "struct F { ptr<a::TB> a_; };", + "TB"}, + {"struct F { ptr<a::[[U^A]]> a_; };", "struct F { ptr<a::UB> a_; };", + "UB"}, + + // types in nested name specifiers + {"void f() { a::[[T^A]]::Nested ne; }", + "void f() { a::TB::Nested ne; }", "TB"}, + {"void f() { a::[[U^A]]::Nested ne; }", + "void f() { a::UB::Nested ne; }", "UB"}, + {"void f() { a::[[T^A]]::Nested::NestedEnum e; }", + "void f() { a::TB::Nested::NestedEnum e; }", "TB"}, + {"void f() { auto e = a::[[T^A]]::Nested::NestedEnum::E1; }", + "void f() { auto e = a::TB::Nested::NestedEnum::E1; }", "TB"}, + {"void f() { auto e = a::[[T^A]]::Nested::E1; }", + "void f() { auto e = a::TB::Nested::E1; }", "TB"}, + + // templates + {"template <typename T> struct Foo { T t; }; void f() { " + "Foo<a::[[T^A]]> " + "foo; }", + "template <typename T> struct Foo { T t; }; void f() { Foo<a::TB> " + "foo; }", + "TB"}, + {"template <typename T> struct Foo { a::[[T^A]] a; };", + "template <typename T> struct Foo { a::TB a; };", "TB"}, + {"template <typename T> void f(T t) {} void g() { " + "f<a::[[T^A]]>(a::[[T^A]]()); }", + "template <typename T> void f(T t) {} void g() { f<a::TB>(a::TB()); }", + "TB"}, + {"template <typename T> void f(T t) {} void g() { " + "f<a::[[U^A]]>(a::[[U^A]]()); }", + "template <typename T> void f(T t) {} void g() { f<a::UB>(a::UB()); }", + "UB"}, + {"template <typename T> int f() { return 1; } template <> int " + "f<a::[[T^A]]>() { return 2; } int g() { return f<a::[[T^A]]>(); }", + "template <typename T> int f() { return 1; } template <> int " + "f<a::TB>() { return 2; } int g() { return f<a::TB>(); }", + "TB"}, + {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "auto a = f.template foo<a::[[T^A]]>(); }", + "struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "auto a = f.template foo<a::TB>(); }", + "TB"}, + {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "auto a = f.template foo<a::[[U^A]]>(); }", + "struct Foo { template <typename T> T foo(); }; void g() { Foo f; " + "auto a = f.template foo<a::UB>(); }", + "UB"}, + + // The following two templates are distilled from regressions found in + // unique_ptr<> and type_traits.h + {"template <typename T> struct outer { typedef T type; type Baz(); }; " + "outer<a::[[T^A]]> g_A;", + "template <typename T> struct outer { typedef T type; type Baz(); }; " + "outer<a::TB> g_A;", + "TB"}, + {"template <typename T> struct nested { typedef T type; }; template " + "<typename T> struct outer { typename nested<T>::type Foo(); }; " + "outer<a::[[T^A]]> g_A;", + "template <typename T> struct nested { typedef T type; }; template " + "<typename T> struct outer { typename nested<T>::type Foo(); }; " + "outer<a::TB> g_A;", + "TB"}, + + // macros + {"#define FOO(T, t) T t\nvoid f() { FOO(a::[[T^A]], a1); " + "FOO(a::[[T^A]], " + "a2); }", + "#define FOO(T, t) T t\nvoid f() { FOO(a::TB, a1); FOO(a::TB, a2); }", + "TB"}, + // FIXME: These will not work: can't select within the macro. + // {"#define FOO(n) a::[[T^A]] n\nvoid f() { FOO(a1); FOO(a2); }", + // "#define FOO(n) a::TB n\nvoid f() { FOO(a1); FOO(a2); }", "TB"}, + // {"#define FOO(n) a::[[U^A]] n\nvoid f() { FOO(a1); FOO(a2); }", + // "#define FOO(n) a::UB n\nvoid f() { FOO(a1); FOO(a2); }", "UB"}, + + // Pointer to member functions + {"auto gA = &a::[[T^A]]::foo;", "auto gA = &a::TB::foo;", "TB"}, + // FIXME: This does not work yet: using a::TA points to multiple + // symbols? Selecting at the first location doesn't work and selecting + // at the second one does not rename the first instance. + // {"using a::[[T^A]]; auto gA = &[[T^A]]::foo;", + // "using a::TB; auto gA = &a::TB::foo;", "TB"}, + {"typedef a::[[T^A]] T; auto gA = &T::foo;", + "typedef a::TB T; auto gA = &T::foo;", "TB"}, + {"auto gA = &MACRO(a::[[T^A]])::foo;", "auto gA = &MACRO(a::TB)::foo;", + "TB"}, + + // templated using alias. + {"void f([[T^Ptr]]<int> p) {}", "void f(NewTPtr<int> p) {}", "NewTPtr"}, + {"void f(::[[T^Ptr]]<int> p) {}", "void f(::NewTPtr<int> p) {}", + "NewTPtr"}, + })), ); + +TEST_P(RenameAliasTest, RenameAlias) { + auto Param = GetParam(); + assert(!Param.NewName.empty()); + runRenameOnCode(Param.Before, Param.After, Param.NewName); +} + TEST(RenameTest, Renameable) { struct Case { const char *Code;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits