Skip to content

Commit 54a962b

Browse files
committed
[clangd] Use ObjCProtocolLoc for generalized ObjC protocol support
This removes clangd's existing workaround in favor of proper support via the newly added `ObjCProtocolLoc`. This improves support by allowing clangd to properly identify which protocol is selected now that `ObjCProtocolLoc` gets its own ASTNode. Differential Revision: https://reviews.llvm.org/D119366
1 parent 805f7a4 commit 54a962b

File tree

4 files changed

+46
-50
lines changed

4 files changed

+46
-50
lines changed

clang-tools-extra/clangd/FindTarget.cpp

Lines changed: 13 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -453,15 +453,6 @@ struct TargetFinder {
453453
void VisitObjCInterfaceType(const ObjCInterfaceType *OIT) {
454454
Outer.add(OIT->getDecl(), Flags);
455455
}
456-
void VisitObjCObjectType(const ObjCObjectType *OOT) {
457-
// Make all of the protocols targets since there's no child nodes for
458-
// protocols. This isn't needed for the base type, which *does* have a
459-
// child `ObjCInterfaceTypeLoc`. This structure is a hack, but it works
460-
// well for go-to-definition.
461-
unsigned NumProtocols = OOT->getNumProtocols();
462-
for (unsigned I = 0; I < NumProtocols; I++)
463-
Outer.add(OOT->getProtocol(I), Flags);
464-
}
465456
};
466457
Visitor(*this, Flags).Visit(T.getTypePtr());
467458
}
@@ -547,6 +538,8 @@ allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver) {
547538
Finder.add(TAL->getArgument(), Flags);
548539
else if (const CXXBaseSpecifier *CBS = N.get<CXXBaseSpecifier>())
549540
Finder.add(CBS->getTypeSourceInfo()->getType(), Flags);
541+
else if (const ObjCProtocolLoc *PL = N.get<ObjCProtocolLoc>())
542+
Finder.add(PL->getProtocol(), Flags);
550543
return Finder.takeDecls();
551544
}
552545

@@ -669,25 +662,7 @@ llvm::SmallVector<ReferenceLoc> refInDecl(const Decl *D,
669662
{OMD}});
670663
}
671664

672-
void visitProtocolList(
673-
llvm::iterator_range<ObjCProtocolList::iterator> Protocols,
674-
llvm::iterator_range<const SourceLocation *> Locations) {
675-
for (const auto &P : llvm::zip(Protocols, Locations)) {
676-
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
677-
std::get<1>(P),
678-
/*IsDecl=*/false,
679-
{std::get<0>(P)}});
680-
}
681-
}
682-
683-
void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *OID) {
684-
if (OID->isThisDeclarationADefinition())
685-
visitProtocolList(OID->protocols(), OID->protocol_locs());
686-
Base::VisitObjCInterfaceDecl(OID); // Visit the interface's name.
687-
}
688-
689665
void VisitObjCCategoryDecl(const ObjCCategoryDecl *OCD) {
690-
visitProtocolList(OCD->protocols(), OCD->protocol_locs());
691666
// getLocation is the extended class's location, not the category's.
692667
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
693668
OCD->getLocation(),
@@ -709,12 +684,6 @@ llvm::SmallVector<ReferenceLoc> refInDecl(const Decl *D,
709684
/*IsDecl=*/true,
710685
{OCID->getCategoryDecl()}});
711686
}
712-
713-
void VisitObjCProtocolDecl(const ObjCProtocolDecl *OPD) {
714-
if (OPD->isThisDeclarationADefinition())
715-
visitProtocolList(OPD->protocols(), OPD->protocol_locs());
716-
Base::VisitObjCProtocolDecl(OPD); // Visit the protocol's name.
717-
}
718687
};
719688

720689
Visitor V{Resolver};
@@ -944,16 +913,6 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) {
944913
/*IsDecl=*/false,
945914
{L.getIFaceDecl()}});
946915
}
947-
948-
void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc L) {
949-
unsigned NumProtocols = L.getNumProtocols();
950-
for (unsigned I = 0; I < NumProtocols; I++) {
951-
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
952-
L.getProtocolLoc(I),
953-
/*IsDecl=*/false,
954-
{L.getProtocol(I)}});
955-
}
956-
}
957916
};
958917

959918
Visitor V{Resolver};
@@ -1049,6 +1008,11 @@ class ExplicitReferenceCollector
10491008
return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(L);
10501009
}
10511010

1011+
bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc) {
1012+
visitNode(DynTypedNode::create(ProtocolLoc));
1013+
return true;
1014+
}
1015+
10521016
bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
10531017
visitNode(DynTypedNode::create(*Init));
10541018
return RecursiveASTVisitor::TraverseConstructorInitializer(Init);
@@ -1094,6 +1058,12 @@ class ExplicitReferenceCollector
10941058
{CCI->getAnyMember()}}};
10951059
}
10961060
}
1061+
if (const ObjCProtocolLoc *PL = N.get<ObjCProtocolLoc>())
1062+
return {ReferenceLoc{NestedNameSpecifierLoc(),
1063+
PL->getLocation(),
1064+
/*IsDecl=*/false,
1065+
{PL->getProtocol()}}};
1066+
10971067
// We do not have location information for other nodes (QualType, etc)
10981068
return {};
10991069
}

clang-tools-extra/clangd/Selection.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,9 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
684684
return traverseNode<TypeLoc>(
685685
&QX, [&] { return TraverseTypeLoc(QX.getUnqualifiedLoc()); });
686686
}
687+
bool TraverseObjCProtocolLoc(ObjCProtocolLoc PL) {
688+
return traverseNode(&PL, [&] { return Base::TraverseObjCProtocolLoc(PL); });
689+
}
687690
// Uninteresting parts of the AST that don't have locations within them.
688691
bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; }
689692
bool TraverseType(QualType) { return true; }

clang-tools-extra/clangd/unittests/FindTargetTests.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -946,11 +946,9 @@ TEST_F(TargetDeclTest, ObjC) {
946946
EXPECT_DECLS("ObjCCategoryImplDecl", "@interface Foo(Ext)");
947947

948948
Code = R"cpp(
949-
@protocol Foo
950-
@end
951-
void test([[id<Foo>]] p);
949+
void test(id</*error-ok*/[[InvalidProtocol]]> p);
952950
)cpp";
953-
EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo");
951+
EXPECT_DECLS("ParmVarDecl", "id p");
954952

955953
Code = R"cpp(
956954
@class C;
@@ -966,7 +964,7 @@ TEST_F(TargetDeclTest, ObjC) {
966964
@end
967965
void test(C<[[Foo]]> *p);
968966
)cpp";
969-
EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo");
967+
EXPECT_DECLS("ObjCProtocolLoc", "@protocol Foo");
970968

971969
Code = R"cpp(
972970
@class C;
@@ -976,8 +974,17 @@ TEST_F(TargetDeclTest, ObjC) {
976974
@end
977975
void test(C<[[Foo]], Bar> *p);
978976
)cpp";
979-
// FIXME: We currently can't disambiguate between multiple protocols.
980-
EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo", "@protocol Bar");
977+
EXPECT_DECLS("ObjCProtocolLoc", "@protocol Foo");
978+
979+
Code = R"cpp(
980+
@class C;
981+
@protocol Foo
982+
@end
983+
@protocol Bar
984+
@end
985+
void test(C<Foo, [[Bar]]> *p);
986+
)cpp";
987+
EXPECT_DECLS("ObjCProtocolLoc", "@protocol Bar");
981988

982989
Code = R"cpp(
983990
@interface Foo

clang-tools-extra/clangd/unittests/HoverTests.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,6 +2522,22 @@ TEST(Hover, All) {
25222522
HI.Definition = "@property(nonatomic, assign, unsafe_unretained, "
25232523
"readwrite) int prop1;";
25242524
}},
2525+
{
2526+
R"cpp(
2527+
@protocol MYProtocol
2528+
@end
2529+
@interface MYObject
2530+
@end
2531+
2532+
@interface MYObject (Ext) <[[MYProt^ocol]]>
2533+
@end
2534+
)cpp",
2535+
[](HoverInfo &HI) {
2536+
HI.Name = "MYProtocol";
2537+
HI.Kind = index::SymbolKind::Protocol;
2538+
HI.NamespaceScope = "";
2539+
HI.Definition = "@protocol MYProtocol\n@end";
2540+
}},
25252541
{R"objc(
25262542
@interface Foo
25272543
@end

0 commit comments

Comments
 (0)