[index] Fixes for locations and relations in Objective C categories and getters/setters

- Add entries for protocols on categories
- Add relation between categories and class they extend
- Add relation between getters/setters and their corresponding property
- Use category name location as the location of category decls/defs if it has one

llvm-svn: 285120
This commit is contained in:
Argyrios Kyrtzidis 2016-10-25 21:11:22 +00:00
parent 83fb4019f7
commit 806faaf42b
5 changed files with 75 additions and 13 deletions

View File

@ -88,8 +88,10 @@ enum class SymbolRole : uint16_t {
RelationOverrideOf = 1 << 11,
RelationReceivedBy = 1 << 12,
RelationCalledBy = 1 << 13,
RelationExtendedBy = 1 << 14,
RelationAccessorOf = 1 << 15,
};
static const unsigned SymbolRoleBitNum = 14;
static const unsigned SymbolRoleBitNum = 16;
typedef unsigned SymbolRoleSet;
/// Represents a relation to another symbol for a symbol occurrence.

View File

@ -75,8 +75,21 @@ public:
}
}
bool handleObjCMethod(const ObjCMethodDecl *D) {
if (!IndexCtx.handleDecl(D, (unsigned)SymbolRole::Dynamic))
bool handleObjCMethod(const ObjCMethodDecl *D,
const ObjCPropertyDecl *AssociatedProp = nullptr) {
SmallVector<SymbolRelation, 4> Relations;
SmallVector<const ObjCMethodDecl*, 4> Overriden;
D->getOverriddenMethods(Overriden);
for(auto overridden: Overriden) {
Relations.emplace_back((unsigned) SymbolRole::RelationOverrideOf,
overridden);
}
if (AssociatedProp)
Relations.emplace_back((unsigned)SymbolRole::RelationAccessorOf,
AssociatedProp);
if (!IndexCtx.handleDecl(D, (unsigned)SymbolRole::Dynamic, Relations))
return false;
IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
for (const auto *I : D->parameters())
@ -269,9 +282,18 @@ public:
}
bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
if (!IndexCtx.handleDecl(D))
return false;
IndexCtx.indexDeclContext(D);
const ObjCInterfaceDecl *C = D->getClassInterface();
if (C)
TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D,
SymbolRoleSet(), SymbolRelation{
(unsigned)SymbolRole::RelationExtendedBy, D
}));
SourceLocation CategoryLoc = D->getCategoryNameLoc();
if (!CategoryLoc.isValid())
CategoryLoc = D->getLocation();
TRY_TO(IndexCtx.handleDecl(D, CategoryLoc));
TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D));
TRY_TO(IndexCtx.indexDeclContext(D));
return true;
}
@ -279,8 +301,14 @@ public:
const ObjCCategoryDecl *Cat = D->getCategoryDecl();
if (!Cat)
return true;
if (!IndexCtx.handleDecl(D))
const ObjCInterfaceDecl *C = D->getClassInterface();
if (C)
TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D,
SymbolRoleSet()));
SourceLocation CategoryLoc = D->getCategoryNameLoc();
if (!CategoryLoc.isValid())
CategoryLoc = D->getLocation();
if (!IndexCtx.handleDecl(D, CategoryLoc))
return false;
IndexCtx.indexDeclContext(D);
return true;
@ -299,10 +327,10 @@ public:
bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
handleObjCMethod(MD);
handleObjCMethod(MD, D);
if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
handleObjCMethod(MD);
handleObjCMethod(MD, D);
if (!IndexCtx.handleDecl(D))
return false;
IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);

View File

@ -262,6 +262,8 @@ void index::applyForEachSymbolRole(SymbolRoleSet Roles,
APPLY_FOR_ROLE(RelationOverrideOf);
APPLY_FOR_ROLE(RelationReceivedBy);
APPLY_FOR_ROLE(RelationCalledBy);
APPLY_FOR_ROLE(RelationExtendedBy);
APPLY_FOR_ROLE(RelationAccessorOf);
#undef APPLY_FOR_ROLE
}
@ -288,6 +290,8 @@ void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {
case SymbolRole::RelationOverrideOf: OS << "RelOver"; break;
case SymbolRole::RelationReceivedBy: OS << "RelRec"; break;
case SymbolRole::RelationCalledBy: OS << "RelCall"; break;
case SymbolRole::RelationExtendedBy: OS << "RelExt"; break;
case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break;
}
});
}

View File

@ -95,13 +95,37 @@ extern int setjmp(jmp_buf);
@interface I3
@property (readwrite) id prop;
// CHECK: [[@LINE+3]]:1 | instance-method/ObjC | prop | c:objc(cs)I3(im)prop | -[I3 prop] | Decl,Dyn,RelChild,RelAcc | rel: 2
// CHECK-NEXT: RelChild | I3 | c:objc(cs)I3
// CHECK-NEXT: RelAcc | prop | c:objc(cs)I3(py)prop
-(id)prop;
// CHECK: [[@LINE+3]]:1 | instance-method/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Decl,Dyn,RelChild,RelAcc | rel: 2
// CHECK-NEXT: RelChild | I3 | c:objc(cs)I3
// CHECK-NEXT: RelAcc | prop | c:objc(cs)I3(py)prop
-(void)setProp:(id)p;
@end
// CHECK: [[@LINE+1]]:17 | class/ObjC | I3 | c:objc(cs)I3 | <no-cgname> | Def | rel: 0
@implementation I3
// CHECK: [[@LINE+3]]:13 | instance-property/ObjC | prop | c:objc(cs)I3(py)prop | <no-cgname> | Ref | rel: 0
// CHECK: [[@LINE+2]]:13 | instance-method/ObjC | prop | c:objc(cs)I3(im)prop | -[I3 prop] | Def,RelChild | rel: 1
// CHECK: [[@LINE+1]]:13 | instance-method/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Def,RelChild | rel: 1
@synthesize prop = _prop;
@end
// CHECK: [[@LINE+5]]:12 | class/ObjC | I3 | c:objc(cs)I3 | _OBJC_CLASS_$_I3 | Ref,RelExt | rel: 1
// CHECK-NEXT: RelExt | bar | c:objc(cy)I3@bar
// CHECK: [[@LINE+3]]:15 | extension/ObjC | bar | c:objc(cy)I3@bar | <no-cgname> | Decl | rel: 0
// CHECK: [[@LINE+2]]:21 | protocol/ObjC | Prot1 | c:objc(pl)Prot1 | <no-cgname> | Ref,RelBase | rel: 1
// CHECK-NEXT: RelBase | bar | c:objc(cy)I3@bar
@interface I3(bar) <Prot1>
@end
// CHECK: [[@LINE+2]]:17 | class/ObjC | I3 | c:objc(cs)I3 | _OBJC_CLASS_$_I3 | Ref | rel: 0
// CHECK: [[@LINE+1]]:20 | extension/ObjC | I3 | c:objc(cy)I3@bar | <no-cgname> | Def | rel: 0
@implementation I3(bar)
@end
// CHECK: [[@LINE+1]]:12 | extension/ObjC | <no-name> | <no-usr> | <no-cgname> | Decl | rel: 0
@interface NonExistent()
@end

View File

@ -26,10 +26,13 @@
-(void)testIt2 {}
@end
// CHECK: [[@LINE+1]]:12 | extension/ObjC | cat | c:objc(cy)MyTestCase@cat | <no-cgname> | Decl | rel: 0
// CHECK: [[@LINE+3]]:12 | class(test)/ObjC | MyTestCase | c:objc(cs)MyTestCase | _OBJC_CLASS_$_MyTestCase | Ref,RelExt | rel: 1
// CHECK-NEXT: RelExt | cat | c:objc(cy)MyTestCase@cat
// CHECK: [[@LINE+1]]:23 | extension/ObjC | cat | c:objc(cy)MyTestCase@cat | <no-cgname> | Decl | rel: 0
@interface MyTestCase(cat)
@end
// CHECK: [[@LINE+1]]:17 | extension/ObjC | MyTestCase | c:objc(cy)MyTestCase@cat | <no-cgname> | Def | rel: 0
// CHECK: [[@LINE+2]]:17 | class(test)/ObjC | MyTestCase | c:objc(cs)MyTestCase | _OBJC_CLASS_$_MyTestCase | Ref | rel: 0
// CHECK: [[@LINE+1]]:28 | extension/ObjC | MyTestCase | c:objc(cy)MyTestCase@cat | <no-cgname> | Def | rel: 0
@implementation MyTestCase(cat)
// CHECK: [[@LINE+1]]:1 | instance-method(test)/ObjC | testInCat | c:objc(cs)MyTestCase(im)testInCat | -[MyTestCase(cat) testInCat] | Def,Dyn,RelChild | rel: 1
- (void)testInCat {}
@ -38,7 +41,8 @@
@class NSButton;
@interface IBCls
// CHECK: [[@LINE+2]]:34 | instance-method/ObjC | prop | c:objc(cs)IBCls(im)prop | -[IBCls prop] | Decl,Dyn,RelChild | rel: 1
// CHECK: [[@LINE+2]]:34 | instance-method/ObjC | prop | c:objc(cs)IBCls(im)prop | -[IBCls prop] | Decl,Dyn,RelChild,RelAcc | rel: 2
// CHECK: [[@LINE+1]]:34 | instance-property(IB)/ObjC | prop | c:objc(cs)IBCls(py)prop | <no-cgname> | Decl,RelChild | rel: 1
@property (readonly) IBOutlet id prop;
// CHECK: [[@LINE+1]]:54 | instance-property(IB,IBColl)/ObjC | propColl | c:objc(cs)IBCls(py)propColl | <no-cgname> | Decl,RelChild | rel: 1