Skip to content

Commit 61a2134

Browse files
committed
Index clang files
Fixes #1253 rdar://127474135
1 parent 4bff560 commit 61a2134

File tree

2 files changed

+150
-11
lines changed

2 files changed

+150
-11
lines changed

Sources/SemanticIndex/UpdateIndexStoreTaskDescription.swift

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,12 @@ public struct UpdateIndexStoreTaskDescription: TaskDescriptionProtocol {
163163
BuildSettingsLogger.log(settings: buildSettings, for: uri)
164164
}
165165
case .c, .cpp, .objective_c, .objective_cpp:
166-
// TODO (indexing): Support indexing of clang files, including headers.
167-
// https://github.com/apple/sourcekit-lsp/issues/1253
168-
break
166+
do {
167+
try await updateIndexStore(forClangFile: uri, buildSettings: buildSettings, toolchain: toolchain)
168+
} catch {
169+
logger.error("Updating index store for \(uri) failed: \(error.forLogging)")
170+
BuildSettingsLogger.log(settings: buildSettings, for: uri)
171+
}
169172
default:
170173
logger.error(
171174
"Not updating index store for \(uri) because it is a language that is not supported by background indexing"
@@ -190,10 +193,49 @@ public struct UpdateIndexStoreTaskDescription: TaskDescriptionProtocol {
190193
fileToIndex: uri
191194
)
192195

193-
let process = try Process.launch(
194-
arguments: [swiftc.pathString] + indexingArguments,
196+
try await runIndexingProcess(
197+
indexFile: uri,
198+
buildSettings: buildSettings,
199+
processArguments: [swiftc.pathString] + indexingArguments,
195200
workingDirectory: buildSettings.workingDirectory.map(AbsolutePath.init(validating:))
196201
)
202+
}
203+
204+
private func updateIndexStore(
205+
forClangFile uri: DocumentURI,
206+
buildSettings: FileBuildSettings,
207+
toolchain: Toolchain
208+
) async throws {
209+
guard let clang = toolchain.clang else {
210+
logger.error(
211+
"Not updating index store for \(uri.forLogging) because toolchain \(toolchain.identifier) does not contain clang"
212+
)
213+
return
214+
}
215+
216+
let indexingArguments = adjustClangCompilerArgumentsForIndexStoreUpdate(
217+
buildSettings.compilerArguments,
218+
fileToIndex: uri
219+
)
220+
221+
try await runIndexingProcess(
222+
indexFile: uri,
223+
buildSettings: buildSettings,
224+
processArguments: [clang.pathString] + indexingArguments,
225+
workingDirectory: buildSettings.workingDirectory.map(AbsolutePath.init(validating:))
226+
)
227+
}
228+
229+
private func runIndexingProcess(
230+
indexFile: DocumentURI,
231+
buildSettings: FileBuildSettings,
232+
processArguments: [String],
233+
workingDirectory: AbsolutePath?
234+
) async throws {
235+
let process = try Process.launch(
236+
arguments: processArguments,
237+
workingDirectory: workingDirectory
238+
)
197239
let result = try await process.waitUntilExitSendingSigIntOnTaskCancellation()
198240
switch result.exitStatus.exhaustivelySwitchable {
199241
case .terminated(code: 0):
@@ -205,26 +247,26 @@ public struct UpdateIndexStoreTaskDescription: TaskDescriptionProtocol {
205247
// Indexing will frequently fail if the source code is in an invalid state. Thus, log the failure at a low level.
206248
logger.debug(
207249
"""
208-
Updating index store for Swift file \(uri.forLogging) terminated with non-zero exit code \(code)
250+
Updating index store for \(indexFile.forLogging) terminated with non-zero exit code \(code)
209251
Stderr:
210252
\(stderr)
211253
Stdout:
212254
\(stdout)
213255
"""
214256
)
215-
BuildSettingsLogger.log(level: .debug, settings: buildSettings, for: uri)
257+
BuildSettingsLogger.log(level: .debug, settings: buildSettings, for: indexFile)
216258
case .signalled(signal: let signal):
217259
if !Task.isCancelled {
218260
// The indexing job finished with a signal. Could be because the compiler crashed.
219261
// Ignore signal exit codes if this task has been cancelled because the compiler exits with SIGINT if it gets
220262
// interrupted.
221-
logger.error("Updating index store for Swift file \(uri.forLogging) signaled \(signal)")
222-
BuildSettingsLogger.log(level: .error, settings: buildSettings, for: uri)
263+
logger.error("Updating index store for \(indexFile.forLogging) signaled \(signal)")
264+
BuildSettingsLogger.log(level: .error, settings: buildSettings, for: indexFile)
223265
}
224266
case .abnormal(exception: let exception):
225267
if !Task.isCancelled {
226-
logger.error("Updating index store for Swift file \(uri.forLogging) exited abnormally \(exception)")
227-
BuildSettingsLogger.log(level: .error, settings: buildSettings, for: uri)
268+
logger.error("Updating index store for \(indexFile.forLogging) exited abnormally \(exception)")
269+
BuildSettingsLogger.log(level: .error, settings: buildSettings, for: indexFile)
228270
}
229271
}
230272
}
@@ -304,3 +346,56 @@ private func adjustSwiftCompilerArgumentsForIndexStoreUpdate(
304346
]
305347
return result
306348
}
349+
350+
/// Adjust compiler arguments that were created for building to compiler arguments that should be used for indexing.
351+
///
352+
/// This removes compiler arguments that produce output files and adds arguments to index the file.
353+
private func adjustClangCompilerArgumentsForIndexStoreUpdate(
354+
_ compilerArguments: [String],
355+
fileToIndex: DocumentURI
356+
) -> [String] {
357+
let removeFlags: Set<String> = [
358+
// Disable writing of a depfile
359+
"-M",
360+
"-MD",
361+
"-MMD",
362+
"-MG",
363+
"-MM",
364+
"-MV",
365+
// Don't create phony targets
366+
"-MP",
367+
// Don't writ out compilation databases
368+
"-MJ",
369+
// Continue in the presence of errors during indexing
370+
"-fmodules-validate-once-per-build-session",
371+
// Don't compile
372+
"-c",
373+
]
374+
375+
let removeArguments: Set<String> = [
376+
// Disable writing of a depfile
377+
"-MT",
378+
"-MF",
379+
"-MQ",
380+
// Don't write serialized diagnostic files
381+
"--serialize-diagnostics",
382+
]
383+
384+
var result: [String] = []
385+
result.reserveCapacity(compilerArguments.count)
386+
var iterator = compilerArguments.makeIterator()
387+
while let argument = iterator.next() {
388+
if removeFlags.contains(argument) || argument.starts(with: "-fbuild-session-file=") {
389+
continue
390+
}
391+
if removeArguments.contains(argument) {
392+
_ = iterator.next()
393+
continue
394+
}
395+
result.append(argument)
396+
}
397+
result.append(
398+
"-fsyntax-only"
399+
)
400+
return result
401+
}

Tests/SourceKitLSPTests/BackgroundIndexingTests.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,48 @@ final class BackgroundIndexingTests: XCTestCase {
284284
]
285285
)
286286
}
287+
288+
func testIndexCFile() async throws {
289+
let project = try await SwiftPMTestProject(
290+
files: [
291+
"MyLibrary/include/dummy.h": "",
292+
"MyFile.c": """
293+
void 1️⃣someFunc() {}
294+
295+
void 2️⃣test() {
296+
3️⃣someFunc();
297+
}
298+
""",
299+
],
300+
serverOptions: backgroundIndexingOptions
301+
)
302+
303+
let (uri, positions) = try project.openDocument("MyFile.c")
304+
let prepare = try await project.testClient.send(
305+
CallHierarchyPrepareRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"])
306+
)
307+
let calls = try await project.testClient.send(
308+
CallHierarchyIncomingCallsRequest(item: try XCTUnwrap(prepare?.only))
309+
)
310+
XCTAssertEqual(
311+
calls,
312+
[
313+
CallHierarchyIncomingCall(
314+
from: CallHierarchyItem(
315+
name: "test",
316+
kind: .function,
317+
tags: nil,
318+
uri: uri,
319+
range: Range(positions["2️⃣"]),
320+
selectionRange: Range(positions["2️⃣"]),
321+
data: .dictionary([
322+
"usr": .string("c:@F@test"),
323+
"uri": .string(uri.stringValue),
324+
])
325+
),
326+
fromRanges: [Range(positions["3️⃣"])]
327+
)
328+
]
329+
)
330+
}
287331
}

0 commit comments

Comments
 (0)