[clang-rename] Handle designated initializers.

clang Tooling, and more specifically Refactoring/Rename, have support
code to extract source locations given a Unified Symbol Resolution set.
This support code is used by clang-rename and other tools that might not
be in the tree.

Currently field designated initializer are not supported.
So, renaming S::a to S::b in this code:

  S s = { .a = 10 };

will not extract the field designated initializer for a (the 'a' after the
dot).

This patch adds support for field designated initialized to
RecursiveSymbolVisitor and RenameLocFinder that is used in
createRenameAtomicChanges.

Differential Revision: https://reviews.llvm.org/D100310
This commit is contained in:
Daniele Castagna 2021-04-12 13:15:14 -07:00 committed by Justin Lebar
parent ba62ebc48e
commit 7dd6068899
No known key found for this signature in database
GPG Key ID: 13778D367B90F8BF
3 changed files with 50 additions and 0 deletions

View File

@ -122,6 +122,17 @@ public:
return BaseType::TraverseNestedNameSpecifierLoc(NNS);
}
bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) {
for (const DesignatedInitExpr::Designator &D : E->designators()) {
if (D.isFieldDesignator() && D.getField()) {
const FieldDecl *Decl = D.getField();
if (!visit(Decl, D.getFieldLoc(), D.getFieldLoc()))
return false;
}
}
return true;
}
private:
const SourceManager &SM;
const LangOptions &LangOpts;

View File

@ -226,6 +226,24 @@ public:
return true;
}
bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) {
for (const DesignatedInitExpr::Designator &D : E->designators()) {
if (D.isFieldDesignator() && D.getField()) {
const FieldDecl *Decl = D.getField();
if (isInUSRSet(Decl)) {
auto StartLoc = D.getFieldLoc();
auto EndLoc = D.getFieldLoc();
RenameInfos.push_back({StartLoc, EndLoc,
/*FromDecl=*/nullptr,
/*Context=*/nullptr,
/*Specifier=*/nullptr,
/*IgnorePrefixQualifiers=*/true});
}
}
}
return true;
}
bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
// Fix the constructor initializer when renaming class members.
for (const auto *Initializer : CD->inits()) {

View File

@ -780,6 +780,27 @@ TEST_F(RenameClassTest, UsingAlias) {
CompareSnippets(Expected, After);
}
TEST_F(ClangRenameTest, FieldDesignatedInitializers) {
std::string Before = R"(
struct S {
int a;
};
void foo() {
S s = { .a = 10 };
s.a = 20;
})";
std::string Expected = R"(
struct S {
int b;
};
void foo() {
S s = { .b = 10 };
s.b = 20;
})";
std::string After = runClangRenameOnCode(Before, "S::a", "S::b");
CompareSnippets(Expected, After);
}
// FIXME: investigate why the test fails when adding a new USR to the USRSet.
TEST_F(ClangRenameTest, DISABLED_NestedTemplates) {
std::string Before = R"(