Skip to content

Commit f1d0316

Browse files
authored
Merge pull request #386 from benlangmuir/lifetimes-again
Fix lifetime issues in tests
2 parents 57aa4dc + 7788bff commit f1d0316

File tree

10 files changed

+61
-65
lines changed

10 files changed

+61
-65
lines changed

Sources/SKCore/BuildSystemManager.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ public final class BuildSystemManager {
109109
let fallbackBuildSystem: FallbackBuildSystem?
110110

111111
/// Provider of file to main file mappings.
112-
weak var mainFilesProvider: MainFilesProvider?
112+
var _mainFilesProvider: MainFilesProvider?
113113

114114
/// Build system delegate that will receive notifications about setting changes, etc.
115-
weak var _delegate: BuildSystemDelegate?
115+
var _delegate: BuildSystemDelegate?
116116

117117
/// Create a BuildSystemManager that wraps the given build system. The new
118118
/// manager will modify the delegate of the underlying build system.
@@ -121,7 +121,7 @@ public final class BuildSystemManager {
121121
precondition(buildSystem?.delegate == nil)
122122
self.buildSystem = buildSystem
123123
self.fallbackBuildSystem = fallbackBuildSystem
124-
self.mainFilesProvider = mainFilesProvider
124+
self._mainFilesProvider = mainFilesProvider
125125
self.fallbackSettingsTimeout = fallbackSettingsTimeout
126126
self.buildSystem?.delegate = self
127127
}
@@ -138,6 +138,11 @@ extension BuildSystemManager: BuildSystem {
138138
set { queue.sync { _delegate = newValue } }
139139
}
140140

141+
public var mainFilesProvider: MainFilesProvider? {
142+
get { queue.sync { _mainFilesProvider} }
143+
set { queue.sync { _mainFilesProvider = newValue } }
144+
}
145+
141146
public func registerForChangeNotifications(for uri: DocumentURI, language: Language) {
142147
return queue.async {
143148
log("registerForChangeNotifications(\(uri.pseudoPath))")
@@ -146,7 +151,7 @@ extension BuildSystemManager: BuildSystem {
146151
if let watchedFile = self.watchedFiles[uri] {
147152
mainFile = watchedFile.mainFile
148153
} else {
149-
let mainFiles = self.mainFilesProvider?.mainFilesContainingFile(uri)
154+
let mainFiles = self._mainFilesProvider?.mainFilesContainingFile(uri)
150155
mainFile = chooseMainFile(for: uri, from: mainFiles ?? [])
151156
self.watchedFiles[uri] = (mainFile, language)
152157
}
@@ -396,7 +401,7 @@ extension BuildSystemManager: MainFilesDelegate {
396401
var buildSettingsChanges = [DocumentURI: FileBuildSettingsChange]()
397402

398403
for (uri, state) in origWatched {
399-
let mainFiles = self.mainFilesProvider?.mainFilesContainingFile(uri) ?? []
404+
let mainFiles = self._mainFilesProvider?.mainFilesContainingFile(uri) ?? []
400405
let newMainFile = chooseMainFile(for: uri, previous: state.mainFile, from: mainFiles)
401406
let language = state.language
402407

Sources/SourceKitLSP/SourceKitServer.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,11 @@ extension SourceKitServer {
561561
// pipe failure.
562562

563563
// Close the index, which will flush to disk.
564+
self.workspace?.buildSystemManager.mainFilesProvider = nil
564565
self.workspace?.index = nil
566+
567+
// Break retain cycle with the BSM.
568+
self.workspace?.buildSystemManager.delegate = nil
565569
}
566570

567571

Tests/LanguageServerProtocolJSONRPCTests/ConnectionTests.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,9 @@ class ConnectionTests: XCTestCase {
271271
#endif
272272
conn.close()
273273

274-
waitForExpectations(timeout: 10)
274+
withExtendedLifetime(conn) {
275+
waitForExpectations(timeout: 10)
276+
}
275277
}
276278
}
277279
}

Tests/SKCoreTests/BuildSystemManagerTests.swift

Lines changed: 10 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ final class BuildSystemManagerTests: XCTestCase {
2626
let d = DocumentURI(string: "bsm:d")
2727

2828
let mainFiles = ManualMainFilesProvider()
29-
defer {
30-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
31-
_fixLifetime(mainFiles)
32-
}
3329
mainFiles.mainFiles = [
3430
a: Set([c]),
3531
b: Set([c, d]),
@@ -41,6 +37,7 @@ final class BuildSystemManagerTests: XCTestCase {
4137
buildSystem: FallbackBuildSystem(),
4238
fallbackBuildSystem: nil,
4339
mainFilesProvider: mainFiles)
40+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
4441

4542
XCTAssertEqual(bsm._cachedMainFile(for: a), nil)
4643
XCTAssertEqual(bsm._cachedMainFile(for: b), nil)
@@ -95,16 +92,13 @@ final class BuildSystemManagerTests: XCTestCase {
9592
func testSettingsMainFile() {
9693
let a = DocumentURI(string: "bsm:a.swift")
9794
let mainFiles = ManualMainFilesProvider()
98-
defer {
99-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
100-
_fixLifetime(mainFiles)
101-
}
10295
mainFiles.mainFiles = [a: Set([a])]
10396
let bs = ManualBuildSystem()
10497
let bsm = BuildSystemManager(
10598
buildSystem: bs,
10699
fallbackBuildSystem: nil,
107100
mainFilesProvider: mainFiles)
101+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
108102
let del = BSMDelegate(bsm)
109103

110104
bs.map[a] = FileBuildSettings(compilerArguments: ["x"])
@@ -123,16 +117,13 @@ final class BuildSystemManagerTests: XCTestCase {
123117
func testSettingsMainFileInitialNil() {
124118
let a = DocumentURI(string: "bsm:a.swift")
125119
let mainFiles = ManualMainFilesProvider()
126-
defer {
127-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
128-
_fixLifetime(mainFiles)
129-
}
130120
mainFiles.mainFiles = [a: Set([a])]
131121
let bs = ManualBuildSystem()
132122
let bsm = BuildSystemManager(
133123
buildSystem: bs,
134124
fallbackBuildSystem: nil,
135125
mainFilesProvider: mainFiles)
126+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
136127
let del = BSMDelegate(bsm)
137128
let initial = expectation(description: "initial settings")
138129
del.expected = [(a, nil, initial, #file, #line)]
@@ -149,17 +140,14 @@ final class BuildSystemManagerTests: XCTestCase {
149140
func testSettingsMainFileWithFallback() {
150141
let a = DocumentURI(string: "bsm:a.swift")
151142
let mainFiles = ManualMainFilesProvider()
152-
defer {
153-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
154-
_fixLifetime(mainFiles)
155-
}
156143
mainFiles.mainFiles = [a: Set([a])]
157144
let bs = ManualBuildSystem()
158145
let fallback = FallbackBuildSystem()
159146
let bsm = BuildSystemManager(
160147
buildSystem: bs,
161148
fallbackBuildSystem: fallback,
162149
mainFilesProvider: mainFiles)
150+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
163151
let del = BSMDelegate(bsm)
164152
let fallbackSettings = fallback.settings(for: a, .swift)
165153
let initial = expectation(description: "initial fallback settings")
@@ -184,16 +172,13 @@ final class BuildSystemManagerTests: XCTestCase {
184172
let a = DocumentURI(string: "bsm:a.swift")
185173
let b = DocumentURI(string: "bsm:b.swift")
186174
let mainFiles = ManualMainFilesProvider()
187-
defer {
188-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
189-
_fixLifetime(mainFiles)
190-
}
191175
mainFiles.mainFiles = [a: Set([a]), b: Set([b])]
192176
let bs = ManualBuildSystem()
193177
let bsm = BuildSystemManager(
194178
buildSystem: bs,
195179
fallbackBuildSystem: nil,
196180
mainFilesProvider: mainFiles)
181+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
197182
let del = BSMDelegate(bsm)
198183

199184
bs.map[a] = FileBuildSettings(compilerArguments: ["x"])
@@ -234,16 +219,13 @@ final class BuildSystemManagerTests: XCTestCase {
234219
let a = DocumentURI(string: "bsm:a.swift")
235220
let b = DocumentURI(string: "bsm:b.swift")
236221
let mainFiles = ManualMainFilesProvider()
237-
defer {
238-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
239-
_fixLifetime(mainFiles)
240-
}
241222
mainFiles.mainFiles = [a: Set([a]), b: Set([b])]
242223
let bs = ManualBuildSystem()
243224
let bsm = BuildSystemManager(
244225
buildSystem: bs,
245226
fallbackBuildSystem: nil,
246227
mainFilesProvider: mainFiles)
228+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
247229
let del = BSMDelegate(bsm)
248230

249231
bs.map[a] = FileBuildSettings(compilerArguments: ["a"])
@@ -274,10 +256,6 @@ final class BuildSystemManagerTests: XCTestCase {
274256
let cpp1 = DocumentURI(string: "bsm:main.cpp")
275257
let cpp2 = DocumentURI(string: "bsm:other.cpp")
276258
let mainFiles = ManualMainFilesProvider()
277-
defer {
278-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
279-
_fixLifetime(mainFiles)
280-
}
281259
mainFiles.mainFiles = [
282260
h: Set([cpp1]),
283261
cpp1: Set([cpp1]),
@@ -289,6 +267,7 @@ final class BuildSystemManagerTests: XCTestCase {
289267
buildSystem: bs,
290268
fallbackBuildSystem: nil,
291269
mainFilesProvider: mainFiles)
270+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
292271
let del = BSMDelegate(bsm)
293272

294273
bs.map[cpp1] = FileBuildSettings(compilerArguments: ["C++ 1"])
@@ -333,10 +312,6 @@ final class BuildSystemManagerTests: XCTestCase {
333312
let h2 = DocumentURI(string: "bsm:header2.h")
334313
let cpp = DocumentURI(string: "bsm:main.cpp")
335314
let mainFiles = ManualMainFilesProvider()
336-
defer {
337-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
338-
_fixLifetime(mainFiles)
339-
}
340315
mainFiles.mainFiles = [
341316
h1: Set([cpp]),
342317
h2: Set([cpp]),
@@ -347,6 +322,7 @@ final class BuildSystemManagerTests: XCTestCase {
347322
buildSystem: bs,
348323
fallbackBuildSystem: nil,
349324
mainFilesProvider: mainFiles)
325+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
350326
let del = BSMDelegate(bsm)
351327

352328
bs.map[cpp] = FileBuildSettings(compilerArguments: ["C++ Main File"])
@@ -382,16 +358,13 @@ final class BuildSystemManagerTests: XCTestCase {
382358
let b = DocumentURI(string: "bsm:b.swift")
383359
let c = DocumentURI(string: "bsm:c.swift")
384360
let mainFiles = ManualMainFilesProvider()
385-
defer {
386-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
387-
_fixLifetime(mainFiles)
388-
}
389361
mainFiles.mainFiles = [a: Set([a]), b: Set([b]), c: Set([c])]
390362
let bs = ManualBuildSystem()
391363
let bsm = BuildSystemManager(
392364
buildSystem: bs,
393365
fallbackBuildSystem: nil,
394366
mainFilesProvider: mainFiles)
367+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
395368
let del = BSMDelegate(bsm)
396369

397370
bs.map[a] = FileBuildSettings(compilerArguments: ["a"])
@@ -436,10 +409,6 @@ final class BuildSystemManagerTests: XCTestCase {
436409
func testDependenciesUpdated() {
437410
let a = DocumentURI(string: "bsm:a.swift")
438411
let mainFiles = ManualMainFilesProvider()
439-
defer {
440-
// BuildSystemManager has a weak reference to mainFiles. Keep it alive.
441-
_fixLifetime(mainFiles)
442-
}
443412
mainFiles.mainFiles = [a: Set([a])]
444413

445414
class DepUpdateDuringRegistrationBS: ManualBuildSystem {
@@ -454,6 +423,7 @@ final class BuildSystemManagerTests: XCTestCase {
454423
buildSystem: bs,
455424
fallbackBuildSystem: nil,
456425
mainFilesProvider: mainFiles)
426+
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
457427
let del = BSMDelegate(bsm)
458428

459429
bs.map[a] = FileBuildSettings(compilerArguments: ["x"])

Tests/SourceKitLSPTests/CodeActionTests.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,10 @@ final class CodeActionTests: XCTestCase {
182182
let textDocument = TextDocumentIdentifier(loc.url)
183183
let start = Position(line: 2, utf16index: 0)
184184
let request = CodeActionRequest(range: start..<start, context: .init(), textDocument: textDocument)
185-
let result = try ws.sk.sendSync(request)
186-
187-
XCTAssertEqual(result, .codeActions([]))
185+
try withExtendedLifetime(ws) {
186+
let result = try ws.sk.sendSync(request)
187+
XCTAssertEqual(result, .codeActions([]))
188+
}
188189
}
189190

190191
func testSemanticRefactorLocalRenameResult() throws {
@@ -194,8 +195,10 @@ final class CodeActionTests: XCTestCase {
194195

195196
let textDocument = TextDocumentIdentifier(loc.url)
196197
let request = CodeActionRequest(range: loc.position..<loc.position, context: .init(), textDocument: textDocument)
197-
let result = try ws.sk.sendSync(request)
198-
XCTAssertEqual(result, .codeActions([]))
198+
try withExtendedLifetime(ws) {
199+
let result = try ws.sk.sendSync(request)
200+
XCTAssertEqual(result, .codeActions([]))
201+
}
199202
}
200203

201204
func testSemanticRefactorLocationCodeActionResult() throws {
@@ -205,7 +208,7 @@ final class CodeActionTests: XCTestCase {
205208

206209
let textDocument = TextDocumentIdentifier(loc.url)
207210
let request = CodeActionRequest(range: loc.position..<loc.position, context: .init(), textDocument: textDocument)
208-
let result = try ws.sk.sendSync(request)
211+
let result = try withExtendedLifetime(ws) { try ws.sk.sendSync(request) }
209212

210213
let expectedCommandArgs: LSPAny = ["actionString": "source.refactoring.kind.localize.string", "positionRange": ["start": ["character": 43, "line": 1], "end": ["character": 43, "line": 1]], "title": "Localize String", "textDocument": ["uri": .string(loc.url.absoluteString)]]
211214

@@ -230,7 +233,7 @@ final class CodeActionTests: XCTestCase {
230233

231234
let textDocument = TextDocumentIdentifier(rangeStartLoc.url)
232235
let request = CodeActionRequest(range: rangeStartLoc.position..<rangeEndLoc.position, context: .init(), textDocument: textDocument)
233-
let result = try ws.sk.sendSync(request)
236+
let result = try withExtendedLifetime(ws) { try ws.sk.sendSync(request) }
234237

235238
let expectedCommandArgs: LSPAny = ["actionString": "source.refactoring.kind.extract.function", "positionRange": ["start": ["character": 21, "line": 1], "end": ["character": 27, "line": 2]], "title": "Extract Method", "textDocument": ["uri": .string(rangeStartLoc.url.absoluteString)]]
236239
let metadataArguments: LSPAny = ["sourcekitlsp_textDocument": ["uri": .string(rangeStartLoc.url.absoluteString)]]

Tests/SourceKitLSPTests/ExecuteCommandTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ final class ExecuteCommandTests: XCTestCase {
6565
req.reply(ApplyEditResponse(applied: true, failureReason: nil))
6666
}
6767

68-
let result = try ws.sk.sendSync(request)
68+
let result = try withExtendedLifetime(ws) { try ws.sk.sendSync(request) }
6969

7070
guard case .dictionary(let resultDict) = result else {
7171
XCTFail("Result is not a dictionary.")
@@ -108,7 +108,7 @@ final class ExecuteCommandTests: XCTestCase {
108108
req.reply(ApplyEditResponse(applied: true, failureReason: nil))
109109
}
110110

111-
let result = try ws.sk.sendSync(request)
111+
let result = try withExtendedLifetime(ws) { try ws.sk.sendSync(request) }
112112

113113
guard case .dictionary(let resultDict) = result else {
114114
XCTFail("Result is not a dictionary.")

Tests/SourceKitLSPTests/FoldingRangeTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ final class FoldingRangeTests: XCTestCase {
3636
guard let (ws, uri) = try initializeWorkspace(withCapabilities: capabilities, testLoc: "fr:base") else { return }
3737

3838
let request = FoldingRangeRequest(textDocument: TextDocumentIdentifier(uri))
39-
let ranges = try ws.sk.sendSync(request)
39+
let ranges = try withExtendedLifetime(ws) { try ws.sk.sendSync(request) }
4040

4141
XCTAssertEqual(ranges, [
4242
FoldingRange(startLine: 0, startUTF16Index: 0, endLine: 2, endUTF16Index: 0, kind: .comment),
@@ -62,7 +62,7 @@ final class FoldingRangeTests: XCTestCase {
6262
guard let (ws, uri) = try initializeWorkspace(withCapabilities: capabilities, testLoc: "fr:base") else { return }
6363

6464
let request = FoldingRangeRequest(textDocument: TextDocumentIdentifier(uri))
65-
let ranges = try ws.sk.sendSync(request)
65+
let ranges = try withExtendedLifetime(ws) { try ws.sk.sendSync(request) }
6666

6767
XCTAssertEqual(ranges, [
6868
FoldingRange(startLine: 0, endLine: 1, kind: .comment),
@@ -83,7 +83,7 @@ final class FoldingRangeTests: XCTestCase {
8383
capabilities.rangeLimit = limit
8484
guard let (ws, url) = try initializeWorkspace(withCapabilities: capabilities, testLoc: "fr:base") else { return }
8585
let request = FoldingRangeRequest(textDocument: TextDocumentIdentifier(url))
86-
let ranges = try ws.sk.sendSync(request)
86+
let ranges = try withExtendedLifetime(ws) { try ws.sk.sendSync(request) }
8787
XCTAssertEqual(ranges?.count, expectedRanges, "Failed rangeLimit test at line \(line)")
8888
}
8989

@@ -100,7 +100,7 @@ final class FoldingRangeTests: XCTestCase {
100100
guard let (ws, url) = try initializeWorkspace(withCapabilities: capabilities, testLoc: "fr:empty") else { return }
101101

102102
let request = FoldingRangeRequest(textDocument: TextDocumentIdentifier(url))
103-
let ranges = try ws.sk.sendSync(request)
103+
let ranges = try withExtendedLifetime(ws) { try ws.sk.sendSync(request) }
104104

105105
XCTAssertEqual(ranges?.count, 0)
106106
}

Tests/SourceKitLSPTests/LocalClangTests.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ final class LocalClangTests: XCTestCase {
180180

181181
try! ws.openDocument(loc.url, language: .objective_c)
182182

183-
waitForExpectations(timeout: 15)
183+
withExtendedLifetime(ws) {
184+
waitForExpectations(timeout: 15)
185+
}
184186
}
185187
}

0 commit comments

Comments
 (0)