Skip to content

Commit f9887c6

Browse files
authored
Merge pull request #20375 from nathawes/keep-sourcekitd-response-alive-for-variant-lifetime-5.0
[5.0][SourceKit/SwiftLang] Keep sourcekitd response alive for variant lifetime
2 parents 0bea666 + f155ee7 commit f9887c6

File tree

2 files changed

+45
-13
lines changed

2 files changed

+45
-13
lines changed

tools/SourceKit/tools/swift-lang/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ if(NOT SWIFT_SOURCEKIT_USE_INPROC_LIBRARY AND SWIFT_BUILD_STDLIB)
1313
UIDs.swift.gyb
1414

1515
DEPENDS ${DEPENDS_LIST}
16-
SWIFT_MODULE_DEPENDS_OSX Darwin
16+
SWIFT_MODULE_DEPENDS_OSX Darwin Foundation
1717
PRIVATE_LINK_LIBRARIES ${SOURCEKITD_LINK_LIBS}
1818
SWIFT_COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS}
1919
INSTALL_IN_COMPONENT ${INSTALLED_COMP}

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

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,23 @@
1212
// This file provides convenient APIs to interpret a SourceKitd response.
1313
//===----------------------------------------------------------------------===//
1414

15+
import Foundation
1516
import sourcekitd
1617

1718
public class SourceKitdResponse: CustomStringConvertible {
1819

1920
public struct Dictionary: CustomStringConvertible, CustomReflectable {
21+
// The lifetime of this sourcekitd_variant_t is tied to the response it came
22+
// from, so keep a reference to the response too.
2023
private let dict: sourcekitd_variant_t
24+
private let context: SourceKitdResponse
2125

22-
public init(dict: sourcekitd_variant_t) {
26+
27+
public init(dict: sourcekitd_variant_t, context: SourceKitdResponse) {
2328
assert(sourcekitd_variant_get_type(dict).rawValue ==
2429
SOURCEKITD_VARIANT_TYPE_DICTIONARY.rawValue)
2530
self.dict = dict
31+
self.context = context
2632
}
2733

2834
public func getString(_ key: SourceKitdUID) -> String {
@@ -47,12 +53,21 @@ public class SourceKitdResponse: CustomStringConvertible {
4753

4854
public func getArray(_ key: SourceKitdUID) -> Array {
4955
let value = sourcekitd_variant_dictionary_get_value(dict, key.uid)
50-
return Array(arr: value)
56+
return Array(arr: value, context: context)
5157
}
5258

5359
public func getDictionary(_ key: SourceKitdUID) -> Dictionary {
5460
let value = sourcekitd_variant_dictionary_get_value(dict, key.uid)
55-
return Dictionary(dict: value)
61+
return Dictionary(dict: value, context: context)
62+
}
63+
64+
public func getData(_ key: SourceKitdUID) -> Data {
65+
let value = sourcekitd_variant_dictionary_get_value(dict, key.uid)
66+
let size = sourcekitd_variant_data_get_size(value)
67+
guard let ptr = sourcekitd_variant_data_get_ptr(value), size > 0 else {
68+
return Data()
69+
}
70+
return Data(bytes: ptr, count: size)
5671
}
5772

5873
public func getOptional(_ key: SourceKitdUID) -> Variant? {
@@ -61,7 +76,7 @@ public class SourceKitdResponse: CustomStringConvertible {
6176
SOURCEKITD_VARIANT_TYPE_NULL.rawValue {
6277
return nil
6378
}
64-
return Variant(val: value)
79+
return Variant(val: value, context: context)
6580
}
6681

6782
public var description: String {
@@ -74,17 +89,21 @@ public class SourceKitdResponse: CustomStringConvertible {
7489
}
7590

7691
public struct Array: CustomStringConvertible {
92+
// The lifetime of this sourcekitd_variant_t is tied to the response it came
93+
// from, so keep a reference to the response too.
7794
private let arr: sourcekitd_variant_t
95+
private let context: SourceKitdResponse
7896

7997
public var count: Int {
8098
let count = sourcekitd_variant_array_get_count(arr)
8199
return Int(count)
82100
}
83101

84-
public init(arr: sourcekitd_variant_t) {
102+
public init(arr: sourcekitd_variant_t, context: SourceKitdResponse) {
85103
assert(sourcekitd_variant_get_type(arr).rawValue ==
86104
SOURCEKITD_VARIANT_TYPE_ARRAY.rawValue)
87105
self.arr = arr
106+
self.context = context
88107
}
89108

90109
public func getString(_ index: Int) -> String {
@@ -109,20 +128,21 @@ public class SourceKitdResponse: CustomStringConvertible {
109128

110129
public func getArray(_ index: Int) -> Array {
111130
let value = sourcekitd_variant_array_get_value(arr, index)
112-
return Array(arr: value)
131+
return Array(arr: value, context: context)
113132
}
114133

115134
public func getDictionary(_ index: Int) -> Dictionary {
116135
let value = sourcekitd_variant_array_get_value(arr, index)
117-
return Dictionary(dict: value)
136+
return Dictionary(dict: value, context: context)
118137
}
119138

120139
public func enumerate(_ applier: (_ index: Int, _ value: Variant) -> Bool) {
121140
// The block passed to sourcekit_variant_array_apply() does not actually
122141
// escape, it's synchronous and not called after returning.
142+
let context = self.context
123143
withoutActuallyEscaping(applier) { escapingApplier in
124144
_ = sourcekitd_variant_array_apply(arr) { (index, elem) -> Bool in
125-
return escapingApplier(Int(index), Variant(val: elem))
145+
return escapingApplier(Int(index), Variant(val: elem, context: context))
126146
}
127147
}
128148
}
@@ -134,10 +154,14 @@ public class SourceKitdResponse: CustomStringConvertible {
134154
}
135155

136156
public struct Variant: CustomStringConvertible {
157+
// The lifetime of this sourcekitd_variant_t is tied to the response it came
158+
// from, so keep a reference to the response too.
137159
private let val: sourcekitd_variant_t
160+
fileprivate let context: SourceKitdResponse
138161

139-
fileprivate init(val: sourcekitd_variant_t) {
162+
fileprivate init(val: sourcekitd_variant_t, context: SourceKitdResponse) {
140163
self.val = val
164+
self.context = context
141165
}
142166

143167
public func getString() -> String {
@@ -167,11 +191,19 @@ public class SourceKitdResponse: CustomStringConvertible {
167191
}
168192

169193
public func getArray() -> Array {
170-
return Array(arr: val)
194+
return Array(arr: val, context: context)
171195
}
172196

173197
public func getDictionary() -> Dictionary {
174-
return Dictionary(dict: val)
198+
return Dictionary(dict: val, context: context)
199+
}
200+
201+
public func getData() -> Data {
202+
let size = sourcekitd_variant_data_get_size(val)
203+
guard let ptr = sourcekitd_variant_data_get_ptr(val), size > 0 else {
204+
return Data()
205+
}
206+
return Data(bytes: ptr, count: size)
175207
}
176208

177209
public var description: String {
@@ -182,7 +214,7 @@ public class SourceKitdResponse: CustomStringConvertible {
182214
private let resp: sourcekitd_response_t
183215

184216
public var value: Dictionary {
185-
return Dictionary(dict: sourcekitd_response_get_value(resp))
217+
return Dictionary(dict: sourcekitd_response_get_value(resp), context: self)
186218
}
187219

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

0 commit comments

Comments
 (0)