Skip to content

Commit

Permalink
[clangd] Add support for within-file rename of complicated fields
Browse files Browse the repository at this point in the history
This was originally a part of D71880 but is separated for simplicity and ease
of reviewing.

Fixes: clangd/clangd#582

Reviewed By: hokein

Differential Revision: https://reviews.llvm.org/D91952
  • Loading branch information
kirillbobyrev committed Nov 27, 2020
1 parent 4d83aba commit abfcb60
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
22 changes: 22 additions & 0 deletions clang-tools-extra/clangd/refactor/Rename.cpp
Expand Up @@ -124,6 +124,28 @@ const NamedDecl *canonicalRenameDecl(const NamedDecl *D) {
if (const auto *Function = dyn_cast<FunctionDecl>(D))
if (const FunctionTemplateDecl *Template = Function->getPrimaryTemplate())
return canonicalRenameDecl(Template);
if (const auto *Field = dyn_cast<FieldDecl>(D)) {
// This is a hacky way to do something like
// CXXMethodDecl::getInstantiatedFromMemberFunction for the field because
// Clang AST does not store relevant information about the field that is
// instantiated.
const auto *FieldParent = dyn_cast<CXXRecordDecl>(Field->getParent());
if (!FieldParent)
return Field->getCanonicalDecl();
FieldParent = FieldParent->getTemplateInstantiationPattern();
// Field is not instantiation.
if (!FieldParent || Field->getParent() == FieldParent)
return Field->getCanonicalDecl();
for (const FieldDecl *Candidate : FieldParent->fields())
if (Field->getDeclName() == Candidate->getDeclName())
return Candidate->getCanonicalDecl();
elog("FieldParent should have field with the same name as Field.");
}
if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (const VarDecl *OriginalVD = VD->getInstantiatedFromStaticDataMember())
VD = OriginalVD;
return VD->getCanonicalDecl();
}
return dyn_cast<NamedDecl>(D->getCanonicalDecl());
}

Expand Down
88 changes: 88 additions & 0 deletions clang-tools-extra/clangd/unittests/RenameTests.cpp
Expand Up @@ -540,6 +540,94 @@ TEST(RenameTest, WithinFileRename) {
}
)cpp",

// Fields in classes & partial and full specialiations.
R"cpp(
template<typename T>
struct Foo {
T [[Vari^able]] = 42;
};
void foo() {
Foo<int> f;
f.[[Varia^ble]] = 9000;
}
)cpp",
R"cpp(
template<typename T, typename U>
struct Foo {
T Variable[42];
U Another;
void bar() {}
};
template<typename T>
struct Foo<T, bool> {
T [[Var^iable]];
void bar() { ++[[Var^iable]]; }
};
void foo() {
Foo<unsigned, bool> f;
f.[[Var^iable]] = 9000;
}
)cpp",
R"cpp(
template<typename T, typename U>
struct Foo {
T Variable[42];
U Another;
void bar() {}
};
template<typename T>
struct Foo<T, bool> {
T Variable;
void bar() { ++Variable; }
};
template<>
struct Foo<unsigned, bool> {
unsigned [[Var^iable]];
void bar() { ++[[Var^iable]]; }
};
void foo() {
Foo<unsigned, bool> f;
f.[[Var^iable]] = 9000;
}
)cpp",
// Static fields.
R"cpp(
struct Foo {
static int [[Var^iable]];
};
int Foo::[[Var^iable]] = 42;
void foo() {
int LocalInt = Foo::[[Var^iable]];
}
)cpp",
R"cpp(
template<typename T>
struct Foo {
static T [[Var^iable]];
};
template <>
int Foo<int>::[[Var^iable]] = 42;
template <>
bool Foo<bool>::[[Var^iable]] = true;
void foo() {
int LocalInt = Foo<int>::[[Var^iable]];
bool LocalBool = Foo<bool>::[[Var^iable]];
}
)cpp",

// Template parameters.
R"cpp(
template <typename [[^T]]>
Expand Down

0 comments on commit abfcb60

Please sign in to comment.