summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/unittests/RenameTests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clangd/unittests/RenameTests.cpp')
-rw-r--r--clang-tools-extra/clangd/unittests/RenameTests.cpp373
1 files changed, 359 insertions, 14 deletions
diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp
index 212d9c089f9..3c3c60500f9 100644
--- a/clang-tools-extra/clangd/unittests/RenameTests.cpp
+++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp
@@ -38,27 +38,27 @@ std::string expectedResult(Annotations Test, llvm::StringRef NewName) {
return Result;
}
-TEST(RenameTest, SingleFile) {
- // "^" points to the position of the rename, and "[[]]" ranges point to the
+TEST(RenameTest, WithinFileRename) {
+ // rename is runnning on all "^" points, and "[[]]" ranges point to the
// identifier that is being renamed.
llvm::StringRef Tests[] = {
- // Rename function.
+ // Function.
R"cpp(
- void [[foo]]() {
+ void [[foo^]]() {
[[fo^o]]();
}
)cpp",
- // Rename type.
+ // Type.
R"cpp(
- struct [[foo]]{};
+ struct [[foo^]] {};
[[foo]] test() {
[[f^oo]] x;
return x;
}
)cpp",
- // Rename variable.
+ // Local variable.
R"cpp(
void bar() {
if (auto [[^foo]] = 5) {
@@ -66,18 +66,313 @@ TEST(RenameTest, SingleFile) {
}
}
)cpp",
+
+ // Rename class, including constructor/destructor.
+ R"cpp(
+ class [[F^oo]] {
+ [[F^oo]]();
+ ~[[Foo]]();
+ void foo(int x);
+ };
+ [[Foo]]::[[Fo^o]]() {}
+ void [[Foo]]::foo(int x) {}
+ )cpp",
+
+ // Class in template argument.
+ R"cpp(
+ class [[F^oo]] {};
+ template <typename T> void func();
+ template <typename T> class Baz {};
+ int main() {
+ func<[[F^oo]]>();
+ Baz<[[F^oo]]> obj;
+ return 0;
+ }
+ )cpp",
+
+ // Forward class declaration without definition.
+ R"cpp(
+ class [[F^oo]];
+ [[Foo]] *f();
+ )cpp",
+
+ // Class methods overrides.
+ R"cpp(
+ struct A {
+ virtual void [[f^oo]]() {}
+ };
+ struct B : A {
+ void [[f^oo]]() override {}
+ };
+ struct C : B {
+ void [[f^oo]]() override {}
+ };
+
+ void func() {
+ A().[[f^oo]]();
+ B().[[f^oo]]();
+ C().[[f^oo]]();
+ }
+ )cpp",
+
+ // Template class (partial) specializations.
+ R"cpp(
+ template <typename T>
+ class [[F^oo]] {};
+
+ template<>
+ class [[F^oo]]<bool> {};
+ template <typename T>
+ class [[F^oo]]<T*> {};
+
+ void test() {
+ [[Foo]]<int> x;
+ [[Foo]]<bool> y;
+ [[Foo]]<int*> z;
+ }
+ )cpp",
+
+ // Template class instantiations.
+ R"cpp(
+ template <typename T>
+ class [[F^oo]] {
+ public:
+ T foo(T arg, T& ref, T* ptr) {
+ T value;
+ int number = 42;
+ value = (T)number;
+ value = static_cast<T>(number);
+ return value;
+ }
+ static void foo(T value) {}
+ T member;
+ };
+
+ template <typename T>
+ void func() {
+ [[F^oo]]<T> obj;
+ obj.member = T();
+ [[Foo]]<T>::foo();
+ }
+
+ void test() {
+ [[F^oo]]<int> i;
+ i.member = 0;
+ [[F^oo]]<int>::foo(0);
+
+ [[F^oo]]<bool> b;
+ b.member = false;
+ [[Foo]]<bool>::foo(false);
+ }
+ )cpp",
+
+ // Template class methods.
+ R"cpp(
+ template <typename T>
+ class A {
+ public:
+ void [[f^oo]]() {}
+ };
+
+ void func() {
+ A<int>().[[f^oo]]();
+ A<double>().[[f^oo]]();
+ A<float>().[[f^oo]]();
+ }
+ )cpp",
+
+ // Complicated class type.
+ R"cpp(
+ // Forward declaration.
+ class [[Fo^o]];
+ class Baz {
+ virtual int getValue() const = 0;
+ };
+
+ class [[F^oo]] : public Baz {
+ public:
+ [[Foo]](int value = 0) : x(value) {}
+
+ [[Foo]] &operator++(int);
+
+ bool operator<([[Foo]] const &rhs);
+ int getValue() const;
+ private:
+ int x;
+ };
+
+ void func() {
+ [[Foo]] *Pointer = 0;
+ [[Foo]] Variable = [[Foo]](10);
+ for ([[Foo]] it; it < Variable; it++);
+ const [[Foo]] *C = new [[Foo]]();
+ const_cast<[[Foo]] *>(C)->getValue();
+ [[Foo]] foo;
+ const Baz &BazReference = foo;
+ const Baz *BazPointer = &foo;
+ dynamic_cast<const [[^Foo]] &>(BazReference).getValue();
+ dynamic_cast<const [[^Foo]] *>(BazPointer)->getValue();
+ reinterpret_cast<const [[^Foo]] *>(BazPointer)->getValue();
+ static_cast<const [[^Foo]] &>(BazReference).getValue();
+ static_cast<const [[^Foo]] *>(BazPointer)->getValue();
+ }
+ )cpp",
+
+ // CXXConstructor initializer list.
+ R"cpp(
+ class Baz {};
+ class Qux {
+ Baz [[F^oo]];
+ public:
+ Qux();
+ };
+ Qux::Qux() : [[F^oo]]() {}
+ )cpp",
+
+ // DeclRefExpr.
+ R"cpp(
+ class C {
+ public:
+ static int [[F^oo]];
+ };
+
+ int foo(int x);
+ #define MACRO(a) foo(a)
+
+ void func() {
+ C::[[F^oo]] = 1;
+ MACRO(C::[[Foo]]);
+ int y = C::[[F^oo]];
+ }
+ )cpp",
+
+ // Macros.
+ R"cpp(
+ // no rename inside macro body.
+ #define M1 foo
+ #define M2(x) x
+ int [[fo^o]]();
+ void boo(int);
+
+ void qoo() {
+ [[foo]]();
+ boo([[foo]]());
+ M1();
+ boo(M1());
+ M2([[foo]]());
+ M2(M1()); // foo is inside the nested macro body.
+ }
+ )cpp",
+
+ // MemberExpr in macros
+ R"cpp(
+ class Baz {
+ public:
+ int [[F^oo]];
+ };
+ int qux(int x);
+ #define MACRO(a) qux(a)
+
+ int main() {
+ Baz baz;
+ baz.[[Foo]] = 1;
+ MACRO(baz.[[Foo]]);
+ int y = baz.[[Foo]];
+ }
+ )cpp",
+
+ // Template parameters.
+ R"cpp(
+ template <typename [[^T]]>
+ class Foo {
+ [[T]] foo([[T]] arg, [[T]]& ref, [[^T]]* ptr) {
+ [[T]] value;
+ int number = 42;
+ value = ([[T]])number;
+ value = static_cast<[[^T]]>(number);
+ return value;
+ }
+ static void foo([[T]] value) {}
+ [[T]] member;
+ };
+ )cpp",
+
+ // Typedef.
+ R"cpp(
+ namespace std {
+ class basic_string {};
+ typedef basic_string [[s^tring]];
+ } // namespace std
+
+ std::[[s^tring]] foo();
+ )cpp",
+
+ // Variable.
+ R"cpp(
+ namespace A {
+ int [[F^oo]];
+ }
+ int Foo;
+ int Qux = Foo;
+ int Baz = A::[[^Foo]];
+ void fun() {
+ struct {
+ int Foo;
+ } b = {100};
+ int Foo = 100;
+ Baz = Foo;
+ {
+ extern int Foo;
+ Baz = Foo;
+ Foo = A::[[F^oo]] + Baz;
+ A::[[Fo^o]] = b.Foo;
+ }
+ Foo = b.Foo;
+ }
+ )cpp",
+
+ // Namespace alias.
+ R"cpp(
+ namespace a { namespace b { void foo(); } }
+ namespace [[^x]] = a::b;
+ void bar() {
+ [[x]]::foo();
+ }
+ )cpp",
+
+ // Scope enums.
+ R"cpp(
+ enum class [[K^ind]] { ABC };
+ void ff() {
+ [[K^ind]] s;
+ s = [[Kind]]::ABC;
+ }
+ )cpp",
+
+ // template class in template argument list.
+ R"cpp(
+ template<typename T>
+ class [[Fo^o]] {};
+ template <template<typename> class Z> struct Bar { };
+ template <> struct Bar<[[Foo]]> {};
+ )cpp",
};
for (const auto T : Tests) {
Annotations Code(T);
auto TU = TestTU::withCode(Code.code());
auto AST = TU.build();
+ EXPECT_TRUE(AST.getDiagnostics().empty())
+ << AST.getDiagnostics().front() << Code.code();
+
llvm::StringRef NewName = "abcde";
- auto RenameResult =
- renameWithinFile(AST, testPath(TU.Filename), Code.point(), NewName);
- ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError();
- auto ApplyResult = llvm::cantFail(
- tooling::applyAllReplacements(Code.code(), *RenameResult));
- EXPECT_EQ(expectedResult(Code, NewName), ApplyResult);
+ for (const auto &RenamePos : Code.points()) {
+ auto RenameResult =
+ renameWithinFile(AST, testPath(TU.Filename), RenamePos, NewName);
+ ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError() << T;
+ auto ApplyResult = llvm::cantFail(
+ tooling::applyAllReplacements(Code.code(), *RenameResult));
+ EXPECT_EQ(expectedResult(Code, NewName), ApplyResult);
+ }
}
}
@@ -148,12 +443,32 @@ TEST(RenameTest, Renameable) {
{R"cpp(// foo is declared outside the file.
void fo^o() {}
- )cpp", "used outside main file", !HeaderFile /*cc file*/, Index},
+ )cpp",
+ "used outside main file", !HeaderFile /*cc file*/, Index},
{R"cpp(
// We should detect the symbol is used outside the file from the AST.
void fo^o() {})cpp",
"used outside main file", !HeaderFile, nullptr /*no index*/},
+
+ {R"cpp(
+ void foo(int);
+ void foo(char);
+ template <typename T> void f(T t) {
+ fo^o(t);
+ })cpp",
+ "multiple symbols", !HeaderFile, nullptr /*no index*/},
+
+ {R"cpp(// disallow rename on unrelated token.
+ cl^ass Foo {};
+ )cpp",
+ "no symbol", !HeaderFile, nullptr},
+
+ {R"cpp(// disallow rename on unrelated token.
+ temp^late<typename T>
+ class Foo {};
+ )cpp",
+ "no symbol", !HeaderFile, nullptr},
};
for (const auto& Case : Cases) {
@@ -191,6 +506,36 @@ TEST(RenameTest, Renameable) {
}
}
+TEST(RenameTest, MainFileReferencesOnly) {
+ // filter out references not from main file.
+ llvm::StringRef Test =
+ R"cpp(
+ void test() {
+ int [[fo^o]] = 1;
+ // rename references not from main file are not included.
+ #include "foo.inc"
+ })cpp";
+
+ Annotations Code(Test);
+ auto TU = TestTU::withCode(Code.code());
+ TU.AdditionalFiles["foo.inc"] = R"cpp(
+ #define Macro(X) X
+ &Macro(foo);
+ &foo;
+ )cpp";
+ auto AST = TU.build();
+ EXPECT_TRUE(AST.getDiagnostics().empty())
+ << AST.getDiagnostics().front() << Code.code();
+ llvm::StringRef NewName = "abcde";
+
+ auto RenameResult =
+ renameWithinFile(AST, testPath(TU.Filename), Code.point(), NewName);
+ ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError() << Code.point();
+ auto ApplyResult =
+ llvm::cantFail(tooling::applyAllReplacements(Code.code(), *RenameResult));
+ EXPECT_EQ(expectedResult(Code, NewName), ApplyResult);
+}
+
} // namespace
} // namespace clangd
} // namespace clang
OpenPOWER on IntegriCloud