Skip to content

[include-cleaner] Use FoundDecl only for using-shadow-decls #82615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang-tools-extra/include-cleaner/lib/WalkAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {

bool VisitDeclRefExpr(DeclRefExpr *DRE) {
auto *FD = DRE->getFoundDecl();
// Prefer the underlying decl if FoundDecl isn't a shadow decl, e.g:
// - For templates, found-decl is always primary template, but we want the
// specializaiton itself.
if (!llvm::isa<UsingShadowDecl>(FD))
FD = DRE->getDecl();
// For refs to non-meber-like decls, use the found decl.
// For member-like decls, we should have a reference from the qualifier to
// the container decl instead, which is preferred as it'll handle
Expand Down
34 changes: 19 additions & 15 deletions clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,24 +200,26 @@ TEST(WalkAST, VarTemplates) {
EXPECT_THAT(testWalk(R"cpp(
template <typename T> T $explicit^Foo = 0;)cpp",
"int z = ^Foo<int>;"),
ElementsAre(Decl::VarTemplate));
ElementsAre(Decl::VarTemplateSpecialization));
EXPECT_THAT(testWalk(R"cpp(
template<typename T> T $explicit^Foo = 0;
template<> int Foo<int> = 1;)cpp",
template<typename T> T Foo = 0;
template<> int $explicit^Foo<int> = 1;)cpp",
"int x = ^Foo<int>;"),
ElementsAre(Decl::VarTemplate));
ElementsAre(Decl::VarTemplateSpecialization));
// FIXME: This points at implicit specialization, instead we should point to
// explicit partial specializaiton pattern.
EXPECT_THAT(testWalk(R"cpp(
template<typename T> T $explicit^Foo = 0;
template<typename T> T* Foo<T*> = nullptr;)cpp",
template<typename T> T Foo = 0;
template<typename T> T* $explicit^Foo<T*> = nullptr;)cpp",
"int *x = ^Foo<int *>;"),
ElementsAre(Decl::VarTemplate));
ElementsAre(Decl::VarTemplateSpecialization));
// Implicit specializations through explicit instantiations has source
// locations pointing at the primary template.
EXPECT_THAT(testWalk(R"cpp(
template<typename T> T $explicit^Foo = 0;
template int Foo<int>;)cpp",
"int x = ^Foo<int>;"),
ElementsAre(Decl::VarTemplate));
ElementsAre(Decl::VarTemplateSpecialization));
}
TEST(WalkAST, FunctionTemplates) {
// Explicit instantiation and (partial) specialization references primary
Expand All @@ -239,18 +241,19 @@ TEST(WalkAST, FunctionTemplates) {
EXPECT_THAT(testWalk(R"cpp(
template <typename T> void $explicit^foo() {})cpp",
"auto x = []{ ^foo<int>(); };"),
ElementsAre(Decl::FunctionTemplate));
// FIXME: DeclRefExpr points at primary template, not the specialization.
ElementsAre(Decl::Function));
EXPECT_THAT(testWalk(R"cpp(
template<typename T> void $explicit^foo() {}
template<> void foo<int>(){})cpp",
template<typename T> void foo() {}
template<> void $explicit^foo<int>(){})cpp",
"auto x = []{ ^foo<int>(); };"),
ElementsAre(Decl::FunctionTemplate));
ElementsAre(Decl::Function));
// The decl is actually the specialization, but explicit instantations point
// at the primary template.
EXPECT_THAT(testWalk(R"cpp(
template<typename T> void $explicit^foo() {};
template void foo<int>();)cpp",
"auto x = [] { ^foo<int>(); };"),
ElementsAre(Decl::FunctionTemplate));
ElementsAre(Decl::Function));
}
TEST(WalkAST, TemplateSpecializationsFromUsingDecl) {
// Class templates
Expand Down Expand Up @@ -548,7 +551,8 @@ TEST(WalkAST, Concepts) {
testWalk(Concept, "template<typename T> void func() requires ^Foo<T> {}");
testWalk(Concept, "void func(^Foo auto x) {}");
// FIXME: Foo should be explicitly referenced.
testWalk("template<typename T> concept Foo = true;", "void func() { ^Foo auto x = 1; }");
testWalk("template<typename T> concept Foo = true;",
"void func() { ^Foo auto x = 1; }");
}

TEST(WalkAST, FriendDecl) {
Expand Down