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 @@ -62,6 +62,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" @@ -1910,6 +1911,13 @@ if (isExplicitTemplateSpecialization(&ND)) return false; + // Category decls are not useful on their own outside the interface or + // implementation blocks. Moreover, sema already provides completion for + // these, even if it requires preamble deserialization. So by excluding them + // from the index, we reduce the noise in all the other completion scopes. + if (llvm::isa(&ND) || llvm::isa(&ND)) + return false; + if (InTopLevelScope(ND)) return true; 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 @@ -3221,6 +3221,45 @@ UnorderedElementsAre(Labeled("ECHO(X)"), Labeled("ECHO2(X)"))); } +TEST(CompletionTest, ObjCCategoryDecls) { + TestTU TU; + TU.ExtraArgs.push_back("-xobjective-c"); + TU.HeaderCode = R"objc( + @interface Foo + @end + + @interface Foo (FooExt1) + @end + + @interface Foo (FooExt2) + @end + + @interface Bar + @end + + @interface Bar (BarExt) + @end)objc"; + + { + Annotations Test(R"objc( + @implementation Foo (^) + @end + )objc"); + TU.Code = Test.code().str(); + auto Results = completions(TU, Test.point()); + EXPECT_THAT(Results.Completions, + UnorderedElementsAre(Labeled("FooExt1"), Labeled("FooExt2"))); + } + { + Annotations Test(R"objc( + @interface Foo (^) + @end + )objc"); + TU.Code = Test.code().str(); + auto Results = completions(TU, Test.point()); + EXPECT_THAT(Results.Completions, UnorderedElementsAre(Labeled("BarExt"))); + } +} } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp --- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp @@ -552,8 +552,9 @@ EXPECT_THAT(Symbols, UnorderedElementsAre( QName("Person"), QName("Person::someMethodName:lastName:"), - QName("MyCategory"), QName("Person::someMethodName2:"), - QName("MyProtocol"), QName("MyProtocol::someMethodName3:"))); + AllOf(QName("MyCategory"), ForCodeCompletion(false)), + QName("Person::someMethodName2:"), QName("MyProtocol"), + QName("MyProtocol::someMethodName3:"))); } TEST_F(SymbolCollectorTest, ObjCPropertyImpl) {