From: Argyrios Kyrtzidis Date: Fri, 22 Apr 2016 07:21:10 +0000 (+0000) Subject: [index] Add a SymbolSubKind for an ObjC unit test. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=17e80200b6308e6f1c65e50d730314708155d7f0;p=clang [index] Add a SymbolSubKind for an ObjC unit test. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@267117 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Index/IndexSymbol.h b/include/clang/Index/IndexSymbol.h index 68d97d75ac..bd19771a18 100644 --- a/include/clang/Index/IndexSymbol.h +++ b/include/clang/Index/IndexSymbol.h @@ -63,8 +63,9 @@ enum class SymbolSubKind : uint8_t { Generic = 1 << 0, TemplatePartialSpecialization = 1 << 1, TemplateSpecialization = 1 << 2, + UnitTest = 1 << 3, }; -static const unsigned SymbolSubKindBitNum = 3; +static const unsigned SymbolSubKindBitNum = 4; typedef unsigned SymbolSubKindSet; /// Set of roles that are attributed to symbol occurrences. diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp index 097aaf0721..ba83d0cdef 100644 --- a/lib/Index/IndexSymbol.cpp +++ b/lib/Index/IndexSymbol.cpp @@ -16,6 +16,30 @@ using namespace clang; using namespace clang::index; +/// \returns true if \c D is a subclass of 'XCTestCase'. +static bool isUnitTestCase(const ObjCInterfaceDecl *D) { + if (!D) + return false; + while (const ObjCInterfaceDecl *SuperD = D->getSuperClass()) { + if (SuperD->getName() == "XCTestCase") + return true; + D = SuperD; + } + return false; +} + +/// \returns true if \c D is in a subclass of 'XCTestCase', returns void, has +/// no parameters, and its name starts with 'test'. +static bool isUnitTest(const ObjCMethodDecl *D) { + if (!D->parameters().empty()) + return false; + if (!D->getReturnType()->isVoidType()) + return false; + if (!D->getSelector().getNameForSlot(0).startswith("test")) + return false; + return isUnitTestCase(D->getClassInterface()); +} + SymbolInfo index::getSymbolInfo(const Decl *D) { assert(D); SymbolInfo Info; @@ -84,10 +108,16 @@ SymbolInfo index::getSymbolInfo(const Decl *D) { case Decl::EnumConstant: Info.Kind = SymbolKind::EnumConstant; break; case Decl::ObjCInterface: - case Decl::ObjCImplementation: + case Decl::ObjCImplementation: { Info.Kind = SymbolKind::Class; Info.Lang = SymbolLanguage::ObjC; + const ObjCInterfaceDecl *ClsD = dyn_cast(D); + if (!ClsD) + ClsD = cast(D)->getClassInterface(); + if (isUnitTestCase(ClsD)) + Info.SubKinds |= (unsigned)SymbolSubKind::UnitTest; break; + } case Decl::ObjCProtocol: Info.Kind = SymbolKind::Protocol; Info.Lang = SymbolLanguage::ObjC; @@ -103,6 +133,8 @@ SymbolInfo index::getSymbolInfo(const Decl *D) { else Info.Kind = SymbolKind::ClassMethod; Info.Lang = SymbolLanguage::ObjC; + if (isUnitTest(cast(D))) + Info.SubKinds |= (unsigned)SymbolSubKind::UnitTest; break; case Decl::ObjCProperty: Info.Kind = SymbolKind::InstanceProperty; @@ -314,6 +346,7 @@ void index::applyForEachSymbolSubKind(SymbolSubKindSet SubKinds, APPLY_FOR_SUBKIND(Generic); APPLY_FOR_SUBKIND(TemplatePartialSpecialization); APPLY_FOR_SUBKIND(TemplateSpecialization); + APPLY_FOR_SUBKIND(UnitTest); #undef APPLY_FOR_SUBKIND } @@ -329,6 +362,7 @@ void index::printSymbolSubKinds(SymbolSubKindSet SubKinds, raw_ostream &OS) { case SymbolSubKind::Generic: OS << "Gen"; break; case SymbolSubKind::TemplatePartialSpecialization: OS << "TPS"; break; case SymbolSubKind::TemplateSpecialization: OS << "TS"; break; + case SymbolSubKind::UnitTest: OS << "test"; break; } }); } diff --git a/test/Index/Core/index-subkinds.m b/test/Index/Core/index-subkinds.m new file mode 100644 index 0000000000..a78e1235a3 --- /dev/null +++ b/test/Index/Core/index-subkinds.m @@ -0,0 +1,36 @@ +// RUN: c-index-test core -print-source-symbols -- %s -target x86_64-apple-macosx10.7 | FileCheck %s + +// CHECK: [[@LINE+1]]:12 | class/ObjC | XCTestCase | c:objc(cs)XCTestCase | _OBJC_CLASS_$_XCTestCase | Decl | rel: 0 +@interface XCTestCase +@end + +// CHECK: [[@LINE+1]]:12 | class(test)/ObjC | MyTestCase | c:objc(cs)MyTestCase | _OBJC_CLASS_$_MyTestCase | Decl | rel: 0 +@interface MyTestCase : XCTestCase +@end +// CHECK: [[@LINE+1]]:17 | class(test)/ObjC | MyTestCase | c:objc(cs)MyTestCase | | Def | rel: 0 +@implementation MyTestCase +// CHECK: [[@LINE+1]]:1 | instance-method(test)/ObjC | testMe | c:objc(cs)MyTestCase(im)testMe | -[MyTestCase testMe] | Def,Dyn,RelChild | rel: 1 +-(void)testMe {} +// CHECK: [[@LINE+1]]:1 | instance-method/ObjC | testResult | c:objc(cs)MyTestCase(im)testResult | -[MyTestCase testResult] | Def,Dyn,RelChild | rel: 1 +-(id)testResult { return 0; } +// CHECK: [[@LINE+1]]:1 | instance-method/ObjC | testWithInt: | c:objc(cs)MyTestCase(im)testWithInt: | -[MyTestCase testWithInt:] | Def,Dyn,RelChild | rel: 1 +-(void)testWithInt:(int)i {} +@end + +// CHECK: [[@LINE+1]]:12 | class(test)/ObjC | SubTestCase | c:objc(cs)SubTestCase | _OBJC_CLASS_$_SubTestCase | Decl | rel: 0 +@interface SubTestCase : MyTestCase +@end +// CHECK: [[@LINE+1]]:17 | class(test)/ObjC | SubTestCase | c:objc(cs)SubTestCase | | Def | rel: 0 +@implementation SubTestCase +// CHECK: [[@LINE+1]]:1 | instance-method(test)/ObjC | testIt2 | c:objc(cs)SubTestCase(im)testIt2 | -[SubTestCase testIt2] | Def,Dyn,RelChild | rel: 1 +-(void)testIt2 {} +@end + +// CHECK: [[@LINE+1]]:12 | extension/ObjC | cat | c:objc(cy)MyTestCase@cat | | Decl | rel: 0 +@interface MyTestCase(cat) +@end +// CHECK: [[@LINE+1]]:17 | extension/ObjC | MyTestCase | c:objc(cy)MyTestCase@cat | | 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 {} +@end diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp index b19c8cbba7..d11b490e81 100644 --- a/tools/c-index-test/core_main.cpp +++ b/tools/c-index-test/core_main.cpp @@ -169,8 +169,9 @@ static bool printSourceSymbols(ArrayRef Args) { static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS) { OS << getSymbolKindString(SymInfo.Kind); if (SymInfo.SubKinds) { - OS << '-'; + OS << '('; printSymbolSubKinds(SymInfo.SubKinds, OS); + OS << ')'; } OS << '/' << getSymbolLanguageString(SymInfo.Lang); }