@@ -19,6 +19,10 @@ import SourceKitLSP
19
19
import SwiftExtensions
20
20
import XCTest
21
21
22
+ private extension Language {
23
+ static let swiftinterface = Language ( rawValue: " swiftinterface " )
24
+ }
25
+
22
26
final class SwiftInterfaceTests : XCTestCase {
23
27
func testSystemModuleInterface( ) async throws {
24
28
let testClient = try await TestSourceKitLSPClient ( )
@@ -62,7 +66,7 @@ final class SwiftInterfaceTests: XCTestCase {
62
66
let referenceDocument = try await testClient. send ( GetReferenceDocumentRequest ( uri: location. uri) )
63
67
XCTAssert (
64
68
referenceDocument. content. hasPrefix ( " import " ) ,
65
- " Expected that the foundation swift interface starts with 'import ' but got ' \( referenceDocument. content. prefix ( 100 ) ) ' "
69
+ " Expected foundation swift interface to start with 'import ' but got ' \( referenceDocument. content. prefix ( 100 ) ) ' "
66
70
)
67
71
}
68
72
@@ -149,7 +153,7 @@ final class SwiftInterfaceTests: XCTestCase {
149
153
public init() {}
150
154
}
151
155
""" ,
152
- " Exec/main.swift " : " import 1️⃣MyLibrary " ,
156
+ " Exec/main.swift " : " import 1️⃣MyLibrary "
153
157
] ,
154
158
manifest: """
155
159
let package = Package(
@@ -192,21 +196,13 @@ final class SwiftInterfaceTests: XCTestCase {
192
196
func testSemanticFunctionalityInGeneratedInterface( ) async throws {
193
197
let project = try await SwiftPMTestProject (
194
198
files: [
195
- " MyLibrary/MyLibrary.swift " : """
196
- public struct Lib {
197
- public func foo() -> String {}
198
- public init() {}
199
- }
200
- """ ,
201
- " Exec/main.swift " : " import 1️⃣MyLibrary " ,
199
+ " MyLibrary/MyLibrary.swift " : " public struct Lib { public func foo() -> String {} } " ,
200
+ " Exec/main.swift " : " import 1️⃣MyLibrary "
202
201
] ,
203
202
manifest: """
204
203
let package = Package(
205
204
name: " MyLibrary " ,
206
- targets: [
207
- .target(name: " MyLibrary " ),
208
- .executableTarget(name: " Exec " , dependencies: [ " MyLibrary " ])
209
- ]
205
+ targets: [.target(name: " MyLibrary " ), .executableTarget(name: " Exec " , dependencies: [ " MyLibrary " ])]
210
206
)
211
207
""" ,
212
208
capabilities: ClientCapabilities ( experimental: [
@@ -216,36 +212,26 @@ final class SwiftInterfaceTests: XCTestCase {
216
212
)
217
213
218
214
let ( mainUri, mainPositions) = try project. openDocument ( " main.swift " )
219
- let response =
220
- try await project. testClient. send (
221
- DefinitionRequest (
222
- textDocument: TextDocumentIdentifier ( mainUri) ,
223
- position: mainPositions [ " 1️⃣ " ]
224
- )
225
- )
215
+ let response = try await project. testClient. send (
216
+ DefinitionRequest ( textDocument: TextDocumentIdentifier ( mainUri) , position: mainPositions [ " 1️⃣ " ] )
217
+ )
226
218
let referenceDocumentUri = try XCTUnwrap ( response? . locations? . only) . uri
227
219
let referenceDocument = try await project. testClient. send ( GetReferenceDocumentRequest ( uri: referenceDocumentUri) )
228
- let stringIndex = try XCTUnwrap ( referenceDocument. content. firstRange ( of: " -> String " ) )
229
- let ( stringLine, stringColumn) = LineTable ( referenceDocument. content)
230
- . lineAndUTF16ColumnOf ( referenceDocument. content. index ( stringIndex. lowerBound, offsetBy: 3 ) )
231
-
232
- project. testClient. send (
233
- DidOpenTextDocumentNotification (
234
- textDocument: TextDocumentItem (
235
- uri: referenceDocumentUri,
236
- language: . swift,
237
- version: 0 ,
238
- text: referenceDocument. content
220
+
221
+ // Test hover functionality in the interface
222
+ if let stringIndex = referenceDocument. content. firstRange ( of: " -> String " ) {
223
+ let ( line, column) = LineTable ( referenceDocument. content)
224
+ . lineAndUTF16ColumnOf ( referenceDocument. content. index ( stringIndex. lowerBound, offsetBy: 3 ) )
225
+ project. testClient. send (
226
+ DidOpenTextDocumentNotification (
227
+ textDocument: TextDocumentItem ( uri: referenceDocumentUri, language: . swift, version: 0 , text: referenceDocument. content)
239
228
)
240
229
)
241
- )
242
- let hover = try await project. testClient. send (
243
- HoverRequest (
244
- textDocument: TextDocumentIdentifier ( referenceDocumentUri) ,
245
- position: Position ( line: stringLine, utf16index: stringColumn)
230
+ let hover = try await project. testClient. send (
231
+ HoverRequest ( textDocument: TextDocumentIdentifier ( referenceDocumentUri) , position: Position ( line: line, utf16index: column) )
246
232
)
247
- )
248
- XCTAssertNotNil ( hover )
233
+ XCTAssertNotNil ( hover )
234
+ }
249
235
}
250
236
251
237
func testJumpToSynthesizedExtensionMethodInSystemModuleWithoutIndex( ) async throws {
@@ -295,6 +281,7 @@ final class SwiftInterfaceTests: XCTestCase {
295
281
GetReferenceDocumentRequest . method: . dictionary( [ " supported " : . bool( true ) ] )
296
282
] )
297
283
)
284
+
298
285
let uri = DocumentURI ( for: . swift)
299
286
300
287
let positions = testClient. openDocument (
@@ -319,6 +306,137 @@ final class SwiftInterfaceTests: XCTestCase {
319
306
)
320
307
XCTAssertEqual ( diagnostics. fullReport? . items, [ ] )
321
308
}
309
+
310
+ func testInternalNavigationInSwiftInterface( ) async throws {
311
+ let testClient = try await TestSourceKitLSPClient (
312
+ capabilities: ClientCapabilities ( experimental: [
313
+ GetReferenceDocumentRequest . method: . dictionary( [ " supported " : . bool( true ) ] )
314
+ ] )
315
+ )
316
+ let uri = DocumentURI ( for: . swiftinterface)
317
+
318
+ let positions = testClient. openDocument (
319
+ """
320
+ func test(x: 1️⃣String) {
321
+ let a: 2️⃣Int = 5
322
+ }
323
+ """ ,
324
+ uri: uri
325
+ )
326
+
327
+ // First, get definition for String to open the Swift interface
328
+ let stringDefinition = try await testClient. send (
329
+ DefinitionRequest ( textDocument: TextDocumentIdentifier ( uri) , position: positions [ " 1️⃣ " ] )
330
+ )
331
+ let interfaceUri = try XCTUnwrap ( stringDefinition? . locations? . only? . uri)
332
+ let interfaceContents = try await testClient. send ( GetReferenceDocumentRequest ( uri: interfaceUri) )
333
+ // Open the interface document
334
+ testClient. send (
335
+ DidOpenTextDocumentNotification (
336
+ textDocument: TextDocumentItem (
337
+ uri: interfaceUri,
338
+ language: . swift,
339
+ version: 0 ,
340
+ text: interfaceContents. content
341
+ )
342
+ )
343
+ )
344
+
345
+ // Find a symbol within the interface (e.g., "init" method in String)
346
+ guard let initRange = interfaceContents. content. range ( of: " public init() " ) else {
347
+ XCTFail ( " Could not find 'public init()' in String interface " )
348
+ return
349
+ }
350
+ let lineTable = LineTable ( interfaceContents. content)
351
+ let ( line, column) = lineTable. lineAndUTF16ColumnOf ( initRange. lowerBound)
352
+ let initPosition = Position ( line: line, utf16index: column + 7 ) // Position on "init"
353
+
354
+ // Test definition request within the interface
355
+ let internalDefinition = try await testClient. send (
356
+ DefinitionRequest (
357
+ textDocument: TextDocumentIdentifier ( interfaceUri) ,
358
+ position: initPosition
359
+ )
360
+ )
361
+
362
+ // The definition should either:
363
+ // 1. Return a position within the same interface (internal navigation)
364
+ // 2. Return the same position if it's already at the definition
365
+ // 3. Return nil if no definition is available
366
+ if let location = internalDefinition? . locations? . first {
367
+ // If we get a location, it should be in the same interface or a related one
368
+ XCTAssertTrue (
369
+ location. uri. pseudoPath. hasSuffix ( " .swiftinterface " ) ||
370
+ location. uri == interfaceUri,
371
+ " Internal navigation should stay within interface files, got: \( location. uri. pseudoPath) "
372
+ )
373
+ }
374
+ }
375
+
376
+ func testFoundationImportNavigation( ) async throws {
377
+ let testClient = try await TestSourceKitLSPClient (
378
+ capabilities: ClientCapabilities ( experimental: [
379
+ GetReferenceDocumentRequest . method: . dictionary( [ " supported " : . bool( true ) ] )
380
+ ] )
381
+ )
382
+ let uri = DocumentURI ( for: . swiftinterface)
383
+
384
+ let positions = testClient. openDocument (
385
+ """
386
+ import 1️⃣Foundation
387
+ """ ,
388
+ uri: uri
389
+ )
390
+
391
+ // Test navigation to Foundation module
392
+ let foundationDefinition = try await testClient. send (
393
+ DefinitionRequest ( textDocument: TextDocumentIdentifier ( uri) , position: positions [ " 1️⃣ " ] )
394
+ )
395
+ let foundationLocation = try XCTUnwrap ( foundationDefinition? . locations? . only)
396
+ // Verify it's a swiftinterface file (can be either file:// or sourcekit-lsp:// scheme)
397
+ XCTAssertTrue (
398
+ foundationLocation. uri. pseudoPath. hasSuffix ( " .swiftinterface " ) ||
399
+ ( foundationLocation. uri. scheme == " sourcekit-lsp " &&
400
+ foundationLocation. uri. pseudoPath. contains ( " Foundation.swiftinterface " ) )
401
+ )
402
+ }
403
+
404
+ func testFoundationSubmoduleNavigation( ) async throws {
405
+ let testClient = try await TestSourceKitLSPClient (
406
+ capabilities: ClientCapabilities ( experimental: [
407
+ GetReferenceDocumentRequest . method: . dictionary( [ " supported " : . bool( true ) ] )
408
+ ] )
409
+ )
410
+ let uri = DocumentURI ( for: . swift)
411
+
412
+ let positions = testClient. openDocument (
413
+ """
414
+ import 1️⃣Foundation.2️⃣NSAffineTransform
415
+ """ ,
416
+ uri: uri
417
+ )
418
+
419
+ let foundationDefinition = try await testClient. send (
420
+ DefinitionRequest ( textDocument: TextDocumentIdentifier ( uri) , position: positions [ " 1️⃣ " ] )
421
+ )
422
+ if let foundationLocation = foundationDefinition? . locations? . only {
423
+ XCTAssertTrue (
424
+ foundationLocation. uri. pseudoPath. contains ( " Foundation.swiftinterface " ) ||
425
+ foundationLocation. uri. scheme == " sourcekit-lsp "
426
+ )
427
+ }
428
+ // Test navigation to NSAffineTransform
429
+ let transformDefinition = try await testClient. send (
430
+ DefinitionRequest ( textDocument: TextDocumentIdentifier ( uri) , position: positions [ " 2️⃣ " ] )
431
+ )
432
+ if let transformLocation = transformDefinition? . locations? . only {
433
+ // Verify we can identify this as a swiftinterface file
434
+ XCTAssertTrue (
435
+ transformLocation. uri. pseudoPath. contains ( " Foundation.NSAffineTransform.swiftinterface " ) ||
436
+ transformLocation. uri. scheme == " sourcekit-lsp "
437
+ )
438
+ }
439
+ }
322
440
}
323
441
324
442
private func assertSystemSwiftInterface(
0 commit comments