Index: clangd/CodeComplete.cpp =================================================================== --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -48,6 +48,7 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" @@ -526,7 +527,7 @@ std::set Results; for (llvm::StringRef AS : AccessibleScopes) Results.insert( - ((UnresolvedQualifier ? *UnresolvedQualifier : "") + AS).str()); + (AS + (UnresolvedQualifier ? *UnresolvedQualifier : "")).str()); return {Results.begin(), Results.end()}; } }; @@ -570,16 +571,16 @@ } // Unresolved qualifier. - // FIXME: When Sema can resolve part of a scope chain (e.g. - // "known::unknown::id"), we should expand the known part ("known::") rather - // than treating the whole thing as unknown. - SpecifiedScope Info; - Info.AccessibleScopes.push_back(""); // global namespace + SpecifiedScope Info = GetAllAccessibleScopes(CCContext); + if (Info.AccessibleScopes.empty()) + Info.AccessibleScopes.push_back(""); // Fallback to global namespace. - Info.UnresolvedQualifier = + llvm::StringRef SpelledSpecifier = Lexer::getSourceText(CharSourceRange::getCharRange((*SS)->getRange()), - CCSema.SourceMgr, clang::LangOptions()) - .ltrim("::"); + CCSema.SourceMgr, clang::LangOptions()); + if (SpelledSpecifier.consume_front("::")) + Info.AccessibleScopes = {""}; + Info.UnresolvedQualifier = SpelledSpecifier; // Sema excludes the trailing "::". if (!Info.UnresolvedQualifier->empty()) *Info.UnresolvedQualifier += "::"; Index: unittests/clangd/CodeCompleteTests.cpp =================================================================== --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1094,8 +1094,10 @@ } // namespace ns )cpp"); - EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes, - UnorderedElementsAre("bar::")))); + EXPECT_THAT(Requests, + ElementsAre(Field( + &FuzzyFindRequest::Scopes, + UnorderedElementsAre("a::bar::", "ns::bar::", "bar::")))); } TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) { @@ -2314,6 +2316,35 @@ EXPECT_THAT(R.Completions, ElementsAre(Named("loopVar"))); } +TEST(CompletionTest, ScopeIsUnresolved) { + clangd::CodeCompleteOptions Opts = {}; + Opts.AllScopes = true; + + auto Results = completions(R"cpp( + namespace a { + void f() { b::X^ } + } + )cpp", + {cls("a::b::XYZ")}, Opts); + EXPECT_THAT(Results.Completions, + UnorderedElementsAre(AllOf(Qualifier(""), Named("XYZ")))); +} + +TEST(CompletionTest, NestedScopeIsUnresolved) { + clangd::CodeCompleteOptions Opts = {}; + Opts.AllScopes = true; + + auto Results = completions(R"cpp( + namespace a { + namespace b {} + void f() { b::c::X^ } + } + )cpp", + {cls("a::b::c::XYZ")}, Opts); + EXPECT_THAT(Results.Completions, + UnorderedElementsAre(AllOf(Qualifier(""), Named("XYZ")))); +} + } // namespace } // namespace clangd } // namespace clang