Index: include/clang/Index/IndexSymbol.h =================================================================== --- include/clang/Index/IndexSymbol.h +++ include/clang/Index/IndexSymbol.h @@ -66,6 +66,7 @@ CXXMoveConstructor, AccessorGetter, AccessorSetter, + Parameter, }; /// Set of properties that provide additional info about a symbol. @@ -77,8 +78,9 @@ IBAnnotated = 1 << 4, IBOutletCollection = 1 << 5, GKInspectable = 1 << 6, + Local = 1 << 7, }; -static const unsigned SymbolPropertyBitNum = 7; +static const unsigned SymbolPropertyBitNum = 8; typedef unsigned SymbolPropertySet; /// Set of roles that are attributed to symbol occurrences. @@ -125,6 +127,8 @@ SymbolInfo getSymbolInfo(const Decl *D); +bool isFunctionLocalSymbol(const Decl *D); + void applyForEachSymbolRole(SymbolRoleSet Roles, llvm::function_ref Fn); void printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS); Index: lib/Index/IndexBody.cpp =================================================================== --- lib/Index/IndexBody.cpp +++ lib/Index/IndexBody.cpp @@ -269,7 +269,7 @@ const Decl *D = *I; if (!D) continue; - if (!IndexCtx.isFunctionLocalDecl(D)) + if (!isFunctionLocalSymbol(D)) IndexCtx.indexTopLevelDecl(D); } Index: lib/Index/IndexSymbol.cpp =================================================================== --- lib/Index/IndexSymbol.cpp +++ lib/Index/IndexSymbol.cpp @@ -49,6 +49,34 @@ } } +bool index::isFunctionLocalSymbol(const Decl *D) { + assert(D); + + if (isa(D)) + return true; + + if (isa(D)) + return true; + + if (!D->getParentFunctionOrMethod()) + return false; + + if (const NamedDecl *ND = dyn_cast(D)) { + switch (ND->getFormalLinkage()) { + case NoLinkage: + case VisibleNoLinkage: + case InternalLinkage: + return true; + case UniqueExternalLinkage: + llvm_unreachable("Not a sema linkage"); + case ExternalLinkage: + return false; + } + } + + return true; +} + SymbolInfo index::getSymbolInfo(const Decl *D) { assert(D); SymbolInfo Info; @@ -57,6 +85,10 @@ Info.Properties = SymbolPropertySet(); Info.Lang = SymbolLanguage::C; + if (isFunctionLocalSymbol(D)) { + Info.Properties |= (unsigned)SymbolProperty::Local; + } + if (const TagDecl *TD = dyn_cast(D)) { switch (TD->getTagKind()) { case TTK_Struct: @@ -94,10 +126,13 @@ } else if (auto *VD = dyn_cast(D)) { Info.Kind = SymbolKind::Variable; - if (isa(D->getDeclContext())) { + if (isa(D)) { + Info.SubKind = SymbolSubKind::Parameter; + } else if (isa(D->getDeclContext())) { Info.Kind = SymbolKind::StaticProperty; Info.Lang = SymbolLanguage::CXX; } + if (isa(D)) { Info.Lang = SymbolLanguage::CXX; Info.Properties |= (unsigned)SymbolProperty::Generic; @@ -389,6 +424,7 @@ case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor"; case SymbolSubKind::AccessorGetter: return "acc-get"; case SymbolSubKind::AccessorSetter: return "acc-set"; + case SymbolSubKind::Parameter: return "param"; } llvm_unreachable("invalid symbol subkind"); } @@ -415,6 +451,7 @@ APPLY_FOR_PROPERTY(IBAnnotated); APPLY_FOR_PROPERTY(IBOutletCollection); APPLY_FOR_PROPERTY(GKInspectable); + APPLY_FOR_PROPERTY(Local); #undef APPLY_FOR_PROPERTY } @@ -434,6 +471,7 @@ case SymbolProperty::IBAnnotated: OS << "IB"; break; case SymbolProperty::IBOutletCollection: OS << "IBColl"; break; case SymbolProperty::GKInspectable: OS << "GKI"; break; + case SymbolProperty::Local: OS << "local"; break; } }); } Index: lib/Index/IndexTypeSourceInfo.cpp =================================================================== --- lib/Index/IndexTypeSourceInfo.cpp +++ lib/Index/IndexTypeSourceInfo.cpp @@ -191,7 +191,7 @@ } void IndexingContext::indexTagDecl(const TagDecl *D) { - if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D)) + if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D)) return; if (handleDecl(D)) { Index: lib/Index/IndexingContext.h =================================================================== --- lib/Index/IndexingContext.h +++ lib/Index/IndexingContext.h @@ -58,7 +58,6 @@ return false; } - static bool isFunctionLocalDecl(const Decl *D); static bool isTemplateImplicitInstantiation(const Decl *D); bool handleDecl(const Decl *D, SymbolRoleSet Roles = SymbolRoleSet(), Index: lib/Index/IndexingContext.cpp =================================================================== --- lib/Index/IndexingContext.cpp +++ lib/Index/IndexingContext.cpp @@ -50,7 +50,7 @@ ArrayRef Relations, const Expr *RefE, const Decl *RefD) { - if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D)) + if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D)) return true; if (isa(D) || isa(D)) @@ -100,34 +100,6 @@ return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset); } -bool IndexingContext::isFunctionLocalDecl(const Decl *D) { - assert(D); - - if (isa(D)) - return true; - - if (isa(D)) - return true; - - if (!D->getParentFunctionOrMethod()) - return false; - - if (const NamedDecl *ND = dyn_cast(D)) { - switch (ND->getFormalLinkage()) { - case NoLinkage: - case VisibleNoLinkage: - case InternalLinkage: - return true; - case UniqueExternalLinkage: - llvm_unreachable("Not a sema linkage"); - case ExternalLinkage: - return false; - } - } - - return true; -} - bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { TemplateSpecializationKind TKind = TSK_Undeclared; if (const ClassTemplateSpecializationDecl * @@ -316,12 +288,12 @@ }; if (Parent) { - if (IsRef) { + if (IsRef || isFunctionLocalSymbol(D)) { addRelation(SymbolRelation{ (unsigned)SymbolRole::RelationContainedBy, Parent }); - } else if (!cast(Parent)->isFunctionOrMethod()) { + } else { addRelation(SymbolRelation{ (unsigned)SymbolRole::RelationChildOf, Parent Index: test/Index/Core/index-source.m =================================================================== --- test/Index/Core/index-source.m +++ test/Index/Core/index-source.m @@ -1,4 +1,5 @@ // RUN: c-index-test core -print-source-symbols -- %s -target x86_64-apple-macosx10.7 | FileCheck %s +// RUN: c-index-test core -print-source-symbols -include-locals -- %s -target x86_64-apple-macosx10.7 | FileCheck -check-prefix=LOCAL %s @interface Base // CHECK: [[@LINE-1]]:12 | class/ObjC | Base | c:objc(cs)Base | _OBJC_CLASS_$_Base | Decl | rel: 0 @@ -13,10 +14,33 @@ @end void foo(); -// CHECK: [[@LINE+3]]:6 | function/C | goo | c:@F@goo | _goo | Def | rel: 0 -// CHECK: [[@LINE+2]]:10 | class/ObjC | Base | c:objc(cs)Base | _OBJC_CLASS_$_Base | Ref,RelCont | rel: 1 +// CHECK: [[@LINE+6]]:6 | function/C | goo | c:@F@goo | _goo | Def | rel: 0 +// CHECK: [[@LINE+5]]:10 | class/ObjC | Base | c:objc(cs)Base | _OBJC_CLASS_$_Base | Ref,RelCont | rel: 1 // CHECK-NEXT: RelCont | goo | c:@F@goo +// CHECK-NOT: [[@LINE+3]]:16 | variable/param/C | b | {{.*}} | _b | Def,RelCont | rel: 1 +// LOCAL: [[@LINE+2]]:16 | variable/param(local)/C | b | [[b_USR:c:.*]] | _b | Def,RelCont | rel: 1 +// LOCAL-NEXT: RelCont | goo | c:@F@goo void goo(Base *b) { + // CHECK-NOT: [[@LINE+6]]:7 | variable(local)/C | x | [[x_USR:c:.*]] | _x | Def,RelCont | rel: 1 + // LOCAL: [[@LINE+5]]:7 | variable(local)/C | x | [[x_USR:c:.*]] | _x | Def,RelCont | rel: 1 + // LOCAL-NEXT: RelCont | goo | c:@F@goo + // CHECK-NOT: [[@LINE+3]]:11 | variable/param(local)/C | b | [[b_USR]] | _b | Ref,Read,RelCont | rel: 1 + // LOCAL: [[@LINE+2]]:11 | variable/param(local)/C | b | [[b_USR]] | _b | Ref,Read,RelCont | rel: 1 + // LOCAL-NEXT: RelCont | x | [[x_USR]] + int x = b; + // CHECK-NOT: [[@LINE+5]]:7 | variable(local)/C | y | [[y_USR:c:.*]] | _y | Def,RelCont | rel: 1 + // LOCAL: [[@LINE+4]]:7 | variable(local)/C | y | [[y_USR:c:.*]] | _y | Def,RelCont | rel: 1 + // CHECK-NOT: [[@LINE+3]]:11 | variable(local)/C | x | [[x_USR]] | _x | Ref,Read,RelCont | rel: 1 + // LOCAL: [[@LINE+2]]:11 | variable(local)/C | x | [[x_USR]] | _x | Ref,Read,RelCont | rel: 1 + // LOCAL-NEXT: RelCont | y | [[y_USR]] + int y = x; + + // CHECK-NOT: [[@LINE+1]]:10 | struct(local)/C | Foo | c:{{.*}} | | Def,RelCont | rel: 1 + // LOCAL: [[@LINE+1]]:10 | struct(local)/C | Foo | c:{{.*}} | | Def,RelCont | rel: 1 + struct Foo { + int i; + }; + // CHECK: [[@LINE+2]]:3 | function/C | foo | c:@F@foo | _foo | Ref,Call,RelCall,RelCont | rel: 1 // CHECK-NEXT: RelCall,RelCont | goo | c:@F@goo foo(); @@ -118,11 +142,17 @@ // CHECK-NEXT: RelChild | I2 | c:objc(cs)I2 @synthesize prop = _prop; -// CHECK: [[@LINE+5]]:12 | instance-method(IB)/ObjC | doAction:foo: | c:objc(cs)I2(im)doAction:foo: | -[I2 doAction:foo:] | Def,Dyn,RelChild | rel: 1 +// 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+3]]:22 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont,RelIBType | rel: 1 +// 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: [[@LINE+1]]:39 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont | rel: 1 +// CHECK-NOT: [[@LINE+7]]:27 | variable/param(local)/C | sender | c:{{.*}} | _sender | Def,RelCont | rel: 1 +// LOCAL: [[@LINE+6]]:27 | variable/param(local)/C | sender | c:{{.*}} | _sender | Def,RelCont | rel: 1 +// LOCAL-NEXT: RelCont | doAction:foo: | c:objc(cs)I2(im)doAction:foo: +// CHECK: [[@LINE+4]]:39 | class/ObjC | I1 | c:objc(cs)I1 | _OBJC_CLASS_$_I1 | Ref,RelCont | rel: 1 +// CHECK-NOT: [[@LINE+3]]:44 | variable/param(local)/C | bar | c:{{.*}} | _bar | Def,RelCont | rel: 1 +// LOCAL: [[@LINE+2]]:44 | variable/param(local)/C | bar | c:{{.*}} | _bar | Def,RelCont | rel: 1 +// LOCAL-NEXT: RelCont | doAction:foo: | c:objc(cs)I2(im)doAction:foo: -(IBAction)doAction:(I1 *)sender foo:(I1 *)bar {} @end @@ -132,9 +162,10 @@ // CHECK-NEXT: RelChild | I3 | c:objc(cs)I3 // CHECK-NEXT: RelAcc | prop | c:objc(cs)I3(py)prop -(id)prop; -// CHECK: [[@LINE+3]]:8 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Decl,Dyn,RelChild,RelAcc | rel: 2 +// CHECK: [[@LINE+4]]:8 | instance-method/acc-set/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 +// LOCAL-NOT: [[@LINE+1]]:20 | variable/param(local)/C | p | c:{{.*}} | _p | Def,RelCont | rel: 1 -(void)setProp:(id)p; @end Index: test/Index/Core/index-subkinds.m =================================================================== --- test/Index/Core/index-subkinds.m +++ test/Index/Core/index-subkinds.m @@ -1,4 +1,4 @@ -// RUN: c-index-test core -print-source-symbols -- %s -target x86_64-apple-macosx10.7 | FileCheck %s +// RUN: c-index-test core -print-source-symbols -include-locals -- %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 @@ -13,7 +13,8 @@ -(void)testMe {} // CHECK: [[@LINE+1]]:6 | instance-method/ObjC | testResult | c:objc(cs)MyTestCase(im)testResult | -[MyTestCase testResult] | Def,Dyn,RelChild | rel: 1 -(id)testResult { return 0; } -// CHECK: [[@LINE+1]]:8 | instance-method/ObjC | testWithInt: | c:objc(cs)MyTestCase(im)testWithInt: | -[MyTestCase testWithInt:] | Def,Dyn,RelChild | rel: 1 +// CHECK: [[@LINE+2]]:8 | instance-method/ObjC | testWithInt: | c:objc(cs)MyTestCase(im)testWithInt: | -[MyTestCase testWithInt:] | Def,Dyn,RelChild | rel: 1 +// CHECK: [[@LINE+1]]:25 | variable/param(local)/C | i | c:{{.*}} | _i | Def,RelCont | rel: 1 -(void)testWithInt:(int)i {} @end Index: tools/c-index-test/core_main.cpp =================================================================== --- tools/c-index-test/core_main.cpp +++ tools/c-index-test/core_main.cpp @@ -55,6 +55,9 @@ DumpModuleImports("dump-imported-module-files", cl::desc("Print symbols and input files from imported modules")); +static cl::opt +IncludeLocals("include-locals", cl::desc("Print local symbols")); + static cl::opt ModuleFilePath("module-file", cl::desc("Path to module file to print symbols from")); @@ -159,7 +162,8 @@ } static bool printSourceSymbols(ArrayRef Args, - bool dumpModuleImports) { + bool dumpModuleImports, + bool indexLocals) { SmallVector ArgsWithProgName; ArgsWithProgName.push_back("clang"); ArgsWithProgName.append(Args.begin(), Args.end()); @@ -172,6 +176,7 @@ raw_ostream &OS = outs(); auto DataConsumer = std::make_shared(OS); IndexingOptions IndexOpts; + IndexOpts.IndexFunctionLocals = indexLocals; std::unique_ptr IndexAction; IndexAction = createIndexingAction(DataConsumer, IndexOpts, /*WrappedAction=*/nullptr); @@ -297,7 +302,7 @@ errs() << "error: missing compiler args; pass '-- '\n"; return 1; } - return printSourceSymbols(CompArgs, options::DumpModuleImports); + return printSourceSymbols(CompArgs, options::DumpModuleImports, options::IncludeLocals); } return 0;