Skip to content

Commit 700384a

Browse files
author
Nathan Hawes
authored
Merge pull request #19689 from nathawes/keep-sourcekitd-response-alive-while-variant-lives
[SourceKit] Make each Variant keep a strong reference to its SourceKitdResponse context
2 parents f08d428 + 88b1ae9 commit 700384a

File tree

2 files changed

+54
-12
lines changed

2 files changed

+54
-12
lines changed

test/SourceKit/SwiftLang/basic.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-run-simple-swift
2+
// REQUIRES: executable_test
3+
// REQUIRES: OS=macosx
4+
// REQUIRES: objc_interop
5+
6+
import StdlibUnittest
7+
import SwiftLang
8+
9+
func getSyntaxMap() -> SourceKitdResponse.Array {
10+
let service = SourceKitdService()
11+
let request = SourceKitdRequest(uid: .request_EditorOpen)
12+
13+
request.addParameter(.key_Name, value: "foo")
14+
request.addParameter(.key_SourceText, value: "print(\"Hello, world!\")")
15+
request.addParameter(.key_EnableSyntaxMap, value: 1)
16+
request.addParameter(.key_SyntacticOnly, value: 1)
17+
18+
return service.sendSyn(request: request).value.getArray(.key_SyntaxMap)
19+
}
20+
21+
var swiftLangVariantTests = TestSuite("SwiftLangVariantTests")
22+
23+
swiftLangVariantTests.test("VariantLifetime") {
24+
let syntaxMap = getSyntaxMap()
25+
expectEqual(2, syntaxMap.count)
26+
}
27+
28+
runAllTests()

tools/SourceKit/tools/swift-lang/SourceKitdResponse.swift

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@ import sourcekitd
1717
public class SourceKitdResponse: CustomStringConvertible {
1818

1919
public struct Dictionary: CustomStringConvertible, CustomReflectable {
20+
// The lifetime of this sourcekitd_variant_t is tied to the response it came
21+
// from, so keep a reference to the response too.
2022
private let dict: sourcekitd_variant_t
23+
private let context: SourceKitdResponse
2124

22-
public init(dict: sourcekitd_variant_t) {
25+
26+
public init(dict: sourcekitd_variant_t, context: SourceKitdResponse) {
2327
assert(sourcekitd_variant_get_type(dict).rawValue ==
2428
SOURCEKITD_VARIANT_TYPE_DICTIONARY.rawValue)
2529
self.dict = dict
30+
self.context = context
2631
}
2732

2833
public func getString(_ key: SourceKitdUID) -> String {
@@ -47,12 +52,12 @@ public class SourceKitdResponse: CustomStringConvertible {
4752

4853
public func getArray(_ key: SourceKitdUID) -> Array {
4954
let value = sourcekitd_variant_dictionary_get_value(dict, key.uid)
50-
return Array(arr: value)
55+
return Array(arr: value, context: context)
5156
}
5257

5358
public func getDictionary(_ key: SourceKitdUID) -> Dictionary {
5459
let value = sourcekitd_variant_dictionary_get_value(dict, key.uid)
55-
return Dictionary(dict: value)
60+
return Dictionary(dict: value, context: context)
5661
}
5762

5863
public func getOptional(_ key: SourceKitdUID) -> Variant? {
@@ -61,7 +66,7 @@ public class SourceKitdResponse: CustomStringConvertible {
6166
SOURCEKITD_VARIANT_TYPE_NULL.rawValue {
6267
return nil
6368
}
64-
return Variant(val: value)
69+
return Variant(val: value, context: context)
6570
}
6671

6772
public var description: String {
@@ -74,17 +79,21 @@ public class SourceKitdResponse: CustomStringConvertible {
7479
}
7580

7681
public struct Array: CustomStringConvertible {
82+
// The lifetime of this sourcekitd_variant_t is tied to the response it came
83+
// from, so keep a reference to the response too.
7784
private let arr: sourcekitd_variant_t
85+
private let context: SourceKitdResponse
7886

7987
public var count: Int {
8088
let count = sourcekitd_variant_array_get_count(arr)
8189
return Int(count)
8290
}
8391

84-
public init(arr: sourcekitd_variant_t) {
92+
public init(arr: sourcekitd_variant_t, context: SourceKitdResponse) {
8593
assert(sourcekitd_variant_get_type(arr).rawValue ==
8694
SOURCEKITD_VARIANT_TYPE_ARRAY.rawValue)
8795
self.arr = arr
96+
self.context = context
8897
}
8998

9099
public func getString(_ index: Int) -> String {
@@ -109,20 +118,21 @@ public class SourceKitdResponse: CustomStringConvertible {
109118

110119
public func getArray(_ index: Int) -> Array {
111120
let value = sourcekitd_variant_array_get_value(arr, index)
112-
return Array(arr: value)
121+
return Array(arr: value, context: context)
113122
}
114123

115124
public func getDictionary(_ index: Int) -> Dictionary {
116125
let value = sourcekitd_variant_array_get_value(arr, index)
117-
return Dictionary(dict: value)
126+
return Dictionary(dict: value, context: context)
118127
}
119128

120129
public func enumerate(_ applier: (_ index: Int, _ value: Variant) -> Bool) {
121130
// The block passed to sourcekit_variant_array_apply() does not actually
122131
// escape, it's synchronous and not called after returning.
132+
let context = self.context
123133
withoutActuallyEscaping(applier) { escapingApplier in
124134
_ = sourcekitd_variant_array_apply(arr) { (index, elem) -> Bool in
125-
return escapingApplier(Int(index), Variant(val: elem))
135+
return escapingApplier(Int(index), Variant(val: elem, context: context))
126136
}
127137
}
128138
}
@@ -134,10 +144,14 @@ public class SourceKitdResponse: CustomStringConvertible {
134144
}
135145

136146
public struct Variant: CustomStringConvertible {
147+
// The lifetime of this sourcekitd_variant_t is tied to the response it came
148+
// from, so keep a reference to the response too.
137149
private let val: sourcekitd_variant_t
150+
fileprivate let context: SourceKitdResponse
138151

139-
fileprivate init(val: sourcekitd_variant_t) {
152+
fileprivate init(val: sourcekitd_variant_t, context: SourceKitdResponse) {
140153
self.val = val
154+
self.context = context
141155
}
142156

143157
public func getString() -> String {
@@ -167,11 +181,11 @@ public class SourceKitdResponse: CustomStringConvertible {
167181
}
168182

169183
public func getArray() -> Array {
170-
return Array(arr: val)
184+
return Array(arr: val, context: context)
171185
}
172186

173187
public func getDictionary() -> Dictionary {
174-
return Dictionary(dict: val)
188+
return Dictionary(dict: val, context: context)
175189
}
176190

177191
public var description: String {
@@ -182,7 +196,7 @@ public class SourceKitdResponse: CustomStringConvertible {
182196
private let resp: sourcekitd_response_t
183197

184198
public var value: Dictionary {
185-
return Dictionary(dict: sourcekitd_response_get_value(resp))
199+
return Dictionary(dict: sourcekitd_response_get_value(resp), context: self)
186200
}
187201

188202
/// Copies the raw bytes of the JSON description of this documentation item.

0 commit comments

Comments
 (0)