[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());
 | 
				
			||||||
      // Fill in the qualifier.
 | 
					      size_t NewSize = Refs.size();
 | 
				
			||||||
      if (!Ref)
 | 
					      // Add qualifier for the newly-added refs.
 | 
				
			||||||
        return;
 | 
					      for (unsigned I = InitialSize; I < NewSize; ++I) {
 | 
				
			||||||
      assert(!Ref->Qualifier.hasQualifier() && "qualifier already set");
 | 
					        ReferenceLoc *Ref = &Refs[I];
 | 
				
			||||||
      Ref->Qualifier = L.getQualifierLoc();
 | 
					        // Fill in the qualifier.
 | 
				
			||||||
 | 
					        assert(!Ref->Qualifier.hasQualifier() && "qualifier already set");
 | 
				
			||||||
 | 
					        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(
 | 
				
			||||||
                         /*IsDecl=*/false,
 | 
					          ReferenceLoc{L.getQualifierLoc(), L.getTemplateNameLoc(),
 | 
				
			||||||
                         explicitReferenceTargets(
 | 
					                       /*IsDecl=*/false,
 | 
				
			||||||
                             DynTypedNode::create(L.getType()), {}, Resolver)};
 | 
					                       explicitReferenceTargets(
 | 
				
			||||||
 | 
					                           DynTypedNode::create(L.getType()), {}, Resolver)});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
 | 
					    void VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
 | 
				
			||||||
      Ref = ReferenceLoc{L.getQualifierLoc(), L.getNameLoc(), /*IsDecl=*/false,
 | 
					      Refs.push_back(
 | 
				
			||||||
                         explicitReferenceTargets(
 | 
					          ReferenceLoc{L.getQualifierLoc(), L.getNameLoc(),
 | 
				
			||||||
                             DynTypedNode::create(L.getType()), {}, Resolver)};
 | 
					                       /*IsDecl=*/false,
 | 
				
			||||||
 | 
					                       explicitReferenceTargets(
 | 
				
			||||||
 | 
					                           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