diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -306,6 +306,11 @@ Outer.add(OME->getMethodDecl(), Flags); } void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *OPRE) { + // FIXME: visiting this here allows us to hover on UIColor in + // `UIColor.blackColor` but then `blackColor` no longer refers to the + // method. + // if (OPRE->isClassReceiver()) + // Outer.add(OPRE->getClassReceiver(), Flags); if (OPRE->isExplicitProperty()) Outer.add(OPRE->getExplicitProperty(), Flags); else { @@ -763,6 +768,12 @@ } void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *E) { + if (E->isClassReceiver()) { + Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), + E->getReceiverLocation(), + /*IsDecl=*/false, + {E->getClassReceiver()}}); + } Refs.push_back(ReferenceLoc{ NestedNameSpecifierLoc(), E->getLocation(), /*IsDecl=*/false, diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -957,6 +957,7 @@ @end void test(C<[[Foo]]> *p); )cpp"; + EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo"); Code = R"cpp( @@ -969,6 +970,33 @@ )cpp"; // FIXME: We currently can't disambiguate between multiple protocols. EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo", "@protocol Bar"); + + Code = R"cpp( + @interface Foo + + (id)sharedInstance; + @end + @implementation Foo + + (id)sharedInstance { return 0; } + @end + void test() { + id value = [[Foo]].sharedInstance; + } + )cpp"; + // FIXME: currently failing. + EXPECT_DECLS("ObjCPropertyRefExpr", "@interface Foo"); + + Code = R"cpp( + @interface Foo + + (id)sharedInstance; + @end + @implementation Foo + + (id)sharedInstance { return 0; } + @end + void test() { + id value = Foo.[[sharedInstance]]; + } + )cpp"; + EXPECT_DECLS("ObjCPropertyRefExpr", "+ (id)sharedInstance"); } class FindExplicitReferencesTest : public ::testing::Test { @@ -1610,6 +1638,41 @@ "0: targets = {f}\n" "1: targets = {I::x}\n" "2: targets = {I::setY:}\n"}, + // Objective-C: class properties + { + R"cpp( + @interface I {} + @property(class) I *x; + @end + id local; + void foo() { + $0^I.$1^x = 0; + $2^local = $3^I.$4^x; + } + )cpp", + "0: targets = {I}\n" + "1: targets = {I::setX:}\n" + "2: targets = {local}\n" + "3: targets = {I}\n" + "4: targets = {I::x}\n"}, + // Objective-C: implicit class properties + { + R"cpp( + @interface I {} + +(I*)x; + +(void)setX:(I*)x; + @end + id local; + void foo() { + $0^I.$1^x = 0; + $2^local = $3^I.$4^x; + } + )cpp", + "0: targets = {I}\n" + "1: targets = {I::setX:}\n" + "2: targets = {local}\n" + "3: targets = {I}\n" + "4: targets = {I::x}\n"}, {// Objective-C: methods R"cpp( @interface I