Files
swift-mirror/tools/SwiftSourceKitClient/SourceKitdResponse.swift

259 lines
8.0 KiB
Swift

//===--------------------- SourceKitdResponse.swift -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// This file provides convenient APIs to interpret a SourceKitd response.
//===----------------------------------------------------------------------===//
import Foundation
import sourcekitd
public class SourceKitdResponse: CustomStringConvertible {
public struct Dictionary: CustomStringConvertible, CustomReflectable {
private let dict: sourcekitd_variant_t
public init(dict: sourcekitd_variant_t) {
assert(sourcekitd_variant_get_type(dict).rawValue ==
SOURCEKITD_VARIANT_TYPE_DICTIONARY.rawValue)
self.dict = dict
}
public func getString(_ key: SourceKitdUID) -> String {
let value = sourcekitd_variant_dictionary_get_string(dict, key.uid)!
return String(cString: value)
}
public func getInt(_ key: SourceKitdUID) -> Int {
let value = sourcekitd_variant_dictionary_get_int64(dict, key.uid)
return Int(value)
}
public func getBool(_ key: SourceKitdUID) -> Bool {
let value = sourcekitd_variant_dictionary_get_bool(dict, key.uid)
return value
}
public func getUID(_ key: SourceKitdUID) -> SourceKitdUID {
let value = sourcekitd_variant_dictionary_get_uid(dict, key.uid)!
return SourceKitdUID(uid: value)
}
public func getArray(_ key: SourceKitdUID) -> Array {
let value = sourcekitd_variant_dictionary_get_value(dict, key.uid)
return Array(arr: value)
}
public func getDictionary(_ key: SourceKitdUID) -> Dictionary {
let value = sourcekitd_variant_dictionary_get_value(dict, key.uid)
return Dictionary(dict: value)
}
public func getOptional(_ key: SourceKitdUID) -> Variant? {
let value = sourcekitd_variant_dictionary_get_value(dict, key.uid)
if sourcekitd_variant_get_type(value).rawValue ==
SOURCEKITD_VARIANT_TYPE_NULL.rawValue {
return nil
}
return Variant(val: value)
}
public var description: String {
return dict.description
}
public var customMirror: Mirror {
return Mirror(self, children: [:])
}
}
public struct Array: CustomStringConvertible {
private let arr: sourcekitd_variant_t
public var count: Int {
let count = sourcekitd_variant_array_get_count(arr)
return Int(count)
}
public init(arr: sourcekitd_variant_t) {
assert(sourcekitd_variant_get_type(arr).rawValue ==
SOURCEKITD_VARIANT_TYPE_ARRAY.rawValue)
self.arr = arr
}
public func getString(_ index: Int) -> String {
let value = sourcekitd_variant_array_get_string(arr, index)!
return String(cString: value)
}
public func getInt(_ index: Int) -> Int {
let value = sourcekitd_variant_array_get_int64(arr, index)
return Int(value)
}
public func getBool(_ index: Int) -> Bool {
let value = sourcekitd_variant_array_get_bool(arr, index)
return value
}
public func getUID(_ index: Int) -> SourceKitdUID {
let value = sourcekitd_variant_array_get_uid(arr, index)!
return SourceKitdUID(uid: value)
}
public func getArray(_ index: Int) -> Array {
let value = sourcekitd_variant_array_get_value(arr, index)
return Array(arr: value)
}
public func getDictionary(_ index: Int) -> Dictionary {
let value = sourcekitd_variant_array_get_value(arr, index)
return Dictionary(dict: value)
}
public func enumerate(_ applier: (_ index: Int, _ value: Variant) -> Bool) {
// The block passed to sourcekit_variant_array_apply() does not actually
// escape, it's synchronous and not called after returning.
withoutActuallyEscaping(applier) { escapingApplier in
_ = sourcekitd_variant_array_apply(arr) { (index, elem) -> Bool in
return escapingApplier(Int(index), Variant(val: elem))
}
}
}
public var description: String {
return arr.description
}
}
public struct Variant: CustomStringConvertible {
private let val: sourcekitd_variant_t
fileprivate init(val: sourcekitd_variant_t) {
self.val = val
}
public func getString() -> String {
let value = sourcekitd_variant_string_get_ptr(val)!
let length = sourcekitd_variant_string_get_length(val)
return fromCStringLen(value, length: length)!
}
public func getStringBuffer() -> UnsafeBufferPointer<Int8> {
return UnsafeBufferPointer(start: sourcekitd_variant_string_get_ptr(val),
count: sourcekitd_variant_string_get_length(val))
}
public func getInt() -> Int {
let value = sourcekitd_variant_int64_get_value(val)
return Int(value)
}
public func getBool() -> Bool {
let value = sourcekitd_variant_bool_get_value(val)
return value
}
public func getUID() -> SourceKitdUID {
let value = sourcekitd_variant_uid_get_value(val)!
return SourceKitdUID(uid:value)
}
public func getArray() -> Array {
return Array(arr: val)
}
public func getDictionary() -> Dictionary {
return Dictionary(dict: val)
}
public var description: String {
return val.description
}
}
private let resp: sourcekitd_response_t
public var value: Dictionary {
return Dictionary(dict: sourcekitd_response_get_value(resp))
}
/// Copies the raw bytes of the JSON description of this documentation item.
/// The caller is responsible for freeing the associated memory.
public func copyRawJSONDocumentation() -> UnsafeMutablePointer<Int8>? {
return sourcekitd_variant_json_description_copy(
sourcekitd_response_get_value(resp))
}
/// Whether or not this response represents an error.
public var isError: Bool {
return sourcekitd_response_is_error(resp)
}
/// Whether or not this response represents a notification.
public var isNotification: Bool {
return value.getOptional(.key_notification) != nil
}
/// Whether or not this response represents a connection interruption error.
public var isConnectionInterruptionError: Bool {
return sourcekitd_response_is_error(resp) &&
sourcekitd_response_error_get_kind(resp) ==
SOURCEKITD_ERROR_CONNECTION_INTERRUPTED
}
/// Whether or not this response represents a compiler crash.
public var isCompilerCrash: Bool {
guard let notification = value.getOptional(.key_notification)?.getUID()
else { return false }
return notification == .compilerCrashedNotification
}
/// If this is a document update notification, returns the name of the
/// document to which this update applies. Otherwise, returns `nil`.
public var documentUpdateNotificationDocumentName: String? {
let response = value
guard let notification = response.getOptional(.key_notification)?.getUID(),
notification == .source_notification_editor_documentupdate
else { return nil }
return response.getOptional(.key_name)?.getString()
}
public init(resp: sourcekitd_response_t) {
self.resp = resp
}
deinit {
sourcekitd_response_dispose(resp)
}
public var description: String {
let utf8Str = sourcekitd_response_description_copy(resp)!
let result = String(cString: utf8Str)
free(utf8Str)
return result
}
}
extension sourcekitd_variant_t: CustomStringConvertible {
public var description: String {
let utf8Str = sourcekitd_variant_description_copy(self)!
let result = String(cString: utf8Str)
free(utf8Str)
return result
}
}
private func fromCStringLen(_ ptr: UnsafePointer<Int8>, length: Int) -> String? {
return NSString(bytes: ptr, length: length,
encoding: String.Encoding.utf8.rawValue) as String?
}