[clangd] Improve global code completion when scope specifier is unresolved.

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
This commit is contained in:
Eric Liu 2019-02-27 11:42:37 +00:00
parent 79fb858053
commit e98b86cbe8
2 changed files with 42 additions and 11 deletions

View File

@ -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 @@ 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()};
}
};
@ -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 += "::";

View File

@ -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) {
@ -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