summaryrefslogtreecommitdiffstats
path: root/unittests
diff options
context:
space:
mode:
authorHaojian Wu <hokein@google.com>2017-10-16 10:37:42 +0000
committerHaojian Wu <hokein@google.com>2017-10-16 10:37:42 +0000
commitc49d6ee8203dd3376433a2c928dea15000073a8b (patch)
treed387e1463316ab51a9abaf9420d093b0a3dc9718 /unittests
parente58dc968a14ca674924e078b9ec8bb73dc2ef07b (diff)
[clang-rename] Add function unit tests.
Summary: Also contain a fix: * Fix a false positive of renaming a using shadow function declaration. Reviewers: ioeric Reviewed By: ioeric Subscribers: klimek, mgorny, cfe-commits Differential Revision: https://reviews.llvm.org/D38882 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@315898 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests')
-rw-r--r--unittests/Rename/CMakeLists.txt1
-rw-r--r--unittests/Rename/RenameClassTest.cpp1
-rw-r--r--unittests/Rename/RenameFunctionTest.cpp555
3 files changed, 557 insertions, 0 deletions
diff --git a/unittests/Rename/CMakeLists.txt b/unittests/Rename/CMakeLists.txt
index aa7609260c..763ba3b3b0 100644
--- a/unittests/Rename/CMakeLists.txt
+++ b/unittests/Rename/CMakeLists.txt
@@ -7,6 +7,7 @@ include_directories(${CLANG_SOURCE_DIR})
add_clang_unittest(ClangRenameTests
RenameClassTest.cpp
+ RenameFunctionTest.cpp
)
target_link_libraries(ClangRenameTests
diff --git a/unittests/Rename/RenameClassTest.cpp b/unittests/Rename/RenameClassTest.cpp
index f46126dff6..5845d63412 100644
--- a/unittests/Rename/RenameClassTest.cpp
+++ b/unittests/Rename/RenameClassTest.cpp
@@ -51,6 +51,7 @@ INSTANTIATE_TEST_CASE_P(
testing::ValuesIn(std::vector<Case>({
// basic classes
{"a::Foo f;", "b::Bar f;", "", ""},
+ {"::a::Foo f;", "::b::Bar f;", "", ""},
{"void f(a::Foo f) {}", "void f(b::Bar f) {}", "", ""},
{"void f(a::Foo *f) {}", "void f(b::Bar *f) {}", "", ""},
{"a::Foo f() { return a::Foo(); }", "b::Bar f() { return b::Bar(); }",
diff --git a/unittests/Rename/RenameFunctionTest.cpp b/unittests/Rename/RenameFunctionTest.cpp
new file mode 100644
index 0000000000..ef84b4bdb7
--- /dev/null
+++ b/unittests/Rename/RenameFunctionTest.cpp
@@ -0,0 +1,555 @@
+//===-- RenameFunctionTest.cpp - unit tests for renaming functions --------===//
+//
+// 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 RenameFunctionTest : public ClangRenameTest {
+public:
+ RenameFunctionTest() {
+ AppendToHeader(R"(
+ struct A {
+ static bool Foo();
+ static bool Spam();
+ };
+ struct B {
+ static void Same();
+ static bool Foo();
+ static int Eric(int x);
+ };
+ void Same(int x);
+ int Eric(int x);
+ namespace base {
+ void Same();
+ void ToNanoSeconds();
+ void ToInt64NanoSeconds();
+ })");
+ }
+};
+
+TEST_F(RenameFunctionTest, RefactorsAFoo) {
+ std::string Before = R"(
+ void f() {
+ A::Foo();
+ ::A::Foo();
+ })";
+ std::string Expected = R"(
+ void f() {
+ A::Bar();
+ ::A::Bar();
+ })";
+
+ std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RefactorsNonCallingAFoo) {
+ std::string Before = R"(
+ bool g(bool (*func)()) {
+ return func();
+ }
+ void f() {
+ auto *ref1 = A::Foo;
+ auto *ref2 = ::A::Foo;
+ g(A::Foo);
+ })";
+ std::string Expected = R"(
+ bool g(bool (*func)()) {
+ return func();
+ }
+ void f() {
+ auto *ref1 = A::Bar;
+ auto *ref2 = ::A::Bar;
+ g(A::Bar);
+ })";
+ std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RefactorsEric) {
+ std::string Before = R"(
+ void f() {
+ if (Eric(3)==4) ::Eric(2);
+ })";
+ std::string Expected = R"(
+ void f() {
+ if (Larry(3)==4) ::Larry(2);
+ })";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RefactorsNonCallingEric) {
+ std::string Before = R"(
+ int g(int (*func)(int)) {
+ return func(1);
+ }
+ void f() {
+ auto *ref = ::Eric;
+ g(Eric);
+ })";
+ std::string Expected = R"(
+ int g(int (*func)(int)) {
+ return func(1);
+ }
+ void f() {
+ auto *ref = ::Larry;
+ g(Larry);
+ })";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, DoesNotRefactorBFoo) {
+ std::string Before = R"(
+ void f() {
+ B::Foo();
+ })";
+ std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
+ CompareSnippets(Before, After);
+}
+
+TEST_F(RenameFunctionTest, DoesNotRefactorBEric) {
+ std::string Before = R"(
+ void f() {
+ B::Eric(2);
+ })";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Before, After);
+}
+
+TEST_F(RenameFunctionTest, DoesNotRefactorCEric) {
+ std::string Before = R"(
+ namespace C { int Eric(int x); }
+ void f() {
+ if (C::Eric(3)==4) ::C::Eric(2);
+ })";
+ std::string Expected = R"(
+ namespace C { int Eric(int x); }
+ void f() {
+ if (C::Eric(3)==4) ::C::Eric(2);
+ })";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, DoesNotRefactorEricInNamespaceC) {
+ std::string Before = R"(
+ namespace C {
+ int Eric(int x);
+ void f() {
+ if (Eric(3)==4) Eric(2);
+ }
+ } // namespace C)";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Before, After);
+}
+
+TEST_F(RenameFunctionTest, NamespaceQualified) {
+ std::string Before = R"(
+ void f() {
+ base::ToNanoSeconds();
+ ::base::ToNanoSeconds();
+ }
+ void g() {
+ using base::ToNanoSeconds;
+ base::ToNanoSeconds();
+ ::base::ToNanoSeconds();
+ ToNanoSeconds();
+ }
+ namespace foo {
+ namespace base {
+ void ToNanoSeconds();
+ void f() {
+ base::ToNanoSeconds();
+ }
+ }
+ void f() {
+ ::base::ToNanoSeconds();
+ }
+ })";
+ std::string Expected = R"(
+ void f() {
+ base::ToInt64NanoSeconds();
+ ::base::ToInt64NanoSeconds();
+ }
+ void g() {
+ using base::ToInt64NanoSeconds;
+ base::ToInt64NanoSeconds();
+ ::base::ToInt64NanoSeconds();
+ base::ToInt64NanoSeconds();
+ }
+ namespace foo {
+ namespace base {
+ void ToNanoSeconds();
+ void f() {
+ base::ToNanoSeconds();
+ }
+ }
+ void f() {
+ ::base::ToInt64NanoSeconds();
+ }
+ })";
+ std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds",
+ "base::ToInt64NanoSeconds");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RenameFunctionDecls) {
+ std::string Before = R"(
+ namespace na {
+ void X();
+ void X() {}
+ })";
+ std::string Expected = R"(
+ namespace na {
+ void Y();
+ void Y() {}
+ })";
+ std::string After = runClangRenameOnCode(Before, "na::X", "na::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RenameOutOfLineFunctionDecls) {
+ std::string Before = R"(
+ namespace na {
+ void X();
+ }
+ void na::X() {}
+ )";
+ std::string Expected = R"(
+ namespace na {
+ void Y();
+ }
+ void na::Y() {}
+ )";
+ std::string After = runClangRenameOnCode(Before, "na::X", "na::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, NewNamespaceWithoutLeadingDotDot) {
+ std::string Before = R"(
+ namespace old_ns {
+ void X();
+ void X() {}
+ }
+ // Assume that the reference is in another file.
+ void f() { old_ns::X(); }
+ namespace old_ns { void g() { X(); } }
+ namespace new_ns { void h() { ::old_ns::X(); } }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ void Y();
+ void Y() {}
+ }
+ // Assume that the reference is in another file.
+ void f() { new_ns::Y(); }
+ namespace old_ns { void g() { new_ns::Y(); } }
+ namespace new_ns { void h() { Y(); } }
+ )";
+ std::string After = runClangRenameOnCode(Before, "::old_ns::X", "new_ns::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, NewNamespaceWithLeadingDotDot) {
+ std::string Before = R"(
+ namespace old_ns {
+ void X();
+ void X() {}
+ }
+ // Assume that the reference is in another file.
+ void f() { old_ns::X(); }
+ namespace old_ns { void g() { X(); } }
+ namespace new_ns { void h() { ::old_ns::X(); } }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ void Y();
+ void Y() {}
+ }
+ // Assume that the reference is in another file.
+ void f() { ::new_ns::Y(); }
+ namespace old_ns { void g() { ::new_ns::Y(); } }
+ namespace new_ns { void h() { Y(); } }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::old_ns::X", "::new_ns::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, DontRenameSymbolsDefinedInAnonymousNamespace) {
+ std::string Before = R"(
+ namespace old_ns {
+ class X {};
+ namespace {
+ void X();
+ void X() {}
+ void f() { X(); }
+ }
+ }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ class Y {};
+ namespace {
+ void X();
+ void X() {}
+ void f() { X(); }
+ }
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, NewNestedNamespace) {
+ std::string Before = R"(
+ namespace old_ns {
+ void X();
+ void X() {}
+ }
+ // Assume that the reference is in another file.
+ namespace old_ns {
+ void f() { X(); }
+ }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ void X();
+ void X() {}
+ }
+ // Assume that the reference is in another file.
+ namespace old_ns {
+ void f() { older_ns::X(); }
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::older_ns::X");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithoutLeadingDotDot) {
+ std::string Before = R"(
+ void X();
+ void X() {}
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ void f() { X(); }
+ }
+ )";
+ std::string Expected = R"(
+ void X();
+ void X() {}
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ void f() { ns::X(); }
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::X", "ns::X");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithLeadingDotDot) {
+ std::string Before = R"(
+ void Y() {}
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ void f() { Y(); }
+ }
+ )";
+ std::string Expected = R"(
+ void Y() {}
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ void f() { ::ns::Y(); }
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::Y", "::ns::Y");
+ CompareSnippets(Expected, After);
+}
+
+// FIXME: the rename of overloaded operator is not fully supported yet.
+TEST_F(RenameFunctionTest, DISABLED_DoNotRenameOverloadedOperatorCalls) {
+ std::string Before = R"(
+ namespace old_ns {
+ class T { public: int x; };
+ bool operator==(const T& lhs, const T& rhs) {
+ return lhs.x == rhs.x;
+ }
+ } // namespace old_ns
+
+ // Assume that the reference is in another file.
+ bool f() {
+ auto eq = old_ns::operator==;
+ old_ns::T t1, t2;
+ old_ns::operator==(t1, t2);
+ return t1 == t2;
+ }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ class T { public: int x; };
+ bool operator==(const T& lhs, const T& rhs) {
+ return lhs.x == rhs.x;
+ }
+ } // namespace old_ns
+
+ // Assume that the reference is in another file.
+ bool f() {
+ auto eq = new_ns::operator==;
+ old_ns::T t1, t2;
+ new_ns::operator==(t1, t2);
+ return t1 == t2;
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "old_ns::operator==", "new_ns::operator==");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, FunctionRefAsTemplate) {
+ std::string Before = R"(
+ void X();
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ template <void (*Func)(void)>
+ class TIterator {};
+
+ template <void (*Func)(void)>
+ class T {
+ public:
+ typedef TIterator<Func> IterType;
+ using TI = TIterator<Func>;
+ void g() {
+ Func();
+ auto func = Func;
+ TIterator<Func> iter;
+ }
+ };
+
+
+ void f() { T<X> tx; tx.g(); }
+ } // namespace some_ns
+ )";
+ std::string Expected = R"(
+ void X();
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ template <void (*Func)(void)>
+ class TIterator {};
+
+ template <void (*Func)(void)>
+ class T {
+ public:
+ typedef TIterator<Func> IterType;
+ using TI = TIterator<Func>;
+ void g() {
+ Func();
+ auto func = Func;
+ TIterator<Func> iter;
+ }
+ };
+
+
+ void f() { T<ns::X> tx; tx.g(); }
+ } // namespace some_ns
+ )";
+ std::string After = runClangRenameOnCode(Before, "::X", "ns::X");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RenameFunctionInUsingDecl) {
+ std::string Before = R"(
+ using base::ToNanoSeconds;
+ namespace old_ns {
+ using base::ToNanoSeconds;
+ void f() {
+ using base::ToNanoSeconds;
+ }
+ }
+ )";
+ std::string Expected = R"(
+ using base::ToInt64NanoSeconds;
+ namespace old_ns {
+ using base::ToInt64NanoSeconds;
+ void f() {
+ using base::ToInt64NanoSeconds;
+ }
+ }
+ )";
+ std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds",
+ "base::ToInt64NanoSeconds");
+ CompareSnippets(Expected, After);
+}
+
+// FIXME: Fix the complex the case where the symbol being renamed is located in
+// `std::function<decltype<renamed_symbol>>`.
+TEST_F(ClangRenameTest, DISABLED_ReferencesInLambdaFunctionParameters) {
+ std::string Before = R"(
+ template <class T>
+ class function;
+ template <class R, class... ArgTypes>
+ class function<R(ArgTypes...)> {
+ public:
+ template <typename Functor>
+ function(Functor f) {}
+
+ function() {}
+
+ R operator()(ArgTypes...) const {}
+ };
+
+ namespace ns {
+ void Old() {}
+ void f() {
+ function<decltype(Old)> func;
+ }
+ } // namespace ns)";
+ std::string Expected = R"(
+ template <class T>
+ class function;
+ template <class R, class... ArgTypes>
+ class function<R(ArgTypes...)> {
+ public:
+ template <typename Functor>
+ function(Functor f) {}
+
+ function() {}
+
+ R operator()(ArgTypes...) const {}
+ };
+
+ namespace ns {
+ void New() {}
+ void f() {
+ function<decltype(::new_ns::New)> func;
+ }
+ } // namespace ns)";
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
+ CompareSnippets(Expected, After);
+}
+
+} // anonymous namespace
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang