From 977de9aa100fb9012a1c37d4b1f683b87846e65d Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 18 Oct 2017 12:10:11 +0000 Subject: [clang-rename] Rename alias. Summary: * Support rename alias. * Add unittests for renaming alias. * Don't generate fixes for the SourceLocations that are invalid or in temporary buffer, otherwise crash would be happened when generating AtomicChanges. Reviewers: ioeric Reviewed By: ioeric Subscribers: klimek, mgorny, cfe-commits Differential Revision: https://reviews.llvm.org/D39043 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316074 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/Rename/CMakeLists.txt | 1 + unittests/Rename/RenameAliasTest.cpp | 304 +++++++++++++++++++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 unittests/Rename/RenameAliasTest.cpp (limited to 'unittests/Rename') diff --git a/unittests/Rename/CMakeLists.txt b/unittests/Rename/CMakeLists.txt index 5a6875e0bc..1c50fde37d 100644 --- a/unittests/Rename/CMakeLists.txt +++ b/unittests/Rename/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories(${CLANG_SOURCE_DIR}) add_clang_unittest(ClangRenameTests RenameClassTest.cpp RenameEnumTest.cpp + RenameAliasTest.cpp RenameFunctionTest.cpp ) diff --git a/unittests/Rename/RenameAliasTest.cpp b/unittests/Rename/RenameAliasTest.cpp new file mode 100644 index 0000000000..59becaef68 --- /dev/null +++ b/unittests/Rename/RenameAliasTest.cpp @@ -0,0 +1,304 @@ +//===-- RenameAliasTest.cpp - unit tests for renaming alias ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangRenameTest.h" + +namespace clang { +namespace clang_rename { +namespace test { +namespace { + +class RenameAliasTest : public ClangRenameTest { +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 class ptr {}; + template + + using TPtr = ptr; + )"); + } +}; + +INSTANTIATE_TEST_CASE_P( + RenameAliasTests, RenameAliasTest, + testing::ValuesIn(std::vector({ + // basic functions + {"void f(a::TA a1) {}", "void f(b::TB a1) {}", "a::TA", "b::TB"}, + {"void f(a::UA a1) {}", "void f(b::UB a1) {}", "a::UA", "b::UB"}, + {"void f(a::TA* a1) {}", "void f(b::TB* a1) {}", "a::TA", "b::TB"}, + {"void f(a::TA** a1) {}", "void f(b::TB** a1) {}", "a::TA", "b::TB"}, + {"a::TA f() { return a::TA(); }", "b::TB f() { return b::TB(); }", + "a::TA", "b::TB"}, + {"a::TA f() { return a::UA(); }", "b::TB f() { return a::UA(); }", + "a::TA", "b::TB"}, + {"a::TA f() { return a::UA(); }", "a::TA f() { return b::UB(); }", + "a::UA", "b::UB"}, + {"void f() { a::TA a; }", "void f() { b::TB a; }", "a::TA", "b::TB"}, + {"void f(const a::TA& a1) {}", "void f(const b::TB& a1) {}", "a::TA", + "b::TB"}, + {"void f(const a::UA& a1) {}", "void f(const b::UB& a1) {}", "a::UA", + "b::UB"}, + {"void f(const a::TA* a1) {}", "void f(const b::TB* a1) {}", "a::TA", + "b::TB"}, + {"namespace a { void f(TA a1) {} }", + "namespace a { void f(b::TB a1) {} }", "a::TA", "b::TB"}, + {"void f(MACRO(a::TA) a1) {}", "void f(MACRO(b::TB) a1) {}", "a::TA", + "b::TB"}, + {"void f(MACRO(a::TA a1)) {}", "void f(MACRO(b::TB a1)) {}", "a::TA", + "b::TB"}, + + // shorten/add namespace. + {"namespace b { void f(a::UA a1) {} }", + "namespace b {void f(UB a1) {} }", "a::UA", "b::UB"}, + {"namespace a { void f(UA a1) {} }", + "namespace a {void f(b::UB a1) {} }", "a::UA", "b::UB"}, + + // use namespace and typedefs + {"struct S { using T = a::TA; T a_; };", + "struct S { using T = b::TB; T a_; };", "a::TA", "b::TB"}, + {"using T = a::TA; T gA;", "using T = b::TB; T gA;", "a::TA", "b::TB"}, + {"using T = a::UA; T gA;", "using T = b::UB; T gA;", "a::UA", "b::UB"}, + {"typedef a::TA T; T gA;", "typedef b::TB T; T gA;", "a::TA", "b::TB"}, + {"typedef a::UA T; T gA;", "typedef b::UB T; T gA;", "a::UA", "b::UB"}, + {"typedef MACRO(a::TA) T; T gA;", "typedef MACRO(b::TB) T; T gA;", + "a::TA", "b::TB"}, + + // types in using shadows. + {"using a::TA; TA gA;", "using b::TB; b::TB gA;", "a::TA", "b::TB"}, + {"using a::UA; UA gA;", "using b::UB; b::UB gA;", "a::UA", "b::UB"}, + + // struct members and other oddities + {"struct S : public a::TA {};", "struct S : public b::TB {};", "a::TA", + "b::TB"}, + {"struct S : public a::UA {};", "struct S : public b::UB {};", "a::UA", + "b::UB"}, + {"struct F { void f(a::TA a1) {} };", + "struct F { void f(b::TB a1) {} };", "a::TA", "b::TB"}, + {"struct F { a::TA a_; };", "struct F { b::TB a_; };", "a::TA", + "b::TB"}, + {"struct F { ptr a_; };", "struct F { ptr a_; };", + "a::TA", "b::TB"}, + {"struct F { ptr a_; };", "struct F { ptr a_; };", + "a::UA", "b::UB"}, + + // types in nested name specifiers + {"void f() { a::TA::Nested ne; }", "void f() { b::TB::Nested ne; }", + "a::TA", "b::TB"}, + {"void f() { a::UA::Nested ne; }", "void f() { b::UB::Nested ne; }", + "a::UA", "b::UB"}, + {"void f() { a::TA::Nested::NestedEnum e; }", + "void f() { b::TB::Nested::NestedEnum e; }", "a::TA", "b::TB"}, + {"void f() { auto e = a::TA::Nested::NestedEnum::E1; }", + "void f() { auto e = b::TB::Nested::NestedEnum::E1; }", "a::TA", + "b::TB"}, + {"void f() { auto e = a::TA::Nested::E1; }", + "void f() { auto e = b::TB::Nested::E1; }", "a::TA", "b::TB"}, + + // templates + {"template struct Foo { T t; }; void f() { Foo " + "foo; }", + "template struct Foo { T t; }; void f() { Foo " + "foo; }", + "a::TA", "b::TB"}, + {"template struct Foo { a::TA a; };", + "template struct Foo { b::TB a; };", "a::TA", "b::TB"}, + {"template void f(T t) {} void g() { f(a::TA()); }", + "template void f(T t) {} void g() { f(b::TB()); }", + "a::TA", "b::TB"}, + {"template void f(T t) {} void g() { f(a::UA()); }", + "template void f(T t) {} void g() { f(b::UB()); }", + "a::UA", "b::UB"}, + {"template int f() { return 1; } template <> int " + "f() { return 2; } int g() { return f(); }", + "template int f() { return 1; } template <> int " + "f() { return 2; } int g() { return f(); }", + "a::TA", "b::TB"}, + {"struct Foo { template T foo(); }; void g() { Foo f; " + "auto a = f.template foo(); }", + "struct Foo { template T foo(); }; void g() { Foo f; " + "auto a = f.template foo(); }", + "a::TA", "b::TB"}, + {"struct Foo { template T foo(); }; void g() { Foo f; " + "auto a = f.template foo(); }", + "struct Foo { template T foo(); }; void g() { Foo f; " + "auto a = f.template foo(); }", + "a::UA", "b::UB"}, + + // The following two templates are distilled from regressions found in + // unique_ptr<> and type_traits.h + {"template struct outer { typedef T type; type Baz(); }; " + "outer g_A;", + "template struct outer { typedef T type; type Baz(); }; " + "outer g_A;", + "a::TA", "b::TB"}, + {"template struct nested { typedef T type; }; template " + " struct outer { typename nested::type Foo(); }; " + "outer g_A;", + "template struct nested { typedef T type; }; template " + " struct outer { typename nested::type Foo(); }; " + "outer g_A;", + "a::TA", "b::TB"}, + + // macros + {"#define FOO(T, t) T t\nvoid f() { FOO(a::TA, a1); FOO(a::TA, a2); }", + "#define FOO(T, t) T t\nvoid f() { FOO(b::TB, a1); FOO(b::TB, a2); }", + "a::TA", "b::TB"}, + {"#define FOO(n) a::TA n\nvoid f() { FOO(a1); FOO(a2); }", + "#define FOO(n) b::TB n\nvoid f() { FOO(a1); FOO(a2); }", "a::TA", + "b::TB"}, + {"#define FOO(n) a::UA n\nvoid f() { FOO(a1); FOO(a2); }", + "#define FOO(n) b::UB n\nvoid f() { FOO(a1); FOO(a2); }", "a::UA", + "b::UB"}, + + // Pointer to member functions + {"auto gA = &a::TA::foo;", "auto gA = &b::TB::foo;", "a::TA", "b::TB"}, + {"using a::TA; auto gA = &TA::foo;", + "using b::TB; auto gA = &b::TB::foo;", "a::TA", "b::TB"}, + {"typedef a::TA T; auto gA = &T::foo;", + "typedef b::TB T; auto gA = &T::foo;", "a::TA", "b::TB"}, + {"auto gA = &MACRO(a::TA)::foo;", "auto gA = &MACRO(b::TB)::foo;", + "a::TA", "b::TB"}, + + // templated using alias. + {"void f(TPtr p) {}", "void f(NewTPtr p) {}", "TPtr", + "NewTPtr"}, + {"void f(::TPtr p) {}", "void f(::NewTPtr p) {}", "TPtr", + "NewTPtr"}, + })), ); + +TEST_P(RenameAliasTest, RenameAlias) { + auto Param = GetParam(); + assert(!Param.OldName.empty()); + assert(!Param.NewName.empty()); + std::string Actual = + runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName); + CompareSnippets(Param.After, Actual); +} + +TEST_F(RenameAliasTest, RenameTypedefDefinitions) { + std::string Before = R"( + class X {}; + typedef X TOld; + )"; + std::string Expected = R"( + class X {}; + typedef X TNew; + )"; + std::string After = runClangRenameOnCode(Before, "TOld", "TNew"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameAliasTest, RenameUsingAliasDefinitions) { + std::string Before = R"( + class X {}; + using UOld = X; + )"; + std::string Expected = R"( + class X {}; + using UNew = X; + )"; + std::string After = runClangRenameOnCode(Before, "UOld", "UNew"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameAliasTest, RenameTemplatedAliasDefinitions) { + std::string Before = R"( + template + class X { T t; }; + + template + using Old = X; + )"; + std::string Expected = R"( + template + class X { T t; }; + + template + using New = X; + )"; + std::string After = runClangRenameOnCode(Before, "Old", "New"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameAliasTest, RenameAliasesInNamespaces) { + std::string Before = R"( + namespace x { class X {}; } + namespace ns { + using UOld = x::X; + } + )"; + std::string Expected = R"( + namespace x { class X {}; } + namespace ns { + using UNew = x::X; + } + )"; + std::string After = runClangRenameOnCode(Before, "ns::UOld", "ns::UNew"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameAliasTest, AliasesInMacros) { + std::string Before = R"( + namespace x { class Old {}; } + namespace ns { + #define REF(alias) alias alias_var; + + #define ALIAS(old) \ + using old##Alias = x::old; \ + REF(old##Alias); + + ALIAS(Old); + + OldAlias old_alias; + } + )"; + std::string Expected = R"( + namespace x { class Old {}; } + namespace ns { + #define REF(alias) alias alias_var; + + #define ALIAS(old) \ + using old##Alias = x::old; \ + REF(old##Alias); + + ALIAS(Old); + + NewAlias old_alias; + } + )"; + std::string After = + runClangRenameOnCode(Before, "ns::OldAlias", "ns::NewAlias"); + CompareSnippets(Expected, After); +} + +} // anonymous namespace +} // namespace test +} // namespace clang_rename +} // namesdpace clang -- cgit v1.2.1