[include-cleaner] Report refs for enum constants used through namespace aliases (#106706)

This commit is contained in:
kadir çetinkaya
2024-09-02 14:16:49 +02:00
committed by GitHub
parent 224112f833
commit 60ed1043d7
2 changed files with 26 additions and 4 deletions

View File

@@ -15,6 +15,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
@@ -23,9 +24,11 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang::include_cleaner {
namespace {
@@ -125,6 +128,24 @@ public:
return true;
}
bool qualifierIsNamespaceOrNone(DeclRefExpr *DRE) {
const auto *Qual = DRE->getQualifier();
if (!Qual)
return true;
switch (Qual->getKind()) {
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
return true;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::Super:
case NestedNameSpecifier::Identifier:
return false;
}
llvm_unreachable("Unknown value for NestedNameSpecifierKind");
}
bool VisitDeclRefExpr(DeclRefExpr *DRE) {
auto *FD = DRE->getFoundDecl();
// Prefer the underlying decl if FoundDecl isn't a shadow decl, e.g:
@@ -146,10 +167,8 @@ public:
//
// If it's an enum constant, it must be due to prior decl. Report references
// to it when qualifier isn't a type.
if (llvm::isa<EnumConstantDecl>(FD)) {
if (!DRE->getQualifier() || DRE->getQualifier()->getAsNamespace())
report(DRE->getLocation(), FD);
}
if (llvm::isa<EnumConstantDecl>(FD) && qualifierIsNamespaceOrNone(DRE))
report(DRE->getLocation(), FD);
return true;
}

View File

@@ -534,6 +534,9 @@ TEST(WalkAST, Enums) {
testWalk(R"(namespace ns { enum E { A = 42 }; }
struct S { using ns::E::A; };)",
"int e = S::^A;");
testWalk(R"(namespace ns { enum E { $explicit^A = 42 }; })",
"namespace z = ns; int e = z::^A;");
testWalk(R"(enum E { $explicit^A = 42 };)", "int e = ::^A;");
}
TEST(WalkAST, InitializerList) {