sammccall created this revision.
sammccall added reviewers: ilya-biryukov, urnathan.
Herald added subscribers: kadircet, arphaman, martong.
Herald added a reviewer: shafik.
Herald added a project: All.
sammccall requested review of this revision.
Herald added projects: clang, clang-tools-extra.
Herald added a subscriber: cfe-commits.
- store NestedNameSpecifier & Loc for the qualifiers This information was
entirely missing from the AST.
- expose the location information for enum/qualifier/identifier as typeloc
(ElaboratedTypeLoc+EnumTypeLoc for now). 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
https://github.com/llvm/llvm-project/issues/57659 is resolved.
- fix the SourceRange of UsingEnumDecl to include 'using'.
Fixes https://github.com/clangd/clangd/issues/1283
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D134303
Files:
clang-tools-extra/clangd/FindTarget.cpp
clang-tools-extra/clangd/unittests/FindTargetTests.cpp
clang-tools-extra/clangd/unittests/SelectionTests.cpp
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
clang/include/clang/AST/DeclCXX.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/DeclCXX.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/AST/ast-dump-using-enum.cpp
clang/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
Index: clang/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
===================================================================
--- clang/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
+++ clang/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
@@ -88,4 +88,12 @@
TypeLocVisitor::Lang_C));
}
+TEST(RecursiveASTVisitor, VisitsUsingEnumType) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("enum ::A", 2, 7);
+ EXPECT_TRUE(Visitor.runOver("enum class A {}; \n"
+ "using enum ::A;\n",
+ TypeLocVisitor::Lang_CXX2a));
+}
+
} // end anonymous namespace
Index: clang/test/AST/ast-dump-using-enum.cpp
===================================================================
--- clang/test/AST/ast-dump-using-enum.cpp
+++ clang/test/AST/ast-dump-using-enum.cpp
@@ -21,7 +21,7 @@
// CHECK-NEXT: `-EnumConstantDecl {{.*}} Foo_b 'Bob::Foo'
// CHECK-LABEL: Dumping Foo:
-// CHECK-NEXT: UsingEnumDecl {{.*}} Enum {{.*}} 'Foo'
+// CHECK-NEXT: UsingEnumDecl {{.*}} <{{.*}}:16:1, col:17> {{.*}} Enum {{.*}} 'Foo'
// CHECK-LABEL: Dumping Foo_a:
// CHECK-NEXT: UsingShadowDecl {{.*}} implicit EnumConstant {{.*}} 'Foo_a' 'Bob::Foo'
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1292,7 +1292,7 @@
void ASTDeclWriter::VisitUsingEnumDecl(UsingEnumDecl *D) {
VisitNamedDecl(D);
Record.AddSourceLocation(D->getUsingLoc());
- Record.AddSourceLocation(D->getEnumLoc());
+ Record.AddTypeSourceInfo(D->getEnumType());
Record.AddDeclRef(D->getEnumDecl());
Record.AddDeclRef(D->FirstUsingShadow.getPointer());
Record.AddDeclRef(Context.getInstantiatedFromUsingEnumDecl(D));
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1760,7 +1760,7 @@
void ASTDeclReader::VisitUsingEnumDecl(UsingEnumDecl *D) {
VisitNamedDecl(D);
D->setUsingLoc(readSourceLocation());
- D->setEnumLoc(readSourceLocation());
+ D->setEnumType(Record.readTypeSourceInfo());
D->Enum = readDeclAs<EnumDecl>();
D->FirstUsingShadow.setPointer(readDeclAs<UsingShadowDecl>());
if (auto *Pattern = readDeclAs<UsingEnumDecl>())
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3243,9 +3243,10 @@
if (SemaRef.RequireCompleteEnumDecl(EnumD, EnumD->getLocation()))
return nullptr;
- UsingEnumDecl *NewUD =
- UsingEnumDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(),
- D->getEnumLoc(), D->getLocation(), EnumD);
+ TypeSourceInfo *TSI = SemaRef.SubstType(D->getEnumType(), TemplateArgs,
+ D->getLocation(), D->getDeclName());
+ UsingEnumDecl *NewUD = UsingEnumDecl::Create(SemaRef.Context, Owner,
+ D->getUsingLoc(), TSI, EnumD);
SemaRef.Context.setInstantiatedFromUsingEnumDecl(NewUD, D);
NewUD->setAccess(D->getAccess());
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TypeLocBuilder.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
@@ -11868,8 +11869,17 @@
if (auto *Def = Enum->getDefinition())
Enum = Def;
- auto *UD = BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc,
- DS.getTypeSpecTypeNameLoc(), Enum);
+ TypeLocBuilder TLB;
+ QualType T = Context.getTypeDeclType(Enum);
+ TLB.pushTypeSpec(T).setNameLoc(DS.getTypeSpecTypeNameLoc());
+ T = Context.getElaboratedType(ETK_Enum, DS.getTypeSpecScope().getScopeRep(),
+ T);
+ ElaboratedTypeLoc ETL = TLB.push<ElaboratedTypeLoc>(T);
+ ETL.setElaboratedKeywordLoc(EnumLoc);
+ ETL.setQualifierLoc(DS.getTypeSpecScope().getWithLocInContext(Context));
+ TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, T);
+
+ auto *UD = BuildUsingEnumDeclaration(S, AS, UsingLoc, TSI, Enum);
if (UD)
PushOnScopeChains(UD, S, /*AddToContext*/ false);
@@ -12559,10 +12569,13 @@
NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
- SourceLocation EnumLoc,
- SourceLocation NameLoc,
+ TypeSourceInfo *EnumType,
EnumDecl *ED) {
bool Invalid = false;
+ SourceLocation NameLoc = EnumType->getTypeLoc()
+ .castAs<ElaboratedTypeLoc>()
+ .getNamedTypeLoc()
+ .getBeginLoc();
if (CurContext->getRedeclContext()->isRecord()) {
/// In class scope, check if this is a duplicate, for better a diagnostic.
@@ -12576,7 +12589,7 @@
if (UsingEnumDecl *UED = dyn_cast<UsingEnumDecl>(D))
if (UED->getEnumDecl() == ED) {
Diag(UsingLoc, diag::err_using_enum_decl_redeclaration)
- << SourceRange(EnumLoc, NameLoc);
+ << EnumType->getTypeLoc().getSourceRange();
Diag(D->getLocation(), diag::note_using_enum_decl) << 1;
Invalid = true;
break;
@@ -12586,8 +12599,8 @@
if (RequireCompleteEnumDecl(ED, NameLoc))
Invalid = true;
- UsingEnumDecl *UD = UsingEnumDecl::Create(Context, CurContext, UsingLoc,
- EnumLoc, NameLoc, ED);
+ UsingEnumDecl *UD =
+ UsingEnumDecl::Create(Context, CurContext, UsingLoc, EnumType, ED);
UD->setAccess(AS);
CurContext->addDecl(UD);
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -3091,18 +3091,21 @@
void UsingEnumDecl::anchor() {}
UsingEnumDecl *UsingEnumDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation UL, SourceLocation EL,
- SourceLocation NL, EnumDecl *Enum) {
- return new (C, DC) UsingEnumDecl(DC, Enum->getDeclName(), UL, EL, NL, Enum);
+ SourceLocation UL,
+ TypeSourceInfo *EnumType,
+ EnumDecl *Enum) {
+ auto TL = EnumType->getTypeLoc().castAs<ElaboratedTypeLoc>();
+ return new (C, DC) UsingEnumDecl(DC, Enum->getDeclName(), UL, EnumType,
+ TL.getNamedTypeLoc().getBeginLoc(), Enum);
}
UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(),
- SourceLocation(), SourceLocation(), nullptr);
+ nullptr, SourceLocation(), nullptr);
}
SourceRange UsingEnumDecl::getSourceRange() const {
- return SourceRange(EnumLocation, getLocation());
+ return SourceRange(UsingLocation, EnumType->getTypeLoc().getEndLoc());
}
void UsingPackDecl::anchor() {}
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -4863,14 +4863,14 @@
Error Err = Error::success();
auto ToUsingLoc = importChecked(Err, D->getUsingLoc());
- auto ToEnumLoc = importChecked(Err, D->getEnumLoc());
+ auto ToEnumLoc = importChecked(Err, D->getEnumType());
auto ToEnumDecl = importChecked(Err, D->getEnumDecl());
if (Err)
return std::move(Err);
UsingEnumDecl *ToUsingEnum;
if (GetImportedOrCreateDecl(ToUsingEnum, D, Importer.getToContext(), DC,
- ToUsingLoc, ToEnumLoc, Loc, ToEnumDecl))
+ ToUsingLoc, ToEnumLoc, ToEnumDecl))
return ToUsingEnum;
ToUsingEnum->setLexicalDeclContext(LexicalDC);
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -6069,8 +6069,7 @@
bool IsUsingIfExists);
NamedDecl *BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
- SourceLocation EnumLoc,
- SourceLocation NameLoc, EnumDecl *ED);
+ TypeSourceInfo *EnumType, EnumDecl *ED);
NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom,
ArrayRef<NamedDecl *> Expansions);
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1722,7 +1722,8 @@
TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
})
-DEF_TRAVERSE_DECL(UsingEnumDecl, {})
+DEF_TRAVERSE_DECL(UsingEnumDecl,
+ { TRY_TO(TraverseTypeLoc(D->getEnumTypeLoc())); })
DEF_TRAVERSE_DECL(UsingPackDecl, {})
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -3614,17 +3614,16 @@
class UsingEnumDecl : public BaseUsingDecl, public Mergeable<UsingEnumDecl> {
/// The source location of the 'using' keyword itself.
SourceLocation UsingLocation;
-
- /// Location of the 'enum' keyword.
- SourceLocation EnumLocation;
+ /// 'enum qual::SomeEnum' as an ElaboratedType wrapping (usually) EnumType.
+ TypeSourceInfo *EnumType;
/// The enum
EnumDecl *Enum;
UsingEnumDecl(DeclContext *DC, DeclarationName DN, SourceLocation UL,
- SourceLocation EL, SourceLocation NL, EnumDecl *ED)
+ TypeSourceInfo *EnumType, SourceLocation NL, EnumDecl *ED)
: BaseUsingDecl(UsingEnum, DC, NL, DN), UsingLocation(UL),
- EnumLocation(EL), Enum(ED) {}
+ EnumType(EnumType), Enum(ED) {}
void anchor() override;
@@ -3637,15 +3636,30 @@
void setUsingLoc(SourceLocation L) { UsingLocation = L; }
/// The source location of the 'enum' keyword.
- SourceLocation getEnumLoc() const { return EnumLocation; }
- void setEnumLoc(SourceLocation L) { EnumLocation = L; }
+ SourceLocation getEnumLoc() const {
+ return getEnumTypeLoc().getElaboratedKeywordLoc();
+ }
+ NestedNameSpecifier *getQualifier() const {
+ return getQualifierLoc().getNestedNameSpecifier();
+ }
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ return getEnumTypeLoc().getQualifierLoc();
+ }
+ // Returns the "enum qualifier::Name" part as a TypeLoc.
+ ElaboratedTypeLoc getEnumTypeLoc() const {
+ return EnumType->getTypeLoc().castAs<ElaboratedTypeLoc>();
+ }
+ TypeSourceInfo *getEnumType() const {
+ return EnumType;
+ }
+ void setEnumType(TypeSourceInfo *TSI) { EnumType = TSI; }
public:
EnumDecl *getEnumDecl() const { return Enum; }
static UsingEnumDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation UsingL, SourceLocation EnumL,
- SourceLocation NameL, EnumDecl *ED);
+ SourceLocation UsingL, TypeSourceInfo *EnumType,
+ EnumDecl *ED);
static UsingEnumDecl *CreateDeserialized(ASTContext &C, unsigned ID);
Index: clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -828,6 +828,14 @@
typedef int $Primitive_decl[[MyTypedef]];
enum $Enum_decl[[MyEnum]] : $Primitive[[MyTypedef]] {};
)cpp",
+ // Using enum
+ R"cpp(
+ enum class $Enum_decl[[Color]] { $EnumConstant_decl_readonly[[Black]] };
+ namespace $Namespace_decl[[ns]] {
+ using enum $Enum[[Color]];
+ $Enum[[Color]] $Variable_decl[[ModelT]] = $EnumConstant[[Black]];
+ }
+ )cpp",
// Issue 1096
R"cpp(
void $Function_decl[[Foo]]();
Index: clang-tools-extra/clangd/unittests/SelectionTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/SelectionTests.cpp
+++ clang-tools-extra/clangd/unittests/SelectionTests.cpp
@@ -531,6 +531,27 @@
void func() { [[__^func__]]; }
)cpp",
"PredefinedExpr"},
+
+ {R"cpp(
+ namespace ns { enum class A {}; };
+ using enum ns::[[^A]];
+ )cpp",
+ "EnumTypeLoc"},
+ {R"cpp(
+ namespace ns { enum class A {}; };
+ using enum [[^ns::]]A;
+ )cpp",
+ "NestedNameSpecifierLoc"},
+ {R"cpp(
+ namespace ns { enum class A {}; };
+ using [[^enum ns::A]];
+ )cpp",
+ "ElaboratedTypeLoc"},
+ {R"cpp(
+ namespace ns { enum class A {}; };
+ [[^using enum ns::A]];
+ )cpp",
+ "UsingEnumDecl"},
};
for (const Case &C : Cases) {
@@ -541,6 +562,7 @@
TU.Code = std::string(Test.code());
TU.ExtraArgs.push_back("-xobjective-c++");
+ TU.ExtraArgs.push_back("-std=c++20");
auto AST = TU.build();
auto T = makeSelectionTree(C.Code, AST);
Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -1252,6 +1252,15 @@
)cpp",
"0: targets = {ns}\n"
"1: targets = {ns::global}, qualifier = 'ns::'\n"},
+ // Using enum declarations.
+ {R"cpp(
+ namespace ns { enum class A {}; }
+ void foo() {
+ using enum $0^ns::$1^A;
+ }
+ )cpp",
+ "0: targets = {ns}\n"
+ "1: targets = {ns::A}, qualifier = 'ns::'\n"},
// Simple types.
{R"cpp(
struct Struct { int a; };
Index: clang-tools-extra/clangd/FindTarget.cpp
===================================================================
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -622,6 +622,12 @@
DeclRelation::Underlying, Resolver)});
}
+ void VisitUsingEnumDecl(const UsingEnumDecl *D) {
+ // "using enum ns::E" is a non-declaration reference.
+ // The reference is covered by the embedded typeloc.
+ // Don't use the default VisitNamedDecl, which would report a declaration.
+ }
+
void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
// For namespace alias, "namespace Foo = Target;", we add two references.
// Add a declaration reference for Foo.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits