return true;
}
-// Should we perform index-based completion in this context?
+// Should we perform index-based completion in a context of the specified kind?
// FIXME: consider allowing completion, but restricting the result types.
-bool allowIndex(enum CodeCompletionContext::Kind K) {
+bool contextAllowsIndex(enum CodeCompletionContext::Kind K) {
switch (K) {
case CodeCompletionContext::CCC_TopLevel:
case CodeCompletionContext::CCC_ObjCInterface:
llvm_unreachable("unknown code completion context");
}
+// Should we allow index completions in the specified context?
+bool allowIndex(CodeCompletionContext &CC) {
+ if (!contextAllowsIndex(CC.getKind()))
+ return false;
+ // We also avoid ClassName::bar (but allow namespace::bar).
+ auto Scope = CC.getCXXScopeSpecifier();
+ if (!Scope)
+ return true;
+ NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep();
+ if (!NameSpec)
+ return true;
+ // We only query the index when qualifier is a namespace.
+ // If it's a class, we rely solely on sema completions.
+ switch (NameSpec->getKind()) {
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ return true;
+ case NestedNameSpecifier::Super:
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ // Unresolved inside a template.
+ case NestedNameSpecifier::Identifier:
+ return false;
+ }
+}
+
} // namespace
clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
}
SymbolSlab queryIndex() {
- if (!Opts.Index || !allowIndex(Recorder->CCContext.getKind()))
+ if (!Opts.Index || !allowIndex(Recorder->CCContext))
return SymbolSlab();
trace::Span Tracer("Query index");
SPAN_ATTACH(Tracer, "limit", Opts.Limit);
UnorderedElementsAre(""))));
}
+TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
+ auto Completions = completions(
+ R"cpp(
+ struct Foo {
+ int SomeNameOfField;
+ typedef int SomeNameOfTypedefField;
+ };
+
+ Foo::^)cpp",
+ {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
+
+ EXPECT_THAT(Completions.items,
+ AllOf(Contains(Labeled("SomeNameOfField")),
+ Contains(Labeled("SomeNameOfTypedefField")),
+ Not(Contains(Labeled("SomeNameInTheIndex")))));
+}
+
+TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
+ {
+ auto Completions = completions(
+ R"cpp(
+ template <class T>
+ void foo() {
+ T::^
+ }
+ )cpp",
+ {func("::SomeNameInTheIndex")});
+
+ EXPECT_THAT(Completions.items,
+ Not(Contains(Labeled("SomeNameInTheIndex"))));
+ }
+
+ {
+ auto Completions = completions(
+ R"cpp(
+ template <class T>
+ void foo() {
+ T::template Y<int>::^
+ }
+ )cpp",
+ {func("::SomeNameInTheIndex")});
+
+ EXPECT_THAT(Completions.items,
+ Not(Contains(Labeled("SomeNameInTheIndex"))));
+ }
+
+ {
+ auto Completions = completions(
+ R"cpp(
+ template <class T>
+ void foo() {
+ T::foo::^
+ }
+ )cpp",
+ {func("::SomeNameInTheIndex")});
+
+ EXPECT_THAT(Completions.items,
+ Not(Contains(Labeled("SomeNameInTheIndex"))));
+ }
+}
+
} // namespace
} // namespace clangd
} // namespace clang