llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clangd Author: Tom Praschan (tom-anders) <details> <summary>Changes</summary> Relevant issue: https://github.com/clangd/clangd/issues/1361 The problem here was that writing something like `using ns::ScopedEnum` does not cause Sema to visit this scope, to it won't be added into `CodeCompletionBuilder`'s `AccessibleScopes`, leading to the qualifier not being dropped. To detect this, walk up the DeclContext to check if we have a matching using declaration. If so, drop the qualifiers. Differential Revision: https://reviews.llvm.org/D141800 --- Full diff: https://github.com/llvm/llvm-project/pull/77766.diff 2 Files Affected: - (modified) clang-tools-extra/clangd/CodeComplete.cpp (+30-2) - (modified) clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp (+19) ``````````diff diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 0e5f08cec440ce..0345c014982134 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -333,7 +333,8 @@ std::string removeFirstTemplateArg(llvm::StringRef Signature) { // computed from the first candidate, in the constructor. // Others vary per candidate, so add() must be called for remaining candidates. struct CodeCompletionBuilder { - CodeCompletionBuilder(ASTContext *ASTCtx, const CompletionCandidate &C, + CodeCompletionBuilder(ASTContext *ASTCtx, DeclContext *SemaDeclCtx, + const CompletionCandidate &C, CodeCompletionString *SemaCCS, llvm::ArrayRef<std::string> AccessibleScopes, const IncludeInserter &Includes, @@ -395,6 +396,8 @@ struct CodeCompletionBuilder { ShortestQualifier = Qualifier; } Completion.RequiredQualifier = std::string(ShortestQualifier); + + stripNamespaceForEnumConstantIfUsingDecl(*C.IndexResult, SemaDeclCtx); } } if (C.IdentifierResult) { @@ -452,6 +455,30 @@ struct CodeCompletionBuilder { }); } + // With all-scopes-completion, we can complete enum constants of scoped + // enums, in which case the completion might not be visible to Sema. + // So, if there's a using declaration for the enum class, manually + // drop the qualifiers. + void stripNamespaceForEnumConstantIfUsingDecl(const Symbol &IndexResult, + DeclContext *SemaDeclCtx) { + if (IndexResult.SymInfo.Kind != index::SymbolKind::EnumConstant) + return; + for (auto *Ctx = SemaDeclCtx; Ctx; Ctx = Ctx->getParent()) + for (auto *D : Ctx->decls()) { + const auto *UD = dyn_cast<UsingShadowDecl>(D); + if (!UD) + continue; + const auto *ED = dyn_cast<EnumDecl>(UD->getTargetDecl()); + if (!ED || !ED->isScoped()) + continue; + auto EnumName = printQualifiedName(*ED) + "::"; + if (EnumName == IndexResult.Scope) { + Completion.RequiredQualifier = ED->getName().str() + "::"; + return; + } + } + } + void add(const CompletionCandidate &C, CodeCompletionString *SemaCCS, CodeCompletionContext::Kind ContextKind) { assert(bool(C.SemaResult) == bool(SemaCCS)); @@ -2086,7 +2113,8 @@ class CodeCompleteFlow { : nullptr; if (!Builder) Builder.emplace(Recorder ? &Recorder->CCSema->getASTContext() : nullptr, - Item, SemaCCS, AccessibleScopes, *Inserter, FileName, + Recorder ? Recorder->CCSema->CurContext : nullptr, Item, + SemaCCS, AccessibleScopes, *Inserter, FileName, CCContextKind, Opts, IsUsingDeclaration, NextTokenKind); else Builder->add(Item, SemaCCS, CCContextKind); diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 6d387fec9b3851..0c3eed7c35e578 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -3133,6 +3133,25 @@ TEST(CompletionTest, NoAllScopesCompletionWhenQualified) { AllOf(qualifier(""), scope("na::"), named("ClangdA")))); } +// https://github.com/clangd/clangd/issues/1361 +TEST(CompletionTest, ScopedEnumUsingDecl) { + clangd::CodeCompleteOptions Opts = {}; + Opts.AllScopes = true; + + auto Results = completions( + R"cpp( + namespace ns { enum class Scoped { FooBar }; } + using ns::Scoped; + void f() { + Foo^ + } + )cpp", + {enmConstant("ns::Scoped::FooBar")}, Opts); + EXPECT_THAT(Results.Completions, UnorderedElementsAre(AllOf( + qualifier("Scoped::"), named("FooBar"), + kind(CompletionItemKind::EnumMember)))); +} + TEST(CompletionTest, AllScopesCompletion) { clangd::CodeCompleteOptions Opts = {}; Opts.AllScopes = true; `````````` </details> https://github.com/llvm/llvm-project/pull/77766 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits