Index: include/clang/AST/DeclObjC.h =================================================================== --- include/clang/AST/DeclObjC.h +++ include/clang/AST/DeclObjC.h @@ -743,6 +743,8 @@ Selector GetterName; // getter name of NULL if no getter Selector SetterName; // setter name of NULL if no setter + SourceLocation GetterNameLoc; // location of the getter attribute's value + SourceLocation SetterNameLoc; // location of the setter attribute's value ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method @@ -759,6 +761,8 @@ PropertyImplementation(propControl), GetterName(Selector()), SetterName(Selector()), + GetterNameLoc(SourceLocation()), + SetterNameLoc(SourceLocation()), GetterMethodDecl(nullptr), SetterMethodDecl(nullptr), PropertyIvarDecl(nullptr) {} @@ -855,10 +859,18 @@ } Selector getGetterName() const { return GetterName; } - void setGetterName(Selector Sel) { GetterName = Sel; } + SourceLocation getGetterNameLoc() const { return GetterNameLoc; } + void setGetterName(Selector Sel, SourceLocation Loc) { + GetterName = Sel; + GetterNameLoc = Loc; + } Selector getSetterName() const { return SetterName; } - void setSetterName(Selector Sel) { SetterName = Sel; } + SourceLocation getSetterNameLoc() const { return SetterNameLoc; } + void setSetterName(Selector Sel, SourceLocation Loc) { + SetterName = Sel; + SetterNameLoc = Loc; + } ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; } void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; } Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -817,7 +817,8 @@ ObjCDeclSpec() : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr), - Nullability(0), GetterName(nullptr), SetterName(nullptr) { } + Nullability(0), GetterName(nullptr), SetterName(nullptr), + GetterNameLoc(SourceLocation()), SetterNameLoc(SourceLocation()) { } ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; } void setObjCDeclQualifier(ObjCDeclQualifier DQVal) { @@ -859,11 +860,19 @@ const IdentifierInfo *getGetterName() const { return GetterName; } IdentifierInfo *getGetterName() { return GetterName; } - void setGetterName(IdentifierInfo *name) { GetterName = name; } + SourceLocation getGetterNameLoc() const { return GetterNameLoc; } + void setGetterName(IdentifierInfo *name, SourceLocation loc) { + GetterName = name; + GetterNameLoc = loc; + } const IdentifierInfo *getSetterName() const { return SetterName; } IdentifierInfo *getSetterName() { return SetterName; } - void setSetterName(IdentifierInfo *name) { SetterName = name; } + SourceLocation getSetterNameLoc() const { return SetterNameLoc; } + void setSetterName(IdentifierInfo *name, SourceLocation loc) { + SetterName = name; + SetterNameLoc = loc; + } private: // FIXME: These two are unrelated and mutually exclusive. So perhaps @@ -880,6 +889,9 @@ IdentifierInfo *GetterName; // getter name or NULL if no getter IdentifierInfo *SetterName; // setter name or NULL if no setter + SourceLocation GetterNameLoc; // location of the getter attribute's value + SourceLocation SetterNameLoc; // location of the setter attribute's value + }; /// \brief Represents a C++ unqualified-id that has been parsed. Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3264,7 +3264,9 @@ SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, + SourceLocation GetterNameLoc, Selector SetterSel, + SourceLocation SetterNameLoc, const bool isReadWrite, unsigned &Attributes, const unsigned AttributesAsWritten, @@ -3280,7 +3282,9 @@ SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, + SourceLocation GetterNameLoc, Selector SetterSel, + SourceLocation SetterNameLoc, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -4580,8 +4580,10 @@ ToProperty->setPropertyAttributes(D->getPropertyAttributes()); ToProperty->setPropertyAttributesAsWritten( D->getPropertyAttributesAsWritten()); - ToProperty->setGetterName(Importer.Import(D->getGetterName())); - ToProperty->setSetterName(Importer.Import(D->getSetterName())); + ToProperty->setGetterName(Importer.Import(D->getGetterName()), + Importer.Import(D->getGetterNameLoc())); + ToProperty->setSetterName(Importer.Import(D->getSetterName()), + Importer.Import(D->getSetterNameLoc())); ToProperty->setGetterMethodDecl( cast_or_null(Importer.Import(D->getGetterMethodDecl()))); ToProperty->setSetterMethodDecl( Index: lib/Index/IndexBody.cpp =================================================================== --- lib/Index/IndexBody.cpp +++ lib/Index/IndexBody.cpp @@ -22,6 +22,10 @@ SmallVector StmtStack; typedef RecursiveASTVisitor base; + + Stmt *getParentStmt() const { + return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2]; + } public: BodyIndexer(IndexingContext &indexCtx, const NamedDecl *Parent, const DeclContext *DC) @@ -178,7 +182,8 @@ SymbolRoleSet Roles{}; SmallVector Relations; addCallRole(Roles, Relations); - if (E->isImplicit()) + Stmt *Containing = getParentStmt(); + if (E->isImplicit() || (Containing && isa(Containing))) Roles |= (unsigned)SymbolRole::Implicit; if (isDynamic(E)) { @@ -194,9 +199,12 @@ } bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { - if (E->isExplicitProperty()) + if (E->isExplicitProperty()) { + SmallVector Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(), - Parent, ParentDC, SymbolRoleSet(), {}, E); + Parent, ParentDC, Roles, Relations, E); + } // No need to do a handleReference for the objc method, because there will // be a message expr as part of PseudoObjectExpr. Index: lib/Index/IndexDecl.cpp =================================================================== --- lib/Index/IndexDecl.cpp +++ lib/Index/IndexDecl.cpp @@ -98,9 +98,28 @@ if (MethodLoc.isInvalid()) MethodLoc = D->getLocation(); + SourceLocation AttrLoc; + + // check for (getter=/setter=) + if (AssociatedProp) { + bool isGetter = !D->param_size(); + AttrLoc = isGetter ? + AssociatedProp->getGetterNameLoc(): + AssociatedProp->getSetterNameLoc(); + } + SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic; - if (D->isImplicit()) - Roles |= (SymbolRoleSet)SymbolRole::Implicit; + if (D->isImplicit()) { + if (AttrLoc.isValid()) { + MethodLoc = AttrLoc; + } else { + Roles |= (SymbolRoleSet)SymbolRole::Implicit; + } + } else if (AttrLoc.isValid()) { + IndexCtx.handleReference(D, AttrLoc, cast(D->getDeclContext()), + D->getDeclContext(), 0); + } + if (!IndexCtx.handleDecl(D, MethodLoc, Roles, Relations)) return false; IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D); Index: lib/Parse/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -929,7 +929,7 @@ if (IsSetter) { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); - DS.setSetterName(SelIdent); + DS.setSetterName(SelIdent, SelLoc); if (ExpectAndConsume(tok::colon, diag::err_expected_colon_after_setter_name)) { @@ -938,7 +938,7 @@ } } else { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter); - DS.setGetterName(SelIdent); + DS.setGetterName(SelIdent, SelLoc); } } else if (II->isStr("nonnull")) { if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability) Index: lib/Sema/SemaObjCProperty.cpp =================================================================== --- lib/Sema/SemaObjCProperty.cpp +++ lib/Sema/SemaObjCProperty.cpp @@ -200,9 +200,10 @@ if (ObjCCategoryDecl *CDecl = dyn_cast(ClassDecl)) { if (CDecl->IsClassExtension()) { Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc, - FD, GetterSel, SetterSel, - isReadWrite, - Attributes, + FD, + GetterSel, ODS.getGetterNameLoc(), + SetterSel, ODS.getSetterNameLoc(), + isReadWrite, Attributes, ODS.getPropertyAttributes(), T, TSI, MethodImplKind); if (!Res) @@ -212,9 +213,10 @@ if (!Res) { Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD, - GetterSel, SetterSel, isReadWrite, - Attributes, ODS.getPropertyAttributes(), - T, TSI, MethodImplKind); + GetterSel, ODS.getGetterNameLoc(), SetterSel, + ODS.getSetterNameLoc(), isReadWrite, Attributes, + ODS.getPropertyAttributes(), T, TSI, + MethodImplKind); if (lexicalDC) Res->setLexicalDeclContext(lexicalDC); } @@ -412,7 +414,10 @@ SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, - Selector GetterSel, Selector SetterSel, + Selector GetterSel, + SourceLocation GetterNameLoc, + Selector SetterSel, + SourceLocation SetterNameLoc, const bool isReadWrite, unsigned &Attributes, const unsigned AttributesAsWritten, @@ -512,7 +517,8 @@ // Create a new ObjCPropertyDecl with the DeclContext being // the class extension. ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc, LParenLoc, - FD, GetterSel, SetterSel, + FD, GetterSel, GetterNameLoc, + SetterSel, SetterNameLoc, isReadWrite, Attributes, AttributesAsWritten, T, TSI, MethodImplKind, DC); @@ -562,7 +568,9 @@ SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, + SourceLocation GetterNameLoc, Selector SetterSel, + SourceLocation SetterNameLoc, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, @@ -640,8 +648,8 @@ // Regardless of setter/getter attribute, we save the default getter/setter // selector names in anticipation of declaration of setter/getter methods. - PDecl->setGetterName(GetterSel); - PDecl->setSetterName(SetterSel); + PDecl->setGetterName(GetterSel, GetterNameLoc); + PDecl->setSetterName(SetterSel, SetterNameLoc); PDecl->setPropertyAttributesAsWritten( makePropertyAttributesAsWritten(AttributesAsWritten)); Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -1124,8 +1124,10 @@ (ObjCPropertyDecl::PropertyAttributeKind)Record.readInt()); D->setPropertyImplementation( (ObjCPropertyDecl::PropertyControl)Record.readInt()); - D->setGetterName(Record.readDeclarationName().getObjCSelector()); - D->setSetterName(Record.readDeclarationName().getObjCSelector()); + D->setGetterName(Record.readDeclarationName().getObjCSelector(), + ReadSourceLocation()); + D->setSetterName(Record.readDeclarationName().getObjCSelector(), + ReadSourceLocation()); D->setGetterMethodDecl(ReadDeclAs()); D->setSetterMethodDecl(ReadDeclAs()); D->setPropertyIvarDecl(ReadDeclAs()); Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -799,7 +799,9 @@ // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyImplementation()); Record.AddDeclarationName(D->getGetterName()); + Record.AddSourceLocation(D->getGetterNameLoc()); Record.AddDeclarationName(D->getSetterName()); + Record.AddSourceLocation(D->getSetterNameLoc()); Record.AddDeclRef(D->getGetterMethodDecl()); Record.AddDeclRef(D->getSetterMethodDecl()); Record.AddDeclRef(D->getPropertyIvarDecl()); Index: test/Index/Core/index-source.m =================================================================== --- test/Index/Core/index-source.m +++ test/Index/Core/index-source.m @@ -121,39 +121,79 @@ @end @interface I2 -@property (readwrite) id prop; +// CHECK: [[@LINE-1]]:12 | class/ObjC | I2 | [[I2_USR:.*]] | {{.*}} | Decl | rel: 0 -// CHECK: [[@LINE+4]]:63 | instance-property(IB,IBColl)/ObjC | buttons | c:objc(cs)I2(py)buttons | | Decl,RelChild | rel: 1 -// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2 +@property (readwrite) id prop; +// CHECK: [[@LINE-1]]:26 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR:.*]] | -[I2 prop] | Decl,Dyn,Impl,RelChild,RelAcc | rel: 2 +// CHECK: [[@LINE-2]]:26 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR:.*]] | -[I2 setProp:] | Decl,Dyn,Impl,RelChild,RelAcc | rel: 2 +// CHECK: [[@LINE-3]]:26 | instance-property/ObjC | prop | [[I2_prop_USR:.*]] | | Decl,RelChild | rel: 1 + +@property (readwrite, getter=customGet, setter=customSet:) id unrelated; +// CHECK: [[@LINE-1]]:30 | instance-method/acc-get/ObjC | customGet | {{.*}} | -[I2 customGet] | Decl,Dyn,RelChild,RelAcc | rel: 2 +// CHECK: [[@LINE-2]]:48 | instance-method/acc-set/ObjC | customSet: | {{.*}} | -[I2 customSet:] | Decl,Dyn,RelChild,RelAcc | rel: 2 +// CHECK: [[@LINE-3]]:63 | instance-property/ObjC | unrelated | {{.*}} | | Decl,RelChild | rel: 1 + +-(id)declaredGet; +@property (readwrite, getter=declaredGet) id otherProp; +// CHECK: [[@LINE-1]]:30 | instance-method/acc-get/ObjC | declaredGet | {{.*}} | -[I2 declaredGet] | Ref,RelCont | rel: 1 +// CHECK: [[@LINE-3]]:6 | instance-method/acc-get/ObjC | declaredGet | {{.*}} | -[I2 declaredGet] | Decl,Dyn,RelChild,RelAcc | rel: 2 +// CHECK: [[@LINE-3]]:46 | instance-method/acc-set/ObjC | setOtherProp: | {{.*}} | -[I2 setOtherProp:] | Decl,Dyn,Impl,RelChild,RelAcc | rel: 2 + +// CHECK: [[@LINE+4]]:63 | instance-property(IB,IBColl)/ObjC | buttons | [[buttons_USR:.*]] | | Decl,RelChild | rel: 1 +// CHECK-NEXT: RelChild | I2 | [[I2_USR]] // CHECK: [[@LINE+2]]:50 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont,RelIBType | rel: 1 -// CHECK-NEXT: RelCont,RelIBType | buttons | c:objc(cs)I2(py)buttons +// CHECK-NEXT: RelCont,RelIBType | buttons | [[buttons_USR]] @property (nonatomic, strong) IBOutletCollection(I1) NSArray *buttons; @end @implementation I2 -// CHECK: [[@LINE+9]]:13 | instance-property/ObjC | prop | c:objc(cs)I2(py)prop | | Def,RelChild,RelAcc | rel: 2 -// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2 +// CHECK: [[@LINE+9]]:13 | instance-property/ObjC | prop | [[I2_prop_USR:.*]] | | Def,RelChild,RelAcc | rel: 2 +// CHECK-NEXT: RelChild | I2 | [[I2_USR]] // CHECK-NEXT: RelAcc | _prop | c:objc(cs)I2@_prop -// CHECK: [[@LINE+6]]:13 | instance-method/acc-get/ObjC | prop | c:objc(cs)I2(im)prop | -[I2 prop] | Def,Impl,RelChild | rel: 1 -// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2 -// CHECK: [[@LINE+4]]:13 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I2(im)setProp: | -[I2 setProp:] | Def,Impl,RelChild | rel: 1 -// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2 +// CHECK: [[@LINE+6]]:13 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR]] | -[I2 prop] | Def,Impl,RelChild | rel: 1 +// CHECK-NEXT: RelChild | I2 | [[I2_USR]] +// CHECK: [[@LINE+4]]:13 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR]] | -[I2 setProp:] | Def,Impl,RelChild | rel: 1 +// CHECK-NEXT: RelChild | I2 | [[I2_USR]] // CHECK: [[@LINE+2]]:20 | field/ObjC | _prop | c:objc(cs)I2@_prop | | Def,RelChild | rel: 1 -// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2 +// CHECK-NEXT: RelChild | I2 | [[I2_USR]] @synthesize prop = _prop; -// CHECK: [[@LINE+11]]:12 | instance-method(IB)/ObjC | doAction:foo: | c:objc(cs)I2(im)doAction:foo: | -[I2 doAction:foo:] | Def,Dyn,RelChild | rel: 1 -// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2 +// CHECK: [[@LINE+11]]:12 | instance-method(IB)/ObjC | doAction:foo: | [[doAction_USR:.*]] | -[I2 doAction:foo:] | Def,Dyn,RelChild | rel: 1 +// CHECK-NEXT: RelChild | I2 | [[I2_USR]] // CHECK: [[@LINE+9]]:22 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont,RelIBType | rel: 1 -// CHECK-NEXT: RelCont,RelIBType | doAction:foo: | c:objc(cs)I2(im)doAction:foo: +// CHECK-NEXT: RelCont,RelIBType | doAction:foo: | [[doAction_USR]] // CHECK-NOT: [[@LINE+7]]:27 | param // LOCAL: [[@LINE+6]]:27 | param(local)/C | sender | c:{{.*}} | _sender | Def,RelChild | rel: 1 -// LOCAL-NEXT: RelChild | doAction:foo: | c:objc(cs)I2(im)doAction:foo: +// LOCAL-NEXT: RelChild | doAction:foo: | [[doAction_USR:.*]] // CHECK: [[@LINE+4]]:39 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont | rel: 1 // CHECK-NOT: [[@LINE+3]]:44 | param // LOCAL: [[@LINE+2]]:44 | param(local)/C | bar | c:{{.*}} | _bar | Def,RelChild | rel: 1 -// LOCAL-NEXT: RelChild | doAction:foo: | c:objc(cs)I2(im)doAction:foo: --(IBAction)doAction:(I1 *)sender foo:(I1 *)bar {} +// LOCAL-NEXT: RelChild | doAction:foo: | [[doAction_USR]] +-(IBAction)doAction:(I1 *)sender foo:(I1 *)bar { + [self prop]; + // CHECK: [[@LINE-1]]:9 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR]] | -[I2 prop] | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2 + // CHECK-NEXT: RelCall,RelCont | doAction:foo: | [[doAction_USR]] + // CHECK-NEXT: RelRec | I2 | [[I2_USR]] + + [self setProp: bar]; + // CHECK: [[@LINE-1]]:9 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR]] | -[I2 setProp:] | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2 + // CHECK-NEXT: RelCall,RelCont | doAction:foo: | [[doAction_USR]] + // CHECK-NEXT: RelRec | I2 | [[I2_USR]] + + self.prop; + // CHECK: [[@LINE-1]]:8 | instance-property/ObjC | prop | [[I2_prop_USR]] | | Ref,RelCont | rel: 1 + // CHECK-NEXT: RelCont | doAction:foo: | [[doAction_USR]] + // CHECK: [[@LINE-3]]:8 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR]] | -[I2 prop] | Ref,Call,Dyn,Impl,RelRec,RelCall,RelCont | rel: 2 + // CHECK-NEXT: RelCall,RelCont | doAction:foo: | [[doAction_USR]] + // CHECK-NEXT: RelRec | I2 | [[I2_USR]] + + self.prop = self.prop; + // CHECK: [[@LINE-1]]:8 | instance-property/ObjC | prop | [[I2_prop_USR]] | | Ref,Writ,RelCont | rel: 1 + // CHECK-NEXT: RelCont | doAction:foo: | [[doAction_USR]] + // CHECK:[[@LINE-3]]:8 | instance-method/acc-set/ObjC | setProp: | [[I2_prop_setter_USR]] | -[I2 setProp:] | Ref,Call,Dyn,Impl,RelRec,RelCall,RelCont | rel: 2 + // CHECK-NEXT: RelCall,RelCont | doAction:foo: | [[doAction_USR]] + // CHECK-NEXT: RelRec | I2 | [[I2_USR]] +} @end @interface I3