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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits