@@ -193,52 +193,56 @@ package actor SourceKitD {
193193 let dlopenModes : DLOpenFlags = [ . lazy, . local, . first]
194194 #endif
195195 let dlhandle = try dlopen ( path. filePath, mode: dlopenModes)
196- do {
197- try self . init (
198- dlhandle: dlhandle,
199- path: path,
200- pluginPaths: pluginPaths,
201- initialize: initialize
202- )
203- } catch {
204- try ? dlhandle. close ( )
205- throw error
206- }
196+ try self . init (
197+ dlhandle: dlhandle,
198+ path: path,
199+ pluginPaths: pluginPaths,
200+ initialize: initialize
201+ )
207202 }
208203
204+ /// Create a `SourceKitD` instance from an existing `DLHandle`. `SourceKitD` takes over ownership of the `DLHandler`
205+ /// and will close it when the `SourceKitD` instance gets deinitialized or if the initializer throws.
209206 package init ( dlhandle: DLHandle , path: URL , pluginPaths: PluginPaths ? , initialize: Bool ) throws {
210- self . path = path
211- self . dylib = dlhandle
212- let api = try sourcekitd_api_functions_t ( dlhandle)
213- self . api = api
214-
215- // We load the plugin-related functions eagerly so the members are initialized and we don't have data races on first
216- // access to eg. `pluginApi`. But if one of the functions is missing, we will only emit that error when that family
217- // of functions is being used. For example, it is expected that the plugin functions are not available in
218- // SourceKit-LSP.
219- self . ideApiResult = Result ( catching: { try sourcekitd_ide_api_functions_t ( dlhandle) } )
220- self . pluginApiResult = Result ( catching: { try sourcekitd_plugin_api_functions_t ( dlhandle) } )
221- self . servicePluginApiResult = Result ( catching: { try sourcekitd_service_plugin_api_functions_t ( dlhandle) } )
222-
223- if let pluginPaths {
224- api. register_plugin_path ? ( pluginPaths. clientPlugin. path, pluginPaths. servicePlugin. path)
225- }
226- if initialize {
227- self . api. initialize ( )
228- }
207+ do {
208+ self . path = path
209+ self . dylib = dlhandle
210+ let api = try sourcekitd_api_functions_t ( dlhandle)
211+ self . api = api
212+
213+ // We load the plugin-related functions eagerly so the members are initialized and we don't have data races on first
214+ // access to eg. `pluginApi`. But if one of the functions is missing, we will only emit that error when that family
215+ // of functions is being used. For example, it is expected that the plugin functions are not available in
216+ // SourceKit-LSP.
217+ self . ideApiResult = Result ( catching: { try sourcekitd_ide_api_functions_t ( dlhandle) } )
218+ self . pluginApiResult = Result ( catching: { try sourcekitd_plugin_api_functions_t ( dlhandle) } )
219+ self . servicePluginApiResult = Result ( catching: { try sourcekitd_service_plugin_api_functions_t ( dlhandle) } )
229220
230- if initialize {
231- self . api. set_notification_handler { [ weak self] rawResponse in
232- guard let self, let rawResponse else { return }
233- let response = SKDResponse ( rawResponse, sourcekitd: self )
234- self . notificationHandlingQueue. async {
235- let handlers = await self . notificationHandlers. compactMap ( \. value)
221+ if let pluginPaths {
222+ api. register_plugin_path ? ( pluginPaths. clientPlugin. path, pluginPaths. servicePlugin. path)
223+ }
224+ if initialize {
225+ self . api. initialize ( )
226+ }
227+
228+ if initialize {
229+ self . api. set_notification_handler { [ weak self] rawResponse in
230+ guard let self, let rawResponse else { return }
231+ let response = SKDResponse ( rawResponse, sourcekitd: self )
232+ self . notificationHandlingQueue. async {
233+ let handlers = await self . notificationHandlers. compactMap ( \. value)
236234
237- for handler in handlers {
238- handler. notification ( response)
235+ for handler in handlers {
236+ handler. notification ( response)
237+ }
239238 }
240239 }
241240 }
241+ } catch {
242+ orLog ( " Closing dlhandle after opening sourcekitd failed " ) {
243+ try ? dlhandle. close ( )
244+ }
245+ throw error
242246 }
243247 }
244248
0 commit comments