forked from OSchip/llvm-project
[clangd] Add support for within-file rename of complicated fields
This was originally a part of D71880 but is separated for simplicity and ease of reviewing. Fixes: https://github.com/clangd/clangd/issues/582 Reviewed By: hokein Differential Revision: https://reviews.llvm.org/D91952
This commit is contained in:
parent
4d83aba422
commit
abfcb606c2
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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]]>
|
||||
|
|
Loading…
Reference in New Issue