Skip to content

Commit

Permalink
[clangd] Improve global code completion when scope specifier is unres…
Browse files Browse the repository at this point in the history
…olved.

Summary:
Suppose `clangd::` is unresolved in the following example. Currently,
we simply use "clangd::" as the query scope. We can do better by combining with
accessible scopes in the context. The query scopes can be `{clangd::, clang::clangd::}`.
```
namespace clang { clangd::^ }

```

Reviewers: ilya-biryukov, sammccall, hokein, kadircet

Reviewed By: kadircet

Subscribers: MaskRay, jkorous, arphaman, kadircet, jdoerfert, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D58448

llvm-svn: 354963
  • Loading branch information
Eric Liu committed Feb 27, 2019
1 parent 79fb858 commit e98b86c
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 11 deletions.
18 changes: 9 additions & 9 deletions clang-tools-extra/clangd/CodeComplete.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -526,7 +527,7 @@ struct SpecifiedScope {
std::set<std::string> Results;
for (llvm::StringRef AS : AccessibleScopes)
Results.insert(
((UnresolvedQualifier ? *UnresolvedQualifier : "") + AS).str());
(AS + (UnresolvedQualifier ? *UnresolvedQualifier : "")).str());
return {Results.begin(), Results.end()};
}
};
Expand Down Expand Up @@ -570,16 +571,15 @@ getQueryScopes(CodeCompletionContext &CCContext, const Sema &CCSema,
}

// 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);
Info.AccessibleScopes.push_back(""); // Make sure global scope is included.

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 += "::";
Expand Down
35 changes: 33 additions & 2 deletions clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp
Expand Up @@ -1095,8 +1095,10 @@ TEST(CompletionTest, UnresolvedQualifierIdQuery) {
} // 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) {
Expand Down Expand Up @@ -2335,6 +2337,35 @@ TEST(CompletionTest, UsingDecl) {
Kind(CompletionItemKind::Reference))));
}

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

0 comments on commit e98b86c

Please sign in to comment.