diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -94,10 +94,14 @@ case SK::Struct: return CompletionItemKind::Struct; case SK::Class: - case SK::Protocol: case SK::Extension: case SK::Union: return CompletionItemKind::Class; + case SK::Protocol: + // Use interface instead of class for differentiation of classes and + // protocols with the same name (e.g. @interface NSObject vs. @protocol + // NSObject). + return CompletionItemKind::Interface; case SK::TypeAlias: // We use the same kind as the VSCode C++ extension. // FIXME: pick a better option when we have one. @@ -712,13 +716,13 @@ case CodeCompletionContext::CCC_Type: case CodeCompletionContext::CCC_ParenthesizedExpression: case CodeCompletionContext::CCC_ObjCInterfaceName: - case CodeCompletionContext::CCC_ObjCCategoryName: case CodeCompletionContext::CCC_Symbol: case CodeCompletionContext::CCC_SymbolOrNewName: return true; case CodeCompletionContext::CCC_OtherWithMacros: case CodeCompletionContext::CCC_DotMemberAccess: case CodeCompletionContext::CCC_ArrowMemberAccess: + case CodeCompletionContext::CCC_ObjCCategoryName: case CodeCompletionContext::CCC_ObjCPropertyAccess: case CodeCompletionContext::CCC_MacroName: case CodeCompletionContext::CCC_MacroNameUse: @@ -1343,6 +1347,22 @@ llvm_unreachable("invalid NestedNameSpecifier kind"); } +// Should we include a symbol from the index given the completion kind? +// FIXME: Ideally we can filter in the fuzzy find request itself. +bool includeSymbolFromIndex(CodeCompletionContext::Kind Kind, + const Symbol &Sym) { + // Objective-C protocols are only useful in ObjC protocol completions, + // in other places they're confusing, especially when they share the same + // identifier with a class. + if (Sym.SymInfo.Kind == index::SymbolKind::Protocol && + Sym.SymInfo.Lang == index::SymbolLanguage::ObjC) + return Kind == CodeCompletionContext::CCC_ObjCProtocolName; + else if (Kind == CodeCompletionContext::CCC_ObjCProtocolName) + // Don't show anything else in ObjC protocol completions. + return false; + return true; +} + std::future startAsyncFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest &Req) { return runAsync([&Index, Req]() { @@ -1675,14 +1695,6 @@ return Output; } - bool includeSymbolFromIndex(const Symbol &Sym) { - if (CCContextKind == CodeCompletionContext::CCC_ObjCProtocolName) { - return Sym.SymInfo.Lang == index::SymbolLanguage::ObjC && - Sym.SymInfo.Kind == index::SymbolKind::Protocol; - } - return true; - } - SymbolSlab queryIndex() { trace::Span Tracer("Query index"); SPAN_ATTACH(Tracer, "limit", int64_t(Opts.Limit)); @@ -1716,10 +1728,8 @@ // Run the query against the index. SymbolSlab::Builder ResultsBuilder; - if (Opts.Index->fuzzyFind(Req, [&](const Symbol &Sym) { - if (includeSymbolFromIndex(Sym)) - ResultsBuilder.insert(Sym); - })) + if (Opts.Index->fuzzyFind( + Req, [&](const Symbol &Sym) { ResultsBuilder.insert(Sym); })) Incomplete = true; return std::move(ResultsBuilder).build(); } @@ -1783,6 +1793,8 @@ for (const auto &IndexResult : IndexResults) { if (UsedIndexResults.count(&IndexResult)) continue; + if (!includeSymbolFromIndex(CCContextKind, IndexResult)) + continue; AddToBundles(/*SemaResult=*/nullptr, &IndexResult, nullptr); } // Emit identifier results. diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -3215,7 +3215,10 @@ /*Opts=*/{}, "Foo.m"); auto C = Results.Completions; - EXPECT_THAT(C, UnorderedElementsAre(named("Food"), named("Fooey"))); + EXPECT_THAT(C, + UnorderedElementsAre( + AllOf(named("Food"), kind(CompletionItemKind::Interface)), + AllOf(named("Fooey"), kind(CompletionItemKind::Interface)))); } TEST(CompletionTest, CursorInSnippets) {