Skip to content

Commit 440ea3e

Browse files
authored
[clangd] Reduce superfluous rename conflicts (#121515)
This commit adds a namespace check to the code for detecting name collisions, allowing `bar` to be renamed to `foo` in the following snippet: ```c typedef struct foo {} Foo; Foo bar; ``` Previously, such a rename would fail because a declaration for `foo` already exists in the same scope.
1 parent 4fd762c commit 440ea3e

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

clang-tools-extra/clangd/refactor/Rename.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,8 @@ const NamedDecl *lookupSiblingWithinEnclosingScope(ASTContext &Ctx,
338338
for (const auto &Child : DS->getDeclGroup())
339339
if (const auto *ND = dyn_cast<NamedDecl>(Child))
340340
if (ND != &RenamedDecl && ND->getDeclName().isIdentifier() &&
341-
ND->getName() == Name)
341+
ND->getName() == Name &&
342+
ND->getIdentifierNamespace() & RenamedDecl.getIdentifierNamespace())
342343
return ND;
343344
return nullptr;
344345
};
@@ -380,7 +381,9 @@ const NamedDecl *lookupSiblingWithinEnclosingScope(ASTContext &Ctx,
380381
// Also check if there is a name collision with function arguments.
381382
if (const auto *Function = ScopeParent->get<FunctionDecl>())
382383
for (const auto *Parameter : Function->parameters())
383-
if (Parameter->getName() == NewName)
384+
if (Parameter->getName() == NewName &&
385+
Parameter->getIdentifierNamespace() &
386+
RenamedDecl.getIdentifierNamespace())
384387
return Parameter;
385388
return nullptr;
386389
}
@@ -405,7 +408,9 @@ const NamedDecl *lookupSiblingWithinEnclosingScope(ASTContext &Ctx,
405408
if (const auto *EnclosingFunction = Parent->get<FunctionDecl>()) {
406409
// Check for conflicts with other arguments.
407410
for (const auto *Parameter : EnclosingFunction->parameters())
408-
if (Parameter != &RenamedDecl && Parameter->getName() == NewName)
411+
if (Parameter != &RenamedDecl && Parameter->getName() == NewName &&
412+
Parameter->getIdentifierNamespace() &
413+
RenamedDecl.getIdentifierNamespace())
409414
return Parameter;
410415
// FIXME: We don't modify all references to function parameters when
411416
// renaming from forward declaration now, so using a name colliding with
@@ -450,7 +455,8 @@ const NamedDecl *lookupSiblingsWithinContext(ASTContext &Ctx,
450455
}
451456
// Lookup may contain the RenameDecl itself, exclude it.
452457
for (const auto *D : LookupResult)
453-
if (D->getCanonicalDecl() != RenamedDecl.getCanonicalDecl())
458+
if (D->getCanonicalDecl() != RenamedDecl.getCanonicalDecl() &&
459+
D->getIdentifierNamespace() & RenamedDecl.getIdentifierNamespace())
454460
return D;
455461
return nullptr;
456462
}

clang-tools-extra/clangd/unittests/RenameTests.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,39 @@ TEST(RenameTest, Renameable) {
12691269
)cpp",
12701270
"conflict", !HeaderFile, "Conflict"},
12711271

1272+
{R"cpp(
1273+
struct conflict {};
1274+
enum v^ar {};
1275+
)cpp",
1276+
"conflict", !HeaderFile, "conflict"},
1277+
1278+
{R"cpp(
1279+
struct conflict {};
1280+
int [[v^ar]];
1281+
)cpp",
1282+
nullptr, !HeaderFile, "conflict"},
1283+
1284+
{R"cpp(
1285+
enum conflict {};
1286+
int [[v^ar]];
1287+
)cpp",
1288+
nullptr, !HeaderFile, "conflict"},
1289+
1290+
{R"cpp(
1291+
void func(int conflict) {
1292+
struct [[t^ag]] {};
1293+
}
1294+
)cpp",
1295+
nullptr, !HeaderFile, "conflict"},
1296+
1297+
{R"cpp(
1298+
void func(void) {
1299+
struct conflict {};
1300+
int [[v^ar]];
1301+
}
1302+
)cpp",
1303+
nullptr, !HeaderFile, "conflict"},
1304+
12721305
{R"cpp(
12731306
void func(int);
12741307
void [[o^therFunc]](double);

0 commit comments

Comments
 (0)