Skip to content

Commit 2eaf6f9

Browse files
committed
[AST] Preserve more structure in UsingEnumDecl node.
- store NestedNameSpecifier & Loc for the qualifiers This information was entirely missing from the AST. - expose the location information for qualifier/identifier/typedefs as typeloc This allows many traversals/astmatchers etc to handle these generically along with other references. The decl vs type split can help preserve typedef sugar when llvm#57659 is resolved. - fix the SourceRange of UsingEnumDecl to include 'using'. Fixes clangd/clangd#1283 Differential Revision: https://reviews.llvm.org/D134303
1 parent 20be96b commit 2eaf6f9

File tree

15 files changed

+124
-30
lines changed

15 files changed

+124
-30
lines changed

clang-tools-extra/clangd/FindTarget.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,12 @@ llvm::SmallVector<ReferenceLoc> refInDecl(const Decl *D,
629629
DeclRelation::Underlying, Resolver)});
630630
}
631631

632+
void VisitUsingEnumDecl(const UsingEnumDecl *D) {
633+
// "using enum ns::E" is a non-declaration reference.
634+
// The reference is covered by the embedded typeloc.
635+
// Don't use the default VisitNamedDecl, which would report a declaration.
636+
}
637+
632638
void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
633639
// For namespace alias, "namespace Foo = Target;", we add two references.
634640
// Add a declaration reference for Foo.

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,15 @@ TEST_F(FindExplicitReferencesTest, All) {
12671267
)cpp",
12681268
"0: targets = {ns}\n"
12691269
"1: targets = {ns::global}, qualifier = 'ns::'\n"},
1270+
// Using enum declarations.
1271+
{R"cpp(
1272+
namespace ns { enum class A {}; }
1273+
void foo() {
1274+
using enum $0^ns::$1^A;
1275+
}
1276+
)cpp",
1277+
"0: targets = {ns}\n"
1278+
"1: targets = {ns::A}, qualifier = 'ns::'\n"},
12701279
// Simple types.
12711280
{R"cpp(
12721281
struct Struct { int a; };

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,33 @@ TEST(SelectionTest, CommonAncestor) {
531531
void func() { [[__^func__]]; }
532532
)cpp",
533533
"PredefinedExpr"},
534+
535+
// using enum
536+
{R"cpp(
537+
namespace ns { enum class A {}; };
538+
using enum ns::[[^A]];
539+
)cpp",
540+
"EnumTypeLoc"},
541+
{R"cpp(
542+
namespace ns { enum class A {}; using B = A; };
543+
using enum ns::[[^B]];
544+
)cpp",
545+
"TypedefTypeLoc"},
546+
{R"cpp(
547+
namespace ns { enum class A {}; };
548+
using enum [[^ns::]]A;
549+
)cpp",
550+
"NestedNameSpecifierLoc"},
551+
{R"cpp(
552+
namespace ns { enum class A {}; };
553+
[[using ^enum ns::A]];
554+
)cpp",
555+
"UsingEnumDecl"},
556+
{R"cpp(
557+
namespace ns { enum class A {}; };
558+
[[^using enum ns::A]];
559+
)cpp",
560+
"UsingEnumDecl"},
534561
};
535562

536563
for (const Case &C : Cases) {
@@ -541,6 +568,7 @@ TEST(SelectionTest, CommonAncestor) {
541568
TU.Code = std::string(Test.code());
542569

543570
TU.ExtraArgs.push_back("-xobjective-c++");
571+
TU.ExtraArgs.push_back("-std=c++20");
544572

545573
auto AST = TU.build();
546574
auto T = makeSelectionTree(C.Code, AST);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,14 @@ sizeof...($TemplateParameter[[Elements]]);
828828
typedef int $Primitive_decl[[MyTypedef]];
829829
enum $Enum_decl[[MyEnum]] : $Primitive[[MyTypedef]] {};
830830
)cpp",
831+
// Using enum
832+
R"cpp(
833+
enum class $Enum_decl[[Color]] { $EnumConstant_decl_readonly[[Black]] };
834+
namespace $Namespace_decl[[ns]] {
835+
using enum $Enum[[Color]];
836+
$Enum[[Color]] $Variable_decl[[ModelT]] = $EnumConstant[[Black]];
837+
}
838+
)cpp",
831839
// Issue 1096
832840
R"cpp(
833841
void $Function_decl[[Foo]]();

clang/include/clang/AST/DeclCXX.h

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3614,17 +3614,15 @@ class ConstructorUsingShadowDecl final : public UsingShadowDecl {
36143614
class UsingEnumDecl : public BaseUsingDecl, public Mergeable<UsingEnumDecl> {
36153615
/// The source location of the 'using' keyword itself.
36163616
SourceLocation UsingLocation;
3617-
3618-
/// Location of the 'enum' keyword.
3617+
/// The source location of the 'enum' keyword.
36193618
SourceLocation EnumLocation;
3620-
3621-
/// The enum
3622-
EnumDecl *Enum;
3619+
/// 'qual::SomeEnum' as an EnumType, possibly with Elaborated/Typedef sugar.
3620+
TypeSourceInfo *EnumType;
36233621

36243622
UsingEnumDecl(DeclContext *DC, DeclarationName DN, SourceLocation UL,
3625-
SourceLocation EL, SourceLocation NL, EnumDecl *ED)
3626-
: BaseUsingDecl(UsingEnum, DC, NL, DN), UsingLocation(UL),
3627-
EnumLocation(EL), Enum(ED) {}
3623+
SourceLocation EL, SourceLocation NL, TypeSourceInfo *EnumType)
3624+
: BaseUsingDecl(UsingEnum, DC, NL, DN), UsingLocation(UL), EnumLocation(EL),
3625+
EnumType(EnumType){}
36283626

36293627
void anchor() override;
36303628

@@ -3639,13 +3637,29 @@ class UsingEnumDecl : public BaseUsingDecl, public Mergeable<UsingEnumDecl> {
36393637
/// The source location of the 'enum' keyword.
36403638
SourceLocation getEnumLoc() const { return EnumLocation; }
36413639
void setEnumLoc(SourceLocation L) { EnumLocation = L; }
3640+
NestedNameSpecifier *getQualifier() const {
3641+
return getQualifierLoc().getNestedNameSpecifier();
3642+
}
3643+
NestedNameSpecifierLoc getQualifierLoc() const {
3644+
if (auto ETL = EnumType->getTypeLoc().getAs<ElaboratedTypeLoc>())
3645+
return ETL.getQualifierLoc();
3646+
return NestedNameSpecifierLoc();
3647+
}
3648+
// Returns the "qualifier::Name" part as a TypeLoc.
3649+
TypeLoc getEnumTypeLoc() const {
3650+
return EnumType->getTypeLoc();
3651+
}
3652+
TypeSourceInfo *getEnumType() const {
3653+
return EnumType;
3654+
}
3655+
void setEnumType(TypeSourceInfo *TSI) { EnumType = TSI; }
36423656

36433657
public:
3644-
EnumDecl *getEnumDecl() const { return Enum; }
3658+
EnumDecl *getEnumDecl() const { return cast<EnumDecl>(EnumType->getType()->getAsTagDecl()); }
36453659

36463660
static UsingEnumDecl *Create(ASTContext &C, DeclContext *DC,
36473661
SourceLocation UsingL, SourceLocation EnumL,
3648-
SourceLocation NameL, EnumDecl *ED);
3662+
SourceLocation NameL, TypeSourceInfo *EnumType);
36493663

36503664
static UsingEnumDecl *CreateDeserialized(ASTContext &C, unsigned ID);
36513665

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1724,7 +1724,8 @@ DEF_TRAVERSE_DECL(UsingDecl, {
17241724
TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
17251725
})
17261726

1727-
DEF_TRAVERSE_DECL(UsingEnumDecl, {})
1727+
DEF_TRAVERSE_DECL(UsingEnumDecl,
1728+
{ TRY_TO(TraverseTypeLoc(D->getEnumTypeLoc())); })
17281729

17291730
DEF_TRAVERSE_DECL(UsingPackDecl, {})
17301731

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6119,7 +6119,8 @@ class Sema final {
61196119
NamedDecl *BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
61206120
SourceLocation UsingLoc,
61216121
SourceLocation EnumLoc,
6122-
SourceLocation NameLoc, EnumDecl *ED);
6122+
SourceLocation NameLoc,
6123+
TypeSourceInfo *EnumType, EnumDecl *ED);
61236124
NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom,
61246125
ArrayRef<NamedDecl *> Expansions);
61256126

clang/lib/AST/ASTImporter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4870,13 +4870,14 @@ ExpectedDecl ASTNodeImporter::VisitUsingEnumDecl(UsingEnumDecl *D) {
48704870
Error Err = Error::success();
48714871
auto ToUsingLoc = importChecked(Err, D->getUsingLoc());
48724872
auto ToEnumLoc = importChecked(Err, D->getEnumLoc());
4873-
auto ToEnumDecl = importChecked(Err, D->getEnumDecl());
4873+
auto ToNameLoc = importChecked(Err, D->getLocation());
4874+
auto *ToEnumType = importChecked(Err, D->getEnumType());
48744875
if (Err)
48754876
return std::move(Err);
48764877

48774878
UsingEnumDecl *ToUsingEnum;
48784879
if (GetImportedOrCreateDecl(ToUsingEnum, D, Importer.getToContext(), DC,
4879-
ToUsingLoc, ToEnumLoc, Loc, ToEnumDecl))
4880+
ToUsingLoc, ToEnumLoc, ToNameLoc, ToEnumType))
48804881
return ToUsingEnum;
48814882

48824883
ToUsingEnum->setLexicalDeclContext(LexicalDC);

clang/lib/AST/DeclCXX.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3091,18 +3091,23 @@ SourceRange UsingDecl::getSourceRange() const {
30913091
void UsingEnumDecl::anchor() {}
30923092

30933093
UsingEnumDecl *UsingEnumDecl::Create(ASTContext &C, DeclContext *DC,
3094-
SourceLocation UL, SourceLocation EL,
3095-
SourceLocation NL, EnumDecl *Enum) {
3096-
return new (C, DC) UsingEnumDecl(DC, Enum->getDeclName(), UL, EL, NL, Enum);
3094+
SourceLocation UL,
3095+
SourceLocation EL,
3096+
SourceLocation NL,
3097+
TypeSourceInfo *EnumType) {
3098+
assert(isa<EnumDecl>(EnumType->getType()->getAsTagDecl()));
3099+
return new (C, DC)
3100+
UsingEnumDecl(DC, EnumType->getType()->getAsTagDecl()->getDeclName(), UL, EL, NL, EnumType);
30973101
}
30983102

30993103
UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
3100-
return new (C, ID) UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(),
3101-
SourceLocation(), SourceLocation(), nullptr);
3104+
return new (C, ID)
3105+
UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(),
3106+
SourceLocation(), SourceLocation(), nullptr);
31023107
}
31033108

31043109
SourceRange UsingEnumDecl::getSourceRange() const {
3105-
return SourceRange(EnumLocation, getLocation());
3110+
return SourceRange(UsingLocation, EnumType->getTypeLoc().getEndLoc());
31063111
}
31073112

31083113
void UsingPackDecl::anchor() {}

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11871,8 +11871,14 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
1187111871
SourceLocation IdentLoc,
1187211872
IdentifierInfo &II, CXXScopeSpec *SS) {
1187311873
assert(!SS->isInvalid() && "ScopeSpec is invalid");
11874-
ParsedType TypeRep = getTypeName(II, IdentLoc, S, SS);
11875-
if (!TypeRep) {
11874+
TypeSourceInfo *TSI = nullptr;
11875+
QualType EnumTy = GetTypeFromParser(
11876+
getTypeName(II, IdentLoc, S, SS, /*isClassName=*/false,
11877+
/*HasTrailingDot=*/false,
11878+
/*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false,
11879+
/*WantNontrivialTypeSourceInfo=*/true),
11880+
&TSI);
11881+
if (EnumTy.isNull()) {
1187611882
Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS)
1187711883
? diag::err_using_enum_is_dependent
1187811884
: diag::err_unknown_typename)
@@ -11881,17 +11887,21 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
1188111887
return nullptr;
1188211888
}
1188311889

11884-
auto *Enum = dyn_cast_if_present<EnumDecl>(TypeRep.get()->getAsTagDecl());
11890+
auto *Enum = dyn_cast_if_present<EnumDecl>(EnumTy->getAsTagDecl());
1188511891
if (!Enum) {
11886-
Diag(IdentLoc, diag::err_using_enum_not_enum) << TypeRep.get();
11892+
Diag(IdentLoc, diag::err_using_enum_not_enum) << EnumTy;
1188711893
return nullptr;
1188811894
}
1188911895

1189011896
if (auto *Def = Enum->getDefinition())
1189111897
Enum = Def;
1189211898

11899+
if (TSI == nullptr)
11900+
TSI = Context.getTrivialTypeSourceInfo(EnumTy, IdentLoc);
11901+
1189311902
auto *UD =
11894-
BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, Enum);
11903+
BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, TSI, Enum);
11904+
1189511905
if (UD)
1189611906
PushOnScopeChains(UD, S, /*AddToContext*/ false);
1189711907

@@ -12583,6 +12593,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
1258312593
SourceLocation UsingLoc,
1258412594
SourceLocation EnumLoc,
1258512595
SourceLocation NameLoc,
12596+
TypeSourceInfo *EnumType,
1258612597
EnumDecl *ED) {
1258712598
bool Invalid = false;
1258812599

@@ -12609,7 +12620,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
1260912620
Invalid = true;
1261012621

1261112622
UsingEnumDecl *UD = UsingEnumDecl::Create(Context, CurContext, UsingLoc,
12612-
EnumLoc, NameLoc, ED);
12623+
EnumLoc, NameLoc, EnumType);
1261312624
UD->setAccess(AS);
1261412625
CurContext->addDecl(UD);
1261512626

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3294,9 +3294,11 @@ Decl *TemplateDeclInstantiator::VisitUsingEnumDecl(UsingEnumDecl *D) {
32943294
if (SemaRef.RequireCompleteEnumDecl(EnumD, EnumD->getLocation()))
32953295
return nullptr;
32963296

3297+
TypeSourceInfo *TSI = SemaRef.SubstType(D->getEnumType(), TemplateArgs,
3298+
D->getLocation(), D->getDeclName());
32973299
UsingEnumDecl *NewUD =
32983300
UsingEnumDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(),
3299-
D->getEnumLoc(), D->getLocation(), EnumD);
3301+
D->getEnumLoc(), D->getLocation(), TSI);
33003302

33013303
SemaRef.Context.setInstantiatedFromUsingEnumDecl(NewUD, D);
33023304
NewUD->setAccess(D->getAccess());

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1773,7 +1773,7 @@ void ASTDeclReader::VisitUsingEnumDecl(UsingEnumDecl *D) {
17731773
VisitNamedDecl(D);
17741774
D->setUsingLoc(readSourceLocation());
17751775
D->setEnumLoc(readSourceLocation());
1776-
D->Enum = readDeclAs<EnumDecl>();
1776+
D->setEnumType(Record.readTypeSourceInfo());
17771777
D->FirstUsingShadow.setPointer(readDeclAs<UsingShadowDecl>());
17781778
if (auto *Pattern = readDeclAs<UsingEnumDecl>())
17791779
Reader.getContext().setInstantiatedFromUsingEnumDecl(D, Pattern);

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1294,7 +1294,7 @@ void ASTDeclWriter::VisitUsingEnumDecl(UsingEnumDecl *D) {
12941294
VisitNamedDecl(D);
12951295
Record.AddSourceLocation(D->getUsingLoc());
12961296
Record.AddSourceLocation(D->getEnumLoc());
1297-
Record.AddDeclRef(D->getEnumDecl());
1297+
Record.AddTypeSourceInfo(D->getEnumType());
12981298
Record.AddDeclRef(D->FirstUsingShadow.getPointer());
12991299
Record.AddDeclRef(Context.getInstantiatedFromUsingEnumDecl(D));
13001300
Code = serialization::DECL_USING_ENUM;

clang/test/AST/ast-dump-using-enum.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ using enum Bob::Foo;
2121
// CHECK-NEXT: `-EnumConstantDecl {{.*}} Foo_b 'Bob::Foo'
2222

2323
// CHECK-LABEL: Dumping Foo:
24-
// CHECK-NEXT: UsingEnumDecl {{.*}} Enum {{.*}} 'Foo'
24+
// CHECK-NEXT: UsingEnumDecl {{.*}} <{{.*}}:16:1, col:17> {{.*}} Enum {{.*}} 'Foo'
2525

2626
// CHECK-LABEL: Dumping Foo_a:
2727
// CHECK-NEXT: UsingShadowDecl {{.*}} implicit EnumConstant {{.*}} 'Foo_a' 'Bob::Foo'

clang/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,12 @@ TEST(RecursiveASTVisitor, VisitInvalidType) {
8888
TypeLocVisitor::Lang_C));
8989
}
9090

91+
TEST(RecursiveASTVisitor, VisitsUsingEnumType) {
92+
TypeLocVisitor Visitor;
93+
Visitor.ExpectMatch("::A", 2, 12);
94+
EXPECT_TRUE(Visitor.runOver("enum class A {}; \n"
95+
"using enum ::A;\n",
96+
TypeLocVisitor::Lang_CXX2a));
97+
}
98+
9199
} // end anonymous namespace

0 commit comments

Comments
 (0)