diff --git a/Sources/IndexStoreDB/IndexStoreDB.swift b/Sources/IndexStoreDB/IndexStoreDB.swift index 19dbdca7..9ef46ce3 100644 --- a/Sources/IndexStoreDB/IndexStoreDB.swift +++ b/Sources/IndexStoreDB/IndexStoreDB.swift @@ -35,6 +35,11 @@ public struct PathMapping { } } +public enum SymbolProviderKind { + case clang + case swift +} + /// IndexStoreDB index. public final class IndexStoreDB { @@ -148,6 +153,10 @@ public final class IndexStoreDB { return indexstoredb_index_remove_unit_out_file_paths(impl, cPaths, cPaths.count, waitForProcessing) } + /// Invoke `body` with every occurrance of `usr` in one of the specified roles. + /// + /// Stop iteration if `body` returns `false`. + /// - Returns: `false` if iteration was terminated by `body` returning `true` or `true` if iteration finished. @discardableResult public func forEachSymbolOccurrence(byUSR usr: String, roles: SymbolRole, _ body: @escaping (SymbolOccurrence) -> Bool) -> Bool { return indexstoredb_index_symbol_occurrences_by_usr(impl, usr, roles.rawValue) { occur in @@ -155,6 +164,7 @@ public final class IndexStoreDB { } } + /// Returns all occurrences of `usr` in one of the specified roles. public func occurrences(ofUSR usr: String, roles: SymbolRole) -> [SymbolOccurrence] { var result: [SymbolOccurrence] = [] forEachSymbolOccurrence(byUSR: usr, roles: roles) { occur in @@ -275,6 +285,41 @@ public final class IndexStoreDB { return result } + public func symbolProvider(for sourceFilePath: String) -> SymbolProviderKind? { + var result: SymbolProviderKind? = nil + indexstoredb_index_units_containing_file(impl, sourceFilePath) { unit in + let providerKind: SymbolProviderKind? = switch indexstoredb_unit_info_symbol_provider_kind(unit) { + case INDEXSTOREDB_SYMBOL_PROVIDER_KIND_SWIFT: + .swift + case INDEXSTOREDB_SYMBOL_PROVIDER_KIND_CLANG: + .clang + case INDEXSTOREDB_SYMBOL_PROVIDER_KIND_UNKNOWN: + nil + default: + preconditionFailure("Unknown enum case in indexstoredb_symbol_provider_kind_t") + } + + let mainFilePath = String(cString: indexstoredb_unit_info_main_file_path(unit)) + if providerKind == .swift && mainFilePath != sourceFilePath { + // We have a unit that is "included" from Swift. This happens for header + // files that Swift files depend on. But Swift doesn't have includes and + // we shouldn't infer the header file's language to Swift based on this unit. + // Ignore it. + return true + } + + if result == nil { + result = providerKind + } else if result != providerKind { + // Found two conflicting provider kinds. Return nil as we don't know the provider in this case. + result = nil + return false + } + return true + } + return result + } + @discardableResult public func foreachFileIncludedByFile(path: String, body: @escaping (String) -> Bool) -> Bool { return indexstoredb_index_files_included_by_file(impl, path) { targetPath, line in diff --git a/Sources/IndexStoreDB/Symbol.swift b/Sources/IndexStoreDB/Symbol.swift index b23b63b5..662aff8f 100644 --- a/Sources/IndexStoreDB/Symbol.swift +++ b/Sources/IndexStoreDB/Symbol.swift @@ -45,18 +45,33 @@ public enum IndexSymbolKind: Hashable { case commentTag } +public enum Language: Hashable { + case c + case cxx + case objc + case swift +} + public struct Symbol: Equatable { public var usr: String public var name: String public var kind: IndexSymbolKind public var properties: SymbolProperty + public var language: Language - public init(usr: String, name: String, kind: IndexSymbolKind, properties: SymbolProperty = SymbolProperty()) { + public init( + usr: String, + name: String, + kind: IndexSymbolKind, + properties: SymbolProperty = SymbolProperty(), + language: Language + ) { self.usr = usr self.name = name self.kind = kind self.properties = properties + self.language = language } } @@ -69,9 +84,9 @@ extension Symbol: Comparable { extension Symbol: CustomStringConvertible { public var description: String { if properties.isEmpty { - return "\(name) | \(kind) | \(usr)" + return "\(name) | \(kind) | \(usr) | \(language)" } - return "\(name) | \(kind) (\(properties)) | \(usr)" + return "\(name) | \(kind) (\(properties)) | \(usr) | \(language)" } } @@ -82,9 +97,16 @@ extension Symbol { name: String? = nil, usr: String? = nil, kind: IndexSymbolKind? = nil, - properties: SymbolProperty? = nil) -> Symbol - { - return Symbol(usr: usr ?? self.usr, name: name ?? self.name, kind: kind ?? self.kind, properties: properties ?? self.properties) + properties: SymbolProperty? = nil, + language: Language? = nil + ) -> Symbol { + return Symbol( + usr: usr ?? self.usr, + name: name ?? self.name, + kind: kind ?? self.kind, + properties: properties ?? self.properties, + language: language ?? self.language + ) } /// Returns a SymbolOccurrence with the given location and roles. @@ -95,6 +117,23 @@ extension Symbol { // MARK: CIndexStoreDB conversions +fileprivate extension Language { + init(_ value: indexstoredb_language_t) { + switch value { + case INDEXSTOREDB_LANGUAGE_C: + self = .c + case INDEXSTOREDB_LANGUAGE_CXX: + self = .cxx + case INDEXSTOREDB_LANGUAGE_OBJC: + self = .objc + case INDEXSTOREDB_LANGUAGE_SWIFT: + self = .swift + default: + preconditionFailure("Unhandled case from C enum indexstoredb_language_t") + } + } +} + extension Symbol { /// Note: `value` is expected to be passed +1. @@ -103,7 +142,9 @@ extension Symbol { usr: String(cString: indexstoredb_symbol_usr(value)), name: String(cString: indexstoredb_symbol_name(value)), kind: IndexSymbolKind(indexstoredb_symbol_kind(value)), - properties: SymbolProperty(rawValue: indexstoredb_symbol_properties(value))) + properties: SymbolProperty(rawValue: indexstoredb_symbol_properties(value)), + language: Language(indexstoredb_symbol_language(value)) + ) } } diff --git a/Tests/IndexStoreDBTests/IndexTests.swift b/Tests/IndexStoreDBTests/IndexTests.swift index 3a17750d..7b9079d8 100644 --- a/Tests/IndexStoreDBTests/IndexTests.swift +++ b/Tests/IndexStoreDBTests/IndexTests.swift @@ -41,8 +41,8 @@ final class IndexTests: XCTestCase { try ws.buildAndIndex() - let csym = Symbol(usr: usr, name: "c()", kind: .function) - let asym = Symbol(usr: "s:4main1ayyF", name: "a()", kind: .function) + let csym = Symbol(usr: usr, name: "c()", kind: .function, language: .swift) + let asym = Symbol(usr: "s:4main1ayyF", name: "a()", kind: .function, language: .swift) let ccanon = SymbolOccurrence( symbol: csym, @@ -92,7 +92,7 @@ final class IndexTests: XCTestCase { [ ccall, SymbolOccurrence( - symbol: Symbol(usr: "s:4main1byyF", name: "b()", kind: .function), + symbol: Symbol(usr: "s:4main1byyF", name: "b()", kind: .function, language: .swift), location: SymbolLocation(ws.testLoc("b:call")), roles: [.reference, .call, .calledBy, .containedBy], relations: [ @@ -108,26 +108,26 @@ final class IndexTests: XCTestCase { #if os(macOS) - let cdecl = Symbol(usr: "c:objc(cs)C", name: "C", kind: .class) + let cdecl = Symbol(usr: "c:objc(cs)C", name: "C", kind: .class, language: .objc) let cdeclOccs = index.occurrences(ofUSR: cdecl.usr, roles: .all) checkOccurrences(cdeclOccs, expected: [ cdecl.at(ws.testLoc("C:decl"), roles: [.declaration, .canonical]), cdecl.at(ws.testLoc("C:def"), roles: .definition), - cdecl.at(ws.testLoc("C:ref:swift"), roles: .reference), + cdecl.with(language: .swift).at(ws.testLoc("C:ref:swift"), roles: .reference), cdecl.at(ws.testLoc("C:ref:e.mm"), roles: .reference), ]) - let cmethod = Symbol(usr: "c:objc(cs)C(im)method", name: "method", kind: .instanceMethod) + let cmethod = Symbol(usr: "c:objc(cs)C(im)method", name: "method", kind: .instanceMethod, language: .objc) let cmethodOccs = index.occurrences(ofUSR: cmethod.usr, roles: .all) checkOccurrences(cmethodOccs, expected: [ - cmethod.with(name: "method()").at(ws.testLoc("C.method:call:swift"), roles: [.call, .dynamic]), + cmethod.with(name: "method()", language: .swift).at(ws.testLoc("C.method:call:swift"), roles: [.call, .dynamic]), cmethod.at(ws.testLoc("C.method:decl"), roles: .declaration), cmethod.at(ws.testLoc("C.method:def"), roles: .definition), cmethod.at(ws.testLoc("C.method:call:e.mm"), roles: [.call, .dynamic]), ]) #endif - let ddecl = Symbol(usr: "c:@S@D", name: "D", kind: .class) + let ddecl = Symbol(usr: "c:@S@D", name: "D", kind: .class, language: .cxx) let dOccs = index.occurrences(ofUSR: ddecl.usr, roles: .all) checkOccurrences(dOccs, expected: [ ddecl.at(ws.testLoc("D:def"), roles: .definition), @@ -135,11 +135,11 @@ final class IndexTests: XCTestCase { ddecl.at(ws.testLoc("D:ref:e.mm"), roles: .reference), ]) - let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function) + let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function, language: .c) let bridgingHeaderOccs = index.occurrences(ofUSR: bhdecl.usr, roles: .all) checkOccurrences(bridgingHeaderOccs, expected: [ bhdecl.at(ws.testLoc("bridgingHeader:decl"), roles: .declaration), - bhdecl.with(name: "bridgingHeader()").at(ws.testLoc("bridgingHeader:call"), roles: .call), + bhdecl.with(name: "bridgingHeader()", language: .swift).at(ws.testLoc("bridgingHeader:call"), roles: .call), ]) } @@ -154,28 +154,28 @@ final class IndexTests: XCTestCase { let index = ws.index #if os(macOS) - let cdecl = Symbol(usr: "c:objc(cs)C", name: "C", kind: .class) + let cdecl = Symbol(usr: "c:objc(cs)C", name: "C", kind: .class, language: .objc) let cdeclOccs = index.occurrences(ofUSR: cdecl.usr, roles: .all) checkOccurrences(cdeclOccs, expected: [ cdecl.at(ws.testLoc("C:decl"), roles: [.declaration, .canonical]), cdecl.at(ws.testLoc("C:def"), roles: .definition), - cdecl.at(ws.testLoc("C:ref:swift"), roles: .reference), + cdecl.with(language: .swift).at(ws.testLoc("C:ref:swift"), roles: .reference), ]) - let cmethod = Symbol(usr: "c:objc(cs)C(im)method", name: "method", kind: .instanceMethod) + let cmethod = Symbol(usr: "c:objc(cs)C(im)method", name: "method", kind: .instanceMethod, language: .objc) let cmethodOccs = index.occurrences(ofUSR: cmethod.usr, roles: .all) checkOccurrences(cmethodOccs, expected: [ - cmethod.with(name: "method()").at(ws.testLoc("C.method:call:swift"), roles: [.call, .dynamic]), + cmethod.with(name: "method()", language: .swift).at(ws.testLoc("C.method:call:swift"), roles: [.call, .dynamic]), cmethod.at(ws.testLoc("C.method:decl"), roles: .declaration), cmethod.at(ws.testLoc("C.method:def"), roles: .definition), ]) #endif - let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function) + let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function, language: .c) let bridgingHeaderOccs = index.occurrences(ofUSR: bhdecl.usr, roles: .all) checkOccurrences(bridgingHeaderOccs, expected: [ bhdecl.at(ws.testLoc("bridgingHeader:decl"), roles: .declaration), - bhdecl.with(name: "bridgingHeader()").at(ws.testLoc("bridgingHeader:call"), roles: .call), + bhdecl.with(name: "bridgingHeader()", language: .swift).at(ws.testLoc("bridgingHeader:call"), roles: .call), ]) } @@ -191,7 +191,7 @@ final class IndexTests: XCTestCase { let index = ws.index #if os(macOS) - let cdecl = Symbol(usr: "c:objc(cs)C", name: "C", kind: .class) + let cdecl = Symbol(usr: "c:objc(cs)C", name: "C", kind: .class, language: .objc) let getOccs = { index.occurrences(ofUSR: cdecl.usr, roles: .all) } // Output units are not set yet. @@ -205,17 +205,17 @@ final class IndexTests: XCTestCase { index.addUnitOutFilePaths(indexOutputPaths, waitForProcessing: true) // The bridging header is referenced as a PCH unit dependency, make sure we can see the data. - let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function) + let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function, language: .c) let bridgingHeaderOccs = index.occurrences(ofUSR: bhdecl.usr, roles: .all) checkOccurrences(bridgingHeaderOccs, expected: [ bhdecl.at(ws.testLoc("bridgingHeader:decl"), roles: .declaration), - bhdecl.with(name: "bridgingHeader()").at(ws.testLoc("bridgingHeader:call"), roles: .call), + bhdecl.with(name: "bridgingHeader()", language: .swift).at(ws.testLoc("bridgingHeader:call"), roles: .call), ]) #if os(macOS) checkOccurrences(getOccs(), expected: [ cdecl.at(ws.testLoc("C:decl"), roles: [.declaration, .canonical]), cdecl.at(ws.testLoc("C:def"), roles: .definition), - cdecl.at(ws.testLoc("C:ref:swift"), roles: .reference), + cdecl.with(language: .swift).at(ws.testLoc("C:ref:swift"), roles: .reference), ]) let outUnitASwift = try XCTUnwrap(indexOutputPaths.first{ $0.hasSuffix("-a.swift.o") }) @@ -239,7 +239,7 @@ final class IndexTests: XCTestCase { let index = ws.index #if os(macOS) - let cdecl = Symbol(usr: "c:objc(cs)C", name: "C", kind: .class) + let cdecl = Symbol(usr: "c:objc(cs)C", name: "C", kind: .class, language: .objc) let getOccs = { index.occurrences(ofUSR: cdecl.usr, roles: .all) } // Output units are not set yet. @@ -253,17 +253,17 @@ final class IndexTests: XCTestCase { index.addUnitOutFilePaths(indexOutputPaths, waitForProcessing: true) // The bridging header is referenced as a PCH unit dependency, make sure we can see the data. - let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function) + let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function, language: .c) let bridgingHeaderOccs = index.occurrences(ofUSR: bhdecl.usr, roles: .all) checkOccurrences(bridgingHeaderOccs, expected: [ bhdecl.at(ws.testLoc("bridgingHeader:decl"), roles: .declaration), - bhdecl.with(name: "bridgingHeader()").at(ws.testLoc("bridgingHeader:call"), roles: .call), + bhdecl.with(name: "bridgingHeader()", language: .swift).at(ws.testLoc("bridgingHeader:call"), roles: .call), ]) #if os(macOS) checkOccurrences(getOccs(), expected: [ cdecl.at(ws.testLoc("C:decl"), roles: [.declaration, .canonical]), cdecl.at(ws.testLoc("C:def"), roles: .definition), - cdecl.at(ws.testLoc("C:ref:swift"), roles: .reference), + cdecl.with(language: .swift).at(ws.testLoc("C:ref:swift"), roles: .reference), ]) let outUnitASwift = try XCTUnwrap(indexOutputPaths.first{ $0.hasSuffix("-a.swift.o") }) @@ -279,7 +279,7 @@ final class IndexTests: XCTestCase { guard let ws = try staticTibsTestWorkspace(name: "SwiftModules") else { return } try ws.buildAndIndex() - let aaa = Symbol(usr: "s:1A3aaayyF", name: "aaa()", kind: .function) + let aaa = Symbol(usr: "s:1A3aaayyF", name: "aaa()", kind: .function, language: .swift) checkOccurrences(ws.index.occurrences(ofUSR: aaa.usr, roles: .all), expected: [ aaa.at(ws.testLoc("aaa:def"), moduleName: "A", roles: .definition), aaa.at(ws.testLoc("aaa:call"), moduleName: "B", roles: .call), @@ -291,7 +291,7 @@ final class IndexTests: XCTestCase { guard let ws = try mutableTibsTestWorkspace(name: "proj1") else { return } try ws.buildAndIndex() - let cdecl = Symbol(usr: "s:4main1cyyF", name: "c()", kind: .function) + let cdecl = Symbol(usr: "s:4main1cyyF", name: "c()", kind: .function, language: .swift) let roles: SymbolRole = [.reference, .definition, .declaration] checkOccurrences(ws.index.occurrences(ofUSR: cdecl.usr, roles: .all), expected: [ @@ -348,7 +348,7 @@ final class IndexTests: XCTestCase { waitUntilDoneInitializing: true, listenToUnitEvents: true) - let csym = Symbol(usr: "s:4main1cyyF", name: "c()", kind: .function) + let csym = Symbol(usr: "s:4main1cyyF", name: "c()", kind: .function, language: .swift) let waitOccs = indexWait.occurrences(ofUSR: csym.usr, roles: [.reference, .definition]) checkOccurrences(waitOccs, expected: [ @@ -547,7 +547,7 @@ final class IndexTests: XCTestCase { try ws.buildAndIndex() let index = ws.index - let ddecl = Symbol(usr: "c:@S@D", name: "D", kind: .class) + let ddecl = Symbol(usr: "c:@S@D", name: "D", kind: .class, language: .cxx) let getOccs = { index.occurrences(ofUSR: ddecl.usr, roles: .all) } // Output units are not set yet. @@ -569,11 +569,11 @@ final class IndexTests: XCTestCase { ]) // The bridging header is referenced as a PCH unit dependency, make sure we can see the data. - let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function) + let bhdecl = Symbol(usr: "c:@F@bridgingHeader", name: "bridgingHeader", kind: .function, language: .c) let bridgingHeaderOccs = index.occurrences(ofUSR: bhdecl.usr, roles: .all) checkOccurrences(bridgingHeaderOccs, expected: [ bhdecl.at(ws.testLoc("bridgingHeader:decl"), roles: .declaration), - bhdecl.with(name: "bridgingHeader()").at(ws.testLoc("bridgingHeader:call"), roles: .call), + bhdecl.with(name: "bridgingHeader()", language: .swift).at(ws.testLoc("bridgingHeader:call"), roles: .call), ]) } @@ -634,25 +634,25 @@ final class IndexTests: XCTestCase { try ws.buildAndIndex() - let asyncFuncSym = Symbol(usr: "s:4main9asyncFuncyyYaF", name: "asyncFunc()", kind: .function, properties: .swiftAsync) + let asyncFuncSym = Symbol(usr: "s:4main9asyncFuncyyYaF", name: "asyncFunc()", kind: .function, properties: .swiftAsync, language: .swift) let asyncFuncOccs = index.occurrences(ofUSR: asyncFuncSym.usr, roles: .definition) checkOccurrences(asyncFuncOccs, expected: [ asyncFuncSym.at(ws.testLoc("asyncFunc:def"), roles: .definition) ]) - let asyncMethSym = Symbol(usr: "s:4main8MyStructV11asyncMethodyyYaF", name: "asyncMethod()", kind: .instanceMethod, properties: .swiftAsync) + let asyncMethSym = Symbol(usr: "s:4main8MyStructV11asyncMethodyyYaF", name: "asyncMethod()", kind: .instanceMethod, properties: .swiftAsync, language: .swift) let asyncMethOccs = index.occurrences(ofUSR: asyncMethSym.usr, roles: .definition) checkOccurrences(asyncMethOccs, expected: [ asyncMethSym.at(ws.testLoc("asyncMethod:def"), roles: .definition) ]) - let testMeSym = Symbol(usr: "s:4main10MyTestCaseC6testMeyyF", name: "testMe()", kind: .instanceMethod, properties: .unitTest) + let testMeSym = Symbol(usr: "s:4main10MyTestCaseC6testMeyyF", name: "testMe()", kind: .instanceMethod, properties: .unitTest, language: .swift) let testMeOccs = index.occurrences(ofUSR: testMeSym.usr, roles: .definition) checkOccurrences(testMeOccs, expected: [ testMeSym.at(ws.testLoc("testMe:def"), roles: .definition) ]) - let testMeAsyncSym = Symbol(usr: "s:4main10MyTestCaseC11testMeAsyncyyYaF", name: "testMeAsync()", kind: .instanceMethod, properties: [.unitTest, .swiftAsync]) + let testMeAsyncSym = Symbol(usr: "s:4main10MyTestCaseC11testMeAsyncyyYaF", name: "testMeAsync()", kind: .instanceMethod, properties: [.unitTest, .swiftAsync], language: .swift) let testMeAsyncOccs = index.occurrences(ofUSR: testMeAsyncSym.usr, roles: .definition) checkOccurrences(testMeAsyncOccs, expected: [ testMeAsyncSym.at(ws.testLoc("testMeAsync:def"), roles: .definition) @@ -665,7 +665,7 @@ final class IndexTests: XCTestCase { try ws.buildAndIndex() - let largeType = Symbol(usr: "c:@CT@LargeType", name: "LargeType", kind: .concept) + let largeType = Symbol(usr: "c:@CT@LargeType", name: "LargeType", kind: .concept, language: .c) let largeTypeOccs = ws.index.occurrences(ofUSR: largeType.usr, roles: .all) checkOccurrences(largeTypeOccs, expected: [ largeType.at(ws.testLoc("LargeType:def"), roles: .definition), diff --git a/include/CIndexStoreDB/CIndexStoreDB.h b/include/CIndexStoreDB/CIndexStoreDB.h index 655163a5..02dd375d 100644 --- a/include/CIndexStoreDB/CIndexStoreDB.h +++ b/include/CIndexStoreDB/CIndexStoreDB.h @@ -137,6 +137,19 @@ typedef enum { INDEXSTOREDB_EVENT_UNIT_OUT_OF_DATE = 2, } indexstoredb_delegate_event_kind_t; +typedef enum { + INDEXSTOREDB_LANGUAGE_C, + INDEXSTOREDB_LANGUAGE_OBJC, + INDEXSTOREDB_LANGUAGE_CXX, + INDEXSTOREDB_LANGUAGE_SWIFT +} indexstoredb_language_t; + +typedef enum { + INDEXSTOREDB_SYMBOL_PROVIDER_KIND_CLANG, + INDEXSTOREDB_SYMBOL_PROVIDER_KIND_SWIFT, + INDEXSTOREDB_SYMBOL_PROVIDER_KIND_UNKNOWN, +} indexstoredb_symbol_provider_kind_t; + typedef void *indexstoredb_delegate_event_t; /// Returns true on success. @@ -333,6 +346,10 @@ indexstoredb_symbol_name(_Nonnull indexstoredb_symbol_t); INDEXSTOREDB_PUBLIC uint64_t indexstoredb_symbol_properties(_Nonnull indexstoredb_symbol_t); +/// Return the language in which the given symbol is defined. +indexstoredb_language_t +indexstoredb_symbol_language(_Nonnull indexstoredb_symbol_t symbol); + /// Returns the symbol of the given symbol occurrence. /// /// The symbol has the same lifetime as the \c indexstoredb_symbol_occurrence_t. @@ -472,6 +489,9 @@ indexstoredb_unit_info_main_file_path(_Nonnull indexstoredb_unit_info_t); INDEXSTOREDB_PUBLIC const char *_Nonnull indexstoredb_unit_info_unit_name(_Nonnull indexstoredb_unit_info_t); +INDEXSTOREDB_PUBLIC indexstoredb_symbol_provider_kind_t +indexstoredb_unit_info_symbol_provider_kind(_Nonnull indexstoredb_unit_info_t info); + /// Iterates over the compilation units that contain \p path and return their units. /// /// This can be used to find information for units that include a given header. diff --git a/include/IndexStoreDB/Index/StoreUnitInfo.h b/include/IndexStoreDB/Index/StoreUnitInfo.h index eec3640c..291f0bf9 100644 --- a/include/IndexStoreDB/Index/StoreUnitInfo.h +++ b/include/IndexStoreDB/Index/StoreUnitInfo.h @@ -13,6 +13,7 @@ #ifndef INDEXSTOREDB_INDEX_STOREUNITINFO_H #define INDEXSTOREDB_INDEX_STOREUNITINFO_H +#include "IndexStoreDB/Core/Symbol.h" #include "IndexStoreDB/Support/Path.h" #include "llvm/Support/Chrono.h" #include @@ -26,16 +27,18 @@ struct StoreUnitInfo { std::string OutFileIdentifier; bool HasTestSymbols = false; llvm::sys::TimePoint<> ModTime; + Optional SymProviderKind; StoreUnitInfo() = default; StoreUnitInfo(std::string unitName, CanonicalFilePath mainFilePath, StringRef outFileIdentifier, bool hasTestSymbols, - llvm::sys::TimePoint<> modTime) + llvm::sys::TimePoint<> modTime, Optional + SymProviderKind) : UnitName(unitName), MainFilePath(mainFilePath), OutFileIdentifier(outFileIdentifier), HasTestSymbols(hasTestSymbols), - ModTime(modTime) {} + ModTime(modTime), SymProviderKind(SymProviderKind) {} }; } // namespace index diff --git a/lib/CIndexStoreDB/CIndexStoreDB.cpp b/lib/CIndexStoreDB/CIndexStoreDB.cpp index 4b14ca53..a1947625 100644 --- a/lib/CIndexStoreDB/CIndexStoreDB.cpp +++ b/lib/CIndexStoreDB/CIndexStoreDB.cpp @@ -319,6 +319,21 @@ indexstoredb_symbol_usr(indexstoredb_symbol_t symbol) { return value->getUSR().c_str(); } +indexstoredb_language_t +indexstoredb_symbol_language(_Nonnull indexstoredb_symbol_t symbol) { + auto value = (Symbol *)symbol; + switch (value->getLanguage()) { + case IndexStoreDB::SymbolLanguage::C: + return INDEXSTOREDB_LANGUAGE_C; + case IndexStoreDB::SymbolLanguage::ObjC: + return INDEXSTOREDB_LANGUAGE_OBJC; + case IndexStoreDB::SymbolLanguage::CXX: + return INDEXSTOREDB_LANGUAGE_CXX; + case IndexStoreDB::SymbolLanguage::Swift: + return INDEXSTOREDB_LANGUAGE_SWIFT; + } +} + const char * indexstoredb_symbol_name(indexstoredb_symbol_t symbol) { auto value = (Symbol *)symbol; @@ -551,6 +566,20 @@ indexstoredb_unit_info_unit_name(indexstoredb_unit_info_t info) { return obj->UnitName.c_str(); } +indexstoredb_symbol_provider_kind_t +indexstoredb_unit_info_symbol_provider_kind(_Nonnull indexstoredb_unit_info_t info) { + auto obj = (const StoreUnitInfo *)info; + if (!obj->SymProviderKind) { + return INDEXSTOREDB_SYMBOL_PROVIDER_KIND_UNKNOWN; + } + switch (*obj->SymProviderKind) { + case IndexStoreDB::SymbolProviderKind::Clang: + return INDEXSTOREDB_SYMBOL_PROVIDER_KIND_CLANG; + case IndexStoreDB::SymbolProviderKind::Swift: + return INDEXSTOREDB_SYMBOL_PROVIDER_KIND_SWIFT; + } +} + bool indexstoredb_index_units_containing_file( indexstoredb_index_t index, diff --git a/lib/Index/FilePathIndex.cpp b/lib/Index/FilePathIndex.cpp index d3dadded..a0074961 100644 --- a/lib/Index/FilePathIndex.cpp +++ b/lib/Index/FilePathIndex.cpp @@ -166,6 +166,7 @@ bool FileIndexImpl::foreachMainUnitContainingFile(CanonicalFilePathRef filePath, currUnit.ModTime = unitInfo.ModTime; currUnit.MainFilePath = reader.getFullFilePathFromCode(unitInfo.MainFileCode); currUnit.OutFileIdentifier = reader.getUnitFileIdentifierFromCode(unitInfo.OutFileCode); + currUnit.SymProviderKind = unitInfo.SymProviderKind; return true; }); } diff --git a/lib/Index/IndexDatastore.cpp b/lib/Index/IndexDatastore.cpp index 35bbcdcc..a33bcf49 100644 --- a/lib/Index/IndexDatastore.cpp +++ b/lib/Index/IndexDatastore.cpp @@ -479,6 +479,7 @@ void StoreUnitRepo::registerUnit(StringRef unitName, bool isInitialScan, std::sh bool needDatabaseUpdate; Optional optIsSystem; Optional PrevHasTestSymbols; + Optional PrevSymProviderKind; IDCode PrevMainFileCode; IDCode PrevOutFileCode; Optional StoreUnitInfoOpt; @@ -498,6 +499,7 @@ void StoreUnitRepo::registerUnit(StringRef unitName, bool isInitialScan, std::sh PrevMainFileCode = unitImport.getPrevMainFileCode(); PrevOutFileCode = unitImport.getPrevOutFileCode(); PrevHasTestSymbols = unitImport.getHasTestSymbols(); + PrevSymProviderKind = unitImport.getSymbolProviderKind(); return false; } @@ -595,7 +597,14 @@ void StoreUnitRepo::registerUnit(StringRef unitName, bool isInitialScan, std::sh } unitImport.commit(); - StoreUnitInfoOpt = StoreUnitInfo{unitName, CanonMainFile, OutFileIdentifier, unitImport.getHasTestSymbols().getValue(), unitModTime}; + StoreUnitInfoOpt = StoreUnitInfo{ + unitName, + CanonMainFile, + OutFileIdentifier, + unitImport.getHasTestSymbols().getValue(), + unitModTime, + unitImport.getSymbolProviderKind() + }; import.commit(); return false; }; @@ -608,7 +617,14 @@ void StoreUnitRepo::registerUnit(StringRef unitName, bool isInitialScan, std::sh ReadTransaction reader(SymIndex->getDBase()); CanonicalFilePath mainFile = reader.getFullFilePathFromCode(PrevMainFileCode); std::string outFileIdentifier = reader.getUnitFileIdentifierFromCode(PrevOutFileCode); - StoreUnitInfoOpt = StoreUnitInfo{unitName, mainFile, outFileIdentifier, PrevHasTestSymbols.getValue(), unitModTime}; + StoreUnitInfoOpt = StoreUnitInfo{ + unitName, + mainFile, + outFileIdentifier, + PrevHasTestSymbols.getValue(), + unitModTime, + PrevSymProviderKind.getValue() + }; } Delegate->processedStoreUnit(StoreUnitInfoOpt.getValue()); } @@ -816,6 +832,7 @@ void StoreUnitRepo::onUnitOutOfDate(IDCode unitCode, StringRef unitName, CanonicalFilePath MainFilePath; std::string OutFileIdentifier; bool hasTestSymbols = false; + Optional SymProviderKind; llvm::sys::TimePoint<> CurrModTime; SmallVector dependentUnits; { @@ -827,13 +844,21 @@ void StoreUnitRepo::onUnitOutOfDate(IDCode unitCode, StringRef unitName, } OutFileIdentifier = reader.getUnitFileIdentifierFromCode(unitInfo.OutFileCode); hasTestSymbols = unitInfo.HasTestSymbols; + SymProviderKind = unitInfo.SymProviderKind; CurrModTime = unitInfo.ModTime; } reader.getDirectDependentUnits(unitCode, dependentUnits); } if (!MainFilePath.empty() && Delegate) { - StoreUnitInfo unitInfo{unitName, MainFilePath, OutFileIdentifier, hasTestSymbols, CurrModTime}; + StoreUnitInfo unitInfo{ + unitName, + MainFilePath, + OutFileIdentifier, + hasTestSymbols, + CurrModTime, + SymProviderKind + }; Delegate->unitIsOutOfDate(unitInfo, outOfDateModTime, hint, synchronous); }