[clangd] Improve handling of Objective-C protocols in types
Improve support for Objective-C protocols for types/type locs Differential Revision: https://reviews.llvm.org/D98984
This commit is contained in:
parent
4ebb01cbcb
commit
c20e4fbfa6
|
|
@ -432,10 +432,13 @@ public:
|
||||||
Outer.add(OIT->getDecl(), Flags);
|
Outer.add(OIT->getDecl(), Flags);
|
||||||
}
|
}
|
||||||
void VisitObjCObjectType(const ObjCObjectType *OOT) {
|
void VisitObjCObjectType(const ObjCObjectType *OOT) {
|
||||||
// FIXME: ObjCObjectTypeLoc has no children for the protocol list, so
|
// Make all of the protocols targets since there's no child nodes for
|
||||||
// there is no node in id<Foo> that refers to ObjCProtocolDecl Foo.
|
// protocols. This isn't needed for the base type, which *does* have a
|
||||||
if (OOT->isObjCQualifiedId() && OOT->getNumProtocols() == 1)
|
// child `ObjCInterfaceTypeLoc`. This structure is a hack, but it works
|
||||||
Outer.add(OOT->getProtocol(0), Flags);
|
// well for go-to-definition.
|
||||||
|
unsigned NumProtocols = OOT->getNumProtocols();
|
||||||
|
for (unsigned I = 0; I < NumProtocols; I++)
|
||||||
|
Outer.add(OOT->getProtocol(I), Flags);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Visitor(*this, Flags).Visit(T.getTypePtr());
|
Visitor(*this, Flags).Visit(T.getTypePtr());
|
||||||
|
|
@ -813,30 +816,34 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) {
|
||||||
Visitor(const HeuristicResolver *Resolver) : Resolver(Resolver) {}
|
Visitor(const HeuristicResolver *Resolver) : Resolver(Resolver) {}
|
||||||
|
|
||||||
const HeuristicResolver *Resolver;
|
const HeuristicResolver *Resolver;
|
||||||
llvm::Optional<ReferenceLoc> Ref;
|
llvm::SmallVector<ReferenceLoc> Refs;
|
||||||
|
|
||||||
void VisitElaboratedTypeLoc(ElaboratedTypeLoc L) {
|
void VisitElaboratedTypeLoc(ElaboratedTypeLoc L) {
|
||||||
// We only know about qualifier, rest if filled by inner locations.
|
// We only know about qualifier, rest if filled by inner locations.
|
||||||
|
size_t InitialSize = Refs.size();
|
||||||
Visit(L.getNamedTypeLoc().getUnqualifiedLoc());
|
Visit(L.getNamedTypeLoc().getUnqualifiedLoc());
|
||||||
|
size_t NewSize = Refs.size();
|
||||||
|
// Add qualifier for the newly-added refs.
|
||||||
|
for (unsigned I = InitialSize; I < NewSize; ++I) {
|
||||||
|
ReferenceLoc *Ref = &Refs[I];
|
||||||
// Fill in the qualifier.
|
// Fill in the qualifier.
|
||||||
if (!Ref)
|
|
||||||
return;
|
|
||||||
assert(!Ref->Qualifier.hasQualifier() && "qualifier already set");
|
assert(!Ref->Qualifier.hasQualifier() && "qualifier already set");
|
||||||
Ref->Qualifier = L.getQualifierLoc();
|
Ref->Qualifier = L.getQualifierLoc();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VisitTagTypeLoc(TagTypeLoc L) {
|
void VisitTagTypeLoc(TagTypeLoc L) {
|
||||||
Ref = ReferenceLoc{NestedNameSpecifierLoc(),
|
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||||
L.getNameLoc(),
|
L.getNameLoc(),
|
||||||
/*IsDecl=*/false,
|
/*IsDecl=*/false,
|
||||||
{L.getDecl()}};
|
{L.getDecl()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc L) {
|
void VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc L) {
|
||||||
Ref = ReferenceLoc{NestedNameSpecifierLoc(),
|
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||||
L.getNameLoc(),
|
L.getNameLoc(),
|
||||||
/*IsDecl=*/false,
|
/*IsDecl=*/false,
|
||||||
{L.getDecl()}};
|
{L.getDecl()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc L) {
|
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc L) {
|
||||||
|
|
@ -848,63 +855,71 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) {
|
||||||
// 1. valias with mask 'Alias'.
|
// 1. valias with mask 'Alias'.
|
||||||
// 2. 'vector<int>' with mask 'Underlying'.
|
// 2. 'vector<int>' with mask 'Underlying'.
|
||||||
// we want to return only #1 in this case.
|
// we want to return only #1 in this case.
|
||||||
Ref = ReferenceLoc{
|
Refs.push_back(ReferenceLoc{
|
||||||
NestedNameSpecifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false,
|
NestedNameSpecifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false,
|
||||||
explicitReferenceTargets(DynTypedNode::create(L.getType()),
|
explicitReferenceTargets(DynTypedNode::create(L.getType()),
|
||||||
DeclRelation::Alias, Resolver)};
|
DeclRelation::Alias, Resolver)});
|
||||||
}
|
}
|
||||||
void VisitDeducedTemplateSpecializationTypeLoc(
|
void VisitDeducedTemplateSpecializationTypeLoc(
|
||||||
DeducedTemplateSpecializationTypeLoc L) {
|
DeducedTemplateSpecializationTypeLoc L) {
|
||||||
Ref = ReferenceLoc{
|
Refs.push_back(ReferenceLoc{
|
||||||
NestedNameSpecifierLoc(), L.getNameLoc(), /*IsDecl=*/false,
|
NestedNameSpecifierLoc(), L.getNameLoc(), /*IsDecl=*/false,
|
||||||
explicitReferenceTargets(DynTypedNode::create(L.getType()),
|
explicitReferenceTargets(DynTypedNode::create(L.getType()),
|
||||||
DeclRelation::Alias, Resolver)};
|
DeclRelation::Alias, Resolver)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
|
void VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
|
||||||
Ref = ReferenceLoc{NestedNameSpecifierLoc(),
|
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||||
TL.getNameLoc(),
|
TL.getNameLoc(),
|
||||||
/*IsDecl=*/false,
|
/*IsDecl=*/false,
|
||||||
{TL.getDecl()}};
|
{TL.getDecl()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitDependentTemplateSpecializationTypeLoc(
|
void VisitDependentTemplateSpecializationTypeLoc(
|
||||||
DependentTemplateSpecializationTypeLoc L) {
|
DependentTemplateSpecializationTypeLoc L) {
|
||||||
Ref = ReferenceLoc{L.getQualifierLoc(), L.getTemplateNameLoc(),
|
Refs.push_back(
|
||||||
|
ReferenceLoc{L.getQualifierLoc(), L.getTemplateNameLoc(),
|
||||||
/*IsDecl=*/false,
|
/*IsDecl=*/false,
|
||||||
explicitReferenceTargets(
|
explicitReferenceTargets(
|
||||||
DynTypedNode::create(L.getType()), {}, Resolver)};
|
DynTypedNode::create(L.getType()), {}, Resolver)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
|
void VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
|
||||||
Ref = ReferenceLoc{L.getQualifierLoc(), L.getNameLoc(), /*IsDecl=*/false,
|
Refs.push_back(
|
||||||
|
ReferenceLoc{L.getQualifierLoc(), L.getNameLoc(),
|
||||||
|
/*IsDecl=*/false,
|
||||||
explicitReferenceTargets(
|
explicitReferenceTargets(
|
||||||
DynTypedNode::create(L.getType()), {}, Resolver)};
|
DynTypedNode::create(L.getType()), {}, Resolver)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitTypedefTypeLoc(TypedefTypeLoc L) {
|
void VisitTypedefTypeLoc(TypedefTypeLoc L) {
|
||||||
Ref = ReferenceLoc{NestedNameSpecifierLoc(),
|
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||||
L.getNameLoc(),
|
L.getNameLoc(),
|
||||||
/*IsDecl=*/false,
|
/*IsDecl=*/false,
|
||||||
{L.getTypedefNameDecl()}};
|
{L.getTypedefNameDecl()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc L) {
|
void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc L) {
|
||||||
Ref = ReferenceLoc{NestedNameSpecifierLoc(),
|
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||||
L.getNameLoc(),
|
L.getNameLoc(),
|
||||||
/*IsDecl=*/false,
|
/*IsDecl=*/false,
|
||||||
{L.getIFaceDecl()}};
|
{L.getIFaceDecl()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: add references to protocols in ObjCObjectTypeLoc and maybe
|
void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc L) {
|
||||||
// ObjCObjectPointerTypeLoc.
|
unsigned NumProtocols = L.getNumProtocols();
|
||||||
|
for (unsigned I = 0; I < NumProtocols; I++) {
|
||||||
|
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||||
|
L.getProtocolLoc(I),
|
||||||
|
/*IsDecl=*/false,
|
||||||
|
{L.getProtocol(I)}});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Visitor V{Resolver};
|
Visitor V{Resolver};
|
||||||
V.Visit(L.getUnqualifiedLoc());
|
V.Visit(L.getUnqualifiedLoc());
|
||||||
if (!V.Ref)
|
return V.Refs;
|
||||||
return {};
|
|
||||||
return {*V.Ref};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExplicitReferenceCollector
|
class ExplicitReferenceCollector
|
||||||
|
|
|
||||||
|
|
@ -943,14 +943,32 @@ TEST_F(TargetDeclTest, ObjC) {
|
||||||
)cpp";
|
)cpp";
|
||||||
EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo");
|
EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo");
|
||||||
|
|
||||||
|
Code = R"cpp(
|
||||||
|
@class C;
|
||||||
|
@protocol Foo
|
||||||
|
@end
|
||||||
|
void test([[C]]<Foo> *p);
|
||||||
|
)cpp";
|
||||||
|
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@class C;");
|
||||||
|
|
||||||
Code = R"cpp(
|
Code = R"cpp(
|
||||||
@class C;
|
@class C;
|
||||||
@protocol Foo
|
@protocol Foo
|
||||||
@end
|
@end
|
||||||
void test(C<[[Foo]]> *p);
|
void test(C<[[Foo]]> *p);
|
||||||
)cpp";
|
)cpp";
|
||||||
// FIXME: there's no AST node corresponding to 'Foo', so we're stuck.
|
EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo");
|
||||||
EXPECT_DECLS("ObjCObjectTypeLoc");
|
|
||||||
|
Code = R"cpp(
|
||||||
|
@class C;
|
||||||
|
@protocol Foo
|
||||||
|
@end
|
||||||
|
@protocol Bar
|
||||||
|
@end
|
||||||
|
void test(C<[[Foo]], Bar> *p);
|
||||||
|
)cpp";
|
||||||
|
// FIXME: We currently can't disambiguate between multiple protocols.
|
||||||
|
EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo", "@protocol Bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
class FindExplicitReferencesTest : public ::testing::Test {
|
class FindExplicitReferencesTest : public ::testing::Test {
|
||||||
|
|
@ -1610,12 +1628,12 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
@protocol P
|
@protocol P
|
||||||
@end
|
@end
|
||||||
void foo() {
|
void foo() {
|
||||||
// FIXME: should reference P
|
$0^I<$1^P> *$2^x;
|
||||||
$0^I<P> *$1^x;
|
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {I}\n"
|
"0: targets = {I}\n"
|
||||||
"1: targets = {x}, decl\n"},
|
"1: targets = {P}\n"
|
||||||
|
"2: targets = {x}, decl\n"},
|
||||||
|
|
||||||
// Designated initializers.
|
// Designated initializers.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
|
|
|
||||||
|
|
@ -676,8 +676,7 @@ sizeof...($TemplateParameter[[Elements]]);
|
||||||
@end
|
@end
|
||||||
@interface $Class_decl[[Klass]] <$Interface[[Protocol]]>
|
@interface $Class_decl[[Klass]] <$Interface[[Protocol]]>
|
||||||
@end
|
@end
|
||||||
// FIXME: protocol list in ObjCObjectType should be highlighted.
|
id<$Interface[[Protocol]]> $Variable_decl[[x]];
|
||||||
id<Protocol> $Variable_decl[[x]];
|
|
||||||
)cpp",
|
)cpp",
|
||||||
R"cpp(
|
R"cpp(
|
||||||
// ObjC: Categories
|
// ObjC: Categories
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue