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,9 @@ Outer.add(OME->getMethodDecl(), Flags); } void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *OPRE) { + // FIXME: We miss visiting the class receiver if one exists, which + // means we skip the corresponding ObjCInterfaceDecl ref since it + // doesn't have a corresponding node. if (OPRE->isExplicitProperty()) Outer.add(OPRE->getExplicitProperty(), Flags); else { @@ -763,6 +766,13 @@ } void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *E) { + // There's no contained TypeLoc node for a class receiver type. + 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 @@ -969,6 +969,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: We currently can't identify the interface here. + EXPECT_DECLS("ObjCPropertyRefExpr", "+ (id)sharedInstance"); + + 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 +1637,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