Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 29 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ var useLocalDependencies: Bool { hasEnvironmentVariable("SWIFTCI_USE_LOCAL_DEPS"
var dependencies: [Package.Dependency] {
if useLocalDependencies {
return [
.package(path: "../swift-lmdb")
.package(path: "../swift-lmdb"),
.package(path: "../swift-argument-parser"),
]
} else {
return [
.package(url: "https://github.com/swiftlang/swift-lmdb.git", branch: "main")
.package(url: "https://github.com/swiftlang/swift-lmdb.git", branch: "main"),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.3.0"),
]
}
}
Expand Down Expand Up @@ -47,6 +49,11 @@ let package = Package(
name: "IndexStore",
targets: ["IndexStore"]
),
// --- ADDED: The Executable Product ---
.executable(
name: "index-dump",
targets: ["index-dump"]
),
],
dependencies: dependencies,
targets: [
Expand Down Expand Up @@ -76,7 +83,7 @@ let package = Package(
),

// C API of libIndexStore that can be dlopen'ed from the IndexStore target
.target(name: "IndexStoreCAPI",),
.target(name: "IndexStoreCAPI", ),

// MARK: Swift interface

Expand All @@ -93,7 +100,6 @@ let package = Package(
),

// MARK: Swift Test Infrastructure

// The Test Index Build System (tibs) library.
.target(
name: "ISDBTibs",
Expand Down Expand Up @@ -168,7 +174,7 @@ let package = Package(
exclude: ["CMakeLists.txt"]
),

// Copy of a subset of llvm's ADT and Support libraries.
// Copy of a subset of llvm's ADT and support libraries.
.target(
name: "IndexStoreDB_LLVMSupport",
dependencies: [],
Expand Down Expand Up @@ -199,6 +205,24 @@ let package = Package(
"Windows/Watchdog.inc",
]
),

// MARK: Command Line Tools

.executableTarget(
name: "index-dump",
dependencies: [
"IndexStore",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
],
swiftSettings: [
.enableUpcomingFeature("ExistentialAny"),
.enableUpcomingFeature("InternalImportsByDefault"),
.enableUpcomingFeature("MemberImportVisibility"),
.enableUpcomingFeature("InferIsolatedConformances"),
.enableUpcomingFeature("NonisolatedNonsendingByDefault"),
.swiftLanguageMode(.v6),
]
),
],
swiftLanguageModes: [.v5],
cxxLanguageStandard: .cxx17
Expand Down
74 changes: 74 additions & 0 deletions Sources/IndexStore/IndexStoreDescription.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2026 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import Foundation

extension IndexStoreUnit: CustomStringConvertible {
public var description: String {
var result = """
Module: \(moduleName.string)
Has Main File: \(hasMainFile)
Main File: \(mainFile.string)
Output File: \(outputFile.string)
Target: \(target.string)
Sysroot: \(sysrootPath.string)
Working Directory: \(workingDirectory.string)
Is System: \(isSystemUnit)
Is Module: \(isModuleUnit)
Is Debug: \(isDebugCompilation)
Provider Identifier: \(providerIdentifier.string)
Provider Version: \(providerVersion.string)
Mod Date: \(modificationDate)

DEPENDENCIES START
\(dependencies.map { dep in
"\(String(describing: dep.kind).capitalized) | \(dep.name.string)"
}.joined(separator: "\n"))
DEPENDENCIES END
"""
Comment on lines +17 to +37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var result = """
Module: \(moduleName.string)
Has Main File: \(hasMainFile)
Main File: \(mainFile.string)
Output File: \(outputFile.string)
Target: \(target.string)
Sysroot: \(sysrootPath.string)
Working Directory: \(workingDirectory.string)
Is System: \(isSystemUnit)
Is Module: \(isModuleUnit)
Is Debug: \(isDebugCompilation)
Provider Identifier: \(providerIdentifier.string)
Provider Version: \(providerVersion.string)
Mod Date: \(modificationDate)
DEPENDENCIES START
\(dependencies.map { dep in
"\(String(describing: dep.kind).capitalized) | \(dep.name.string)"
}.joined(separator: "\n"))
DEPENDENCIES END
"""
let dependenciesLines = dependencies.map { dep in
"\(String(describing: dep.kind).capitalized) | \(dep.name.string)"
}.joined(separator: "\n")
return """
Module: \(moduleName.string)
Has Main File: \(hasMainFile)
Main File: \(mainFile.string)
Output File: \(outputFile.string)
Target: \(target.string)
Sysroot: \(sysrootPath.string)
Working Directory: \(workingDirectory.string)
Is System: \(isSystemUnit)
Is Module: \(isModuleUnit)
Is Debug: \(isDebugCompilation)
Provider Identifier: \(providerIdentifier.string)
Provider Version: \(providerVersion.string)
Mod Date: \(modificationDate)
DEPENDENCIES START
\()
DEPENDENCIES END
"""


return result
}
}

extension IndexStoreRecord: CustomStringConvertible {
public var description: String {
let symbolLines = symbols.map { symbol in
"\(symbol.kind) | \(symbol.name.string) | USR: \(symbol.usr.string)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"\(symbol.kind) | \(symbol.name.string) | USR: \(symbol.usr.string)"
"\(symbol.kind) | \(symbol.name.string) | \(symbol.usr.string)"

}

let occurrencesLines = occurrences.map { occurrence in
var result =
[
"""
\(occurrence.position.line):\(occurrence.position.column) \
| \(occurrence.symbol.kind) \
| USR: \(occurrence.symbol.usr.string) \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For anyone working on this, it’ll be obvious that this is a USR (kind of lesson number 1 you need to learn), so I’d omit that.

Suggested change
| USR: \(occurrence.symbol.usr.string) \
| \(occurrence.symbol.usr.string) \

Copy link
Author

@DPrakashhh DPrakashhh Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will always keep this in my mind ! next time onwards - Sorry

| Roles: \(occurrence.roles)
"""
]
+ occurrence.relations.map { relation in
" Relation | \(relation.symbol.usr.string) | Roles: \(relation.roles)"
}
return result
}

return """
SYMBOLS START
\(symbolLines.joined(separator: "\n"))
SYMBOLS END
OCCURRENCES START
\(occurrencesLines.joined(separator: "\n"))
OCCURRENCES END
"""
}
}
76 changes: 76 additions & 0 deletions Sources/index-dump/LibIndexStoreProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2026 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import Foundation

#if os(Windows)
import WinSDK
#endif

/// Provides utilities to discover and locate libIndexStore in the system.
private enum LibIndexStoreProvider {
/// Find a tool using xcrun/which/where (copied logic from TibsToolchain.findTool)
static func findTool(name: String) -> URL? {
#if os(macOS)
let cmd = ["/usr/bin/xcrun", "--find", name]
#elseif os(Windows)
var buf = [WCHAR](repeating: 0, count: Int(MAX_PATH))
GetWindowsDirectoryW(&buf, UINT(MAX_PATH))
var wherePath = String(decodingCString: &buf, as: UTF16.self)
wherePath = (wherePath as NSString).appendingPathComponent("system32")
wherePath = (wherePath as NSString).appendingPathComponent("where.exe")
let cmd = [wherePath, name]
#else
let cmd = ["/usr/bin/which", name]
#endif

let process = Process()
process.executableURL = URL(fileURLWithPath: cmd[0])
process.arguments = Array(cmd.dropFirst())
let pipe = Pipe()
process.standardOutput = pipe

try? process.run()
process.waitUntilExit()
guard process.terminationStatus == 0 else { return nil }

let data = pipe.fileHandleForReading.readDataToEndOfFile()
var path = String(decoding: data, as: UTF8.self)
#if os(Windows)
path = String((path.split { $0.isNewline })[0])
#endif
return URL(fileURLWithPath: path.trimmingCharacters(in: .whitespacesAndNewlines))
}

/// Infer libIndexStore dylib path from the default toolchain
static func inferLibPath() -> URL? {
guard let swiftURL = findTool(name: "swift") else {
return nil
}

let toolchainURL = swiftURL.deletingLastPathComponent().deletingLastPathComponent()

#if os(macOS)
let libName = "libIndexStore.dylib"
#elseif os(Windows)
let libName = "IndexStore.dll"
#else
let libName = "libIndexStore.so"
#endif

let libURL = toolchainURL.appending(components: "lib", libName)
guard FileManager.default.fileExists(atPath: libURL.path) else {
return nil
}
return libURL
}
}
95 changes: 95 additions & 0 deletions Sources/index-dump/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2026 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import ArgumentParser
import Foundation
import IndexStore

#if os(Windows)
import WinSDK
#endif

@main
struct IndexDump: AsyncParsableCommand {
static let configuration = CommandConfiguration(
abstract: "Dumps the content of unit or record files from an IndexStore."
)

@Argument(help: "Name of the unit/record or a direct path to the file")
var nameOrPath: String

@Option(help: "Path to libIndexStore. Inferred if omitted.")
var libIndexStore: String?

@Option(help: "Path to the index store directory. Inferred if omitted.")
var indexStore: String?

@Option(help: "Explicitly set mode (unit/record).")
var mode: Mode?

enum Mode: String, ExpressibleByArgument {
case unit, record
}

func run() async throws {
let libURL = try explicitOrInferredLibPath()
let storeURL = try explicitOrInferredStorePath()

let lib = try await IndexStoreLibrary.at(dylibPath: libURL)
let store = try lib.indexStore(at: storeURL)

let determinedMode = try mode ?? inferMode(from: nameOrPath)
let cleanName = URL(fileURLWithPath: nameOrPath).lastPathComponent

switch determinedMode {
case .unit:
let unit = try store.unit(named: cleanName)
print(unit)
case .record:
let record = try store.record(named: cleanName)
print(record)
}
}

// MARK: - Mode Inference

private func inferMode(from path: String) throws -> Mode {
let components = URL(fileURLWithPath: path).pathComponents
if components.contains("units") { return .unit }
if components.contains("records") { return .record }
throw ValidationError("Could not infer mode from path. Please specify --mode explicitly.")
}

private func explicitOrInferredStorePath() throws -> URL {
if let explicit = indexStore { return URL(fileURLWithPath: explicit) }

var url = URL(fileURLWithPath: nameOrPath)
if url.pathComponents.contains("v5") {
while url.lastPathComponent != "v5" && url.pathComponents.count > 1 {
url = url.deletingLastPathComponent()
}
return url.deletingLastPathComponent()
}
throw ValidationError("Could not infer store path. Please specify --index-store.")
}

private func explicitOrInferredLibPath() throws -> URL {
if let explicit = libIndexStore { return URL(fileURLWithPath: explicit) }

guard let libURL = LibIndexStoreProvider.inferLibPath() else {
throw ValidationError(
"Could not find 'swift' to infer toolchain path. Please specify --lib-index-store explicitly."
)
}
return libURL
}
}
Loading