Re-apply "SwiftSyntax: Teach SwiftSyntax to use SourceKitd to serialize syntax trees. (#14424)" (#14465)

This commit is contained in:
Xi Ge
2018-02-08 15:11:31 -08:00
committed by GitHub
parent 21de54a3df
commit f8c77e17ce
15 changed files with 574 additions and 27 deletions

View File

@@ -11,6 +11,8 @@ set_property(GLOBAL PROPERTY JOB_POOLS local_jobs=${localhost_logical_cores})
# Put linking in that category # Put linking in that category
set_property(GLOBAL PROPERTY JOB_POOL_LINK local_jobs) set_property(GLOBAL PROPERTY JOB_POOL_LINK local_jobs)
ENABLE_LANGUAGE(C)
# First include general CMake utilities. # First include general CMake utilities.
include(SwiftUtils) include(SwiftUtils)
include(CheckSymbolExists) include(CheckSymbolExists)
@@ -748,10 +750,10 @@ if(swift_build_android AND NOT "${SWIFT_ANDROID_NDK_PATH}" STREQUAL "")
set(SWIFT_ANDROID_PREBUILT_PATH set(SWIFT_ANDROID_PREBUILT_PATH
"${SWIFT_ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-${SWIFT_ANDROID_NDK_GCC_VERSION}/prebuilt/${_swift_android_prebuilt_suffix}") "${SWIFT_ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-${SWIFT_ANDROID_NDK_GCC_VERSION}/prebuilt/${_swift_android_prebuilt_suffix}")
# Resolve the correct linker based on the file name of CMAKE_LINKER (being 'ld' or 'ld.gold' the options) # Resolve the correct linker based on the file name of CMAKE_LINKER (being 'ld' or 'ld.gold' the options)
get_filename_component(SWIFT_ANDROID_LINKER_NAME "${CMAKE_LINKER}" NAME) get_filename_component(SWIFT_ANDROID_LINKER_NAME "${CMAKE_LINKER}" NAME)
set(SWIFT_SDK_ANDROID_ARCH_armv7_LINKER set(SWIFT_SDK_ANDROID_ARCH_armv7_LINKER
"${SWIFT_ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-${SWIFT_ANDROID_NDK_GCC_VERSION}/prebuilt/${_swift_android_prebuilt_suffix}/bin/arm-linux-androideabi-${SWIFT_ANDROID_LINKER_NAME}") "${SWIFT_ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-${SWIFT_ANDROID_NDK_GCC_VERSION}/prebuilt/${_swift_android_prebuilt_suffix}/bin/arm-linux-androideabi-${SWIFT_ANDROID_LINKER_NAME}")
configure_sdk_unix(ANDROID "Android" "android" "android" "armv7" "armv7-none-linux-androideabi" "${SWIFT_ANDROID_SDK_PATH}") configure_sdk_unix(ANDROID "Android" "android" "android" "armv7" "armv7-none-linux-androideabi" "${SWIFT_ANDROID_SDK_PATH}")
@@ -879,7 +881,7 @@ endif()
############### ###############
# #
# We have to include stdlib/ before tools/. # We have to include stdlib/ before tools/.
# Do not move add_subdirectory(stdlib) after add_subdirectory(tools)! # Do not move add_subdirectory(stdlib) after add_subdirectory(tools)!
# #
# We must include stdlib/ before tools/ because stdlib/CMakeLists.txt # We must include stdlib/ before tools/ because stdlib/CMakeLists.txt
# declares the swift-stdlib-* set of targets. These targets will then # declares the swift-stdlib-* set of targets. These targets will then
@@ -898,7 +900,7 @@ add_subdirectory(stdlib)
if(SWIFT_INCLUDE_TOOLS) if(SWIFT_INCLUDE_TOOLS)
add_subdirectory(include) add_subdirectory(include)
add_subdirectory(lib) add_subdirectory(lib)
# Always include this after including stdlib/! # Always include this after including stdlib/!
# Refer to the large comment above the add_subdirectory(stdlib) call. # Refer to the large comment above the add_subdirectory(stdlib) call.
# https://bugs.swift.org/browse/SR-5975 # https://bugs.swift.org/browse/SR-5975

View File

@@ -255,7 +255,7 @@ function(_add_variant_c_compile_flags)
else() else()
list(APPEND result "-DNDEBUG") list(APPEND result "-DNDEBUG")
endif() endif()
if(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS) if(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS)
list(APPEND result "-DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS") list(APPEND result "-DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS")
endif() endif()
@@ -320,7 +320,7 @@ function(_add_variant_swift_compile_flags
if (SWIFT_ENABLE_GUARANTEED_NORMAL_ARGUMENTS) if (SWIFT_ENABLE_GUARANTEED_NORMAL_ARGUMENTS)
list(APPEND result "-Xfrontend" "-enable-guaranteed-normal-arguments") list(APPEND result "-Xfrontend" "-enable-guaranteed-normal-arguments")
endif() endif()
if(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS) if(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS)
list(APPEND result "-D" "SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS") list(APPEND result "-D" "SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS")
endif() endif()
@@ -1605,7 +1605,7 @@ function(add_swift_library name)
if(SWIFTLIB_IS_SDK_OVERLAY) if(SWIFTLIB_IS_SDK_OVERLAY)
list(APPEND swiftlib_swift_compile_flags_all "-Fsystem" "${SWIFT_SDK_${sdk}_PATH}/System/Library/PrivateFrameworks/") list(APPEND swiftlib_swift_compile_flags_all "-Fsystem" "${SWIFT_SDK_${sdk}_PATH}/System/Library/PrivateFrameworks/")
endif() endif()
if("${sdk}" STREQUAL "IOS_SIMULATOR") if("${sdk}" STREQUAL "IOS_SIMULATOR")
if("${name}" STREQUAL "swiftMediaPlayer") if("${name}" STREQUAL "swiftMediaPlayer")
message("DISABLING AUTOLINK FOR swiftMediaPlayer") message("DISABLING AUTOLINK FOR swiftMediaPlayer")
@@ -1854,7 +1854,7 @@ function(add_swift_library name)
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
RUNTIME DESTINATION bin) RUNTIME DESTINATION bin)
swift_is_installing_component(dev is_installing) swift_is_installing_component(dev is_installing)
if(NOT is_installing) if(NOT is_installing)
set_property(GLOBAL APPEND PROPERTY SWIFT_BUILDTREE_EXPORTS ${name}) set_property(GLOBAL APPEND PROPERTY SWIFT_BUILDTREE_EXPORTS ${name})
else() else()
@@ -2177,7 +2177,7 @@ function(add_swift_host_tool executable)
swift_is_installing_component(${ADDSWIFTHOSTTOOL_SWIFT_COMPONENT} swift_is_installing_component(${ADDSWIFTHOSTTOOL_SWIFT_COMPONENT}
is_installing) is_installing)
if(NOT is_installing) if(NOT is_installing)
set_property(GLOBAL APPEND PROPERTY SWIFT_BUILDTREE_EXPORTS ${executable}) set_property(GLOBAL APPEND PROPERTY SWIFT_BUILDTREE_EXPORTS ${executable})
else() else()

View File

@@ -6,6 +6,7 @@
import StdlibUnittest import StdlibUnittest
import Foundation import Foundation
import SwiftSyntax import SwiftSyntax
import SwiftSourceKit
func getInput(_ file: String) -> URL { func getInput(_ file: String) -> URL {
var result = URL(fileURLWithPath: #file) var result = URL(fileURLWithPath: #file)

View File

@@ -2,11 +2,11 @@
// REQUIRES: executable_test // REQUIRES: executable_test
// REQUIRES: OS=macosx // REQUIRES: OS=macosx
// REQUIRES: objc_interop // REQUIRES: objc_interop
// REQUIRES: rdar36740859
import Foundation import Foundation
import StdlibUnittest import StdlibUnittest
import SwiftSyntax import SwiftSyntax
import SwiftSourceKit
var ParseFile = TestSuite("ParseFile") var ParseFile = TestSuite("ParseFile")
@@ -31,7 +31,8 @@ ParseFile.test("ParseSingleFile") {
let currentFile = URL(fileURLWithPath: #file) let currentFile = URL(fileURLWithPath: #file)
expectDoesNotThrow({ expectDoesNotThrow({
let currentFileContents = try String(contentsOf: currentFile) let currentFileContents = try String(contentsOf: currentFile)
let parsed = try SourceFileSyntax.parse(currentFile) let parsed = try SourceFileSyntax.decodeSourceFileSyntax(try
SourceKitdService.encodeSourceFileSyntax(currentFile))
expectEqual("\(parsed)", currentFileContents) expectEqual("\(parsed)", currentFileContents)
}) })
} }

View File

@@ -3,12 +3,10 @@
// REQUIRES: OS=macosx // REQUIRES: OS=macosx
// REQUIRES: objc_interop // REQUIRES: objc_interop
// FIXME: This test fails occassionally in CI with invalid json.
// REQUIRES: disabled
import StdlibUnittest import StdlibUnittest
import Foundation import Foundation
import SwiftSyntax import SwiftSyntax
import SwiftSourceKit
func getInput(_ file: String) -> URL { func getInput(_ file: String) -> URL {
var result = URL(fileURLWithPath: #file) var result = URL(fileURLWithPath: #file)
@@ -29,7 +27,8 @@ VisitorTests.test("Basic") {
} }
} }
expectDoesNotThrow({ expectDoesNotThrow({
let parsed = try SourceFileSyntax.parse(getInput("visitor.swift")) let parsed = try SourceFileSyntax.decodeSourceFileSyntax(try
SourceKitdService.encodeSourceFileSyntax(getInput("visitor.swift")))
let counter = FuncCounter() let counter = FuncCounter()
let hashBefore = parsed.hashValue let hashBefore = parsed.hashValue
counter.visit(parsed) counter.visit(parsed)

View File

@@ -286,6 +286,7 @@ else:
test_resource_dir = os.path.join(config.swift_lib_dir, 'swift') test_resource_dir = os.path.join(config.swift_lib_dir, 'swift')
resource_dir_opt = "" resource_dir_opt = ""
stdlib_resource_dir_opt = resource_dir_opt stdlib_resource_dir_opt = resource_dir_opt
sourcekitd_framework_dir = config.swift_lib_dir
lit_config.note('Using resource dir: ' + test_resource_dir) lit_config.note('Using resource dir: ' + test_resource_dir)
# Parse the variant triple. # Parse the variant triple.
@@ -670,12 +671,13 @@ if run_vendor == 'apple':
(run_cpu, run_os, run_vers, clang_mcp_opt)) (run_cpu, run_os, run_vers, clang_mcp_opt))
config.target_build_swift = ( config.target_build_swift = (
"%s %s %s -F %s -Xlinker -rpath -Xlinker %s %s %s %s %s" "%s %s %s -F %s -Xlinker -rpath -Xlinker %s %s %s %s %s -F %s -Xlinker -rpath -Xlinker %s"
% (xcrun_prefix, config.swiftc, target_options, % (xcrun_prefix, config.swiftc, target_options,
extra_frameworks_dir, extra_frameworks_dir, extra_frameworks_dir, extra_frameworks_dir,
sdk_overlay_linker_opt, config.swift_test_options, sdk_overlay_linker_opt, config.swift_test_options,
config.swift_driver_test_options, config.swift_driver_test_options,
swift_execution_tests_extra_flags)) swift_execution_tests_extra_flags, sourcekitd_framework_dir,
sourcekitd_framework_dir))
config.target_run = "" config.target_run = ""
if 'interpret' in lit_config.params: if 'interpret' in lit_config.params:

View File

@@ -1,3 +1,14 @@
include(CheckIncludeFiles)
check_include_files("xpc/xpc.h" HAVE_XPC_H)
swift_is_installing_component(sourcekit-inproc SOURCEKIT_INSTALLING_INPROC)
if(HAVE_XPC_H AND SWIFT_BUILD_SOURCEKIT AND NOT SOURCEKIT_INSTALLING_INPROC)
set(BUILD_SOURCEKIT_XPC_SERVICE TRUE)
else()
set(BUILD_SOURCEKIT_XPC_SERVICE FALSE)
endif()
# Add generated libSyntax headers to global dependencies. # Add generated libSyntax headers to global dependencies.
list(APPEND LLVM_COMMON_DEPENDS swift-syntax-generated-headers) list(APPEND LLVM_COMMON_DEPENDS swift-syntax-generated-headers)
@@ -16,10 +27,18 @@ add_swift_tool_subdirectory(swift-api-digester)
add_swift_tool_subdirectory(swift-syntax-test) add_swift_tool_subdirectory(swift-syntax-test)
add_swift_tool_subdirectory(swift-refactor) add_swift_tool_subdirectory(swift-refactor)
if(SWIFT_BUILD_SOURCEKIT) if(SWIFT_BUILD_STDLIB AND SWIFT_BUILD_SDK_OVERLAY)
add_swift_tool_subdirectory(SourceKit) set(BUILD_FOUNDATION TRUE)
else()
set(BUILD_FOUNDATION FALSE)
endif() endif()
if(SWIFT_BUILD_SOURCEKIT)
add_swift_tool_subdirectory(SourceKit)
if(BUILD_SOURCEKIT_XPC_SERVICE AND BUILD_FOUNDATION)
add_subdirectory(SwiftSourceKitClient)
endif()
endif()
if(SWIFT_HOST_VARIANT STREQUAL "macosx") if(SWIFT_HOST_VARIANT STREQUAL "macosx")
# Only build Darwin-specific tools when deploying to OS X. # Only build Darwin-specific tools when deploying to OS X.
@@ -28,7 +47,7 @@ if(SWIFT_HOST_VARIANT STREQUAL "macosx")
# SwiftSyntax depends on both the standard library (because it's a # SwiftSyntax depends on both the standard library (because it's a
# Swift module), and the SDK overlays (because it depends on Foundation). # Swift module), and the SDK overlays (because it depends on Foundation).
# Ensure we only build SwiftSyntax when we're building both. # Ensure we only build SwiftSyntax when we're building both.
if(SWIFT_BUILD_STDLIB AND SWIFT_BUILD_SDK_OVERLAY) if(BUILD_FOUNDATION)
add_subdirectory(SwiftSyntax) add_subdirectory(SwiftSyntax)
endif() endif()
endif() endif()

View File

@@ -24,8 +24,6 @@ configure_file(
set(SOURCEKIT_DEPLOYMENT_OS "${SWIFT_HOST_VARIANT}") set(SOURCEKIT_DEPLOYMENT_OS "${SWIFT_HOST_VARIANT}")
set(SOURCEKIT_DEPLOYMENT_TARGET "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_DEPLOYMENT_VERSION}") set(SOURCEKIT_DEPLOYMENT_TARGET "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_DEPLOYMENT_VERSION}")
swift_is_installing_component(sourcekit-inproc SOURCEKIT_INSTALLING_INPROC)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin" AND NOT CMAKE_CROSSCOMPILING) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin" AND NOT CMAKE_CROSSCOMPILING)
set(CMAKE_OSX_SYSROOT "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_PATH}") set(CMAKE_OSX_SYSROOT "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_PATH}")
set(CMAKE_OSX_ARCHITECTURES "${SWIFT_HOST_VARIANT_ARCH}") set(CMAKE_OSX_ARCHITECTURES "${SWIFT_HOST_VARIANT_ARCH}")

View File

@@ -1,4 +1,4 @@
add_subdirectory(InProc) add_subdirectory(InProc)
if (HAVE_XPC_H) if(HAVE_XPC_H)
add_subdirectory(XPC) add_subdirectory(XPC)
endif() endif()

View File

@@ -1,7 +1,3 @@
include(CheckIncludeFiles)
check_include_files("xpc/xpc.h" HAVE_XPC_H)
# If we were going to build for APPLE but don't have XPC, just build inproc. # If we were going to build for APPLE but don't have XPC, just build inproc.
if(APPLE AND NOT HAVE_XPC_H) if(APPLE AND NOT HAVE_XPC_H)
set(SWIFT_SOURCEKIT_USE_INPROC_LIBRARY TRUE) set(SWIFT_SOURCEKIT_USE_INPROC_LIBRARY TRUE)

View File

@@ -0,0 +1,17 @@
set(EXTRA_COMPILE_FLAGS "-F" "${SWIFT_LIBRARY_OUTPUT_INTDIR}")
set(EXTRA_LINKER_FLAGS "-Xlinker" "-rpath" "-Xlinker" "${SWIFT_LIBRARY_OUTPUT_INTDIR}"
"-Xlinker" "-F" "-Xlinker" "${SWIFT_LIBRARY_OUTPUT_INTDIR}")
add_swift_library(swiftSwiftSourceKit SHARED
SourceKitdClient.swift
SourceKitdRequest.swift
SourceKitdResponse.swift
SourceKitdUID.swift
DEPENDS SourceKitService
SWIFT_COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS}
LINK_FLAGS ${EXTRA_LINKER_FLAGS}
SWIFT_MODULE_DEPENDS Foundation
INSTALL_IN_COMPONENT swift-syntax
TARGET_SDKS OSX
IS_STDLIB)

View File

@@ -0,0 +1,48 @@
//===--------------------- SourceKitdClient.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 a wrapper of SourceKitd service.
//===----------------------------------------------------------------------===//
import sourcekitd
import Foundation
public class SourceKitdService {
public init() {
sourcekitd_initialize()
}
deinit {
sourcekitd_shutdown()
}
public func sendSyn(request: SourceKitdRequest) -> SourceKitdResponse {
return SourceKitdResponse(resp: sourcekitd_send_request_sync(request.rawRequest))
}
}
extension SourceKitdService {
/// Parses the Swift file at the provided URL into a `Syntax` tree in Json
/// serialization format by querying SourceKitd service.
/// - Parameter url: The URL you wish to parse.
/// - Returns: The syntax tree in Json format string.
public static func encodeSourceFileSyntax(_ url: URL) throws -> String {
let Service = SourceKitdService()
let Request = SourceKitdRequest(uid: .source_request_editor_open)
let Path = url.path
Request.addParameter(.key_sourcefile, value: Path)
Request.addParameter(.key_name, value: Path)
Request.addParameter(.key_enable_syntax_tree, value: 1)
// FIXME: SourceKitd error handling.
let Resp = Service.sendSyn(request: Request)
return Resp.value.getString(.key_serialized_syntax_tree)
}
}

View File

@@ -0,0 +1,154 @@
//===--------------- SourceKitdRequest.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 a convenient way to build a sourcekitd request.
//===----------------------------------------------------------------------===//
import sourcekitd
public struct SourceKitdRequest: CustomStringConvertible {
public class Dictionary: CustomStringConvertible {
let dict: sourcekitd_object_t
public init() {
dict = sourcekitd_request_dictionary_create(nil, nil, 0)
}
deinit {
sourcekitd_request_release(UnsafeMutableRawPointer(dict))
}
public func add(_ key: SourceKitdUID, value: String) {
sourcekitd_request_dictionary_set_string(dict, key.uid, value)
}
public func add(_ key: SourceKitdUID, value: Int) {
sourcekitd_request_dictionary_set_int64(dict, key.uid, Int64(value))
}
public func add(_ key: SourceKitdUID, value: SourceKitdUID) {
sourcekitd_request_dictionary_set_uid(dict, key.uid, value.uid)
}
public func add(_ key: SourceKitdUID, value: Array) {
sourcekitd_request_dictionary_set_value(dict, key.uid, value.arr)
}
public func add(_ key: SourceKitdUID, value: Dictionary) {
sourcekitd_request_dictionary_set_value(dict, key.uid, value.dict)
}
public func add(_ key: SourceKitdUID, value: Bool) {
sourcekitd_request_dictionary_set_int64(dict, key.uid, value ? 1 : 0)
}
public var description: String {
let utf8Str = sourcekitd_request_description_copy(dict)!
let result = String(cString: utf8Str)
free(utf8Str)
return result
}
}
public class Array: CustomStringConvertible {
let arr: sourcekitd_object_t
private let Append: Int = -1
public init() {
arr = sourcekitd_request_array_create(nil, 0)
}
deinit {
sourcekitd_request_release(arr)
}
public func add(_ value: String) {
sourcekitd_request_array_set_string(arr, Append, value)
}
public func add(_ value: Int) {
sourcekitd_request_array_set_int64(arr, Append, Int64(value))
}
public func add(_ value: SourceKitdUID) {
sourcekitd_request_array_set_uid(arr, Append, value.uid)
}
public func add(_ value: Dictionary) {
sourcekitd_request_array_set_value(arr, Append, value.dict)
}
public var description: String {
let utf8Str = sourcekitd_request_description_copy(arr)!
let result = String(cString: utf8Str)
free(utf8Str)
return result
}
}
private let req = Dictionary()
public init(uid: SourceKitdUID) {
req.add(SourceKitdUID.key_request, value: uid)
}
public func addParameter(_ key: SourceKitdUID, value: String) {
req.add(key, value: value)
}
public func addParameter(_ key: SourceKitdUID, value: Int) {
req.add(key, value: value)
}
public func addParameter(_ key: SourceKitdUID, value: SourceKitdUID) {
req.add(key, value: value)
}
public func addArrayParameter(_ key: SourceKitdUID) -> Array {
let arr = Array()
req.add(key, value: arr)
return arr
}
public func addDictionaryParameter(_ key: SourceKitdUID) -> Dictionary {
let dict = Dictionary()
req.add(key, value: dict)
return dict
}
public var description: String {
return req.description
}
public var rawRequest: sourcekitd_object_t {
return req.dict
}
public func addCompilerArgsToRequest(_ compilerArguments: [String]?,
_ bufferName: String? = nil) {
let args = self.addArrayParameter(SourceKitdUID.key_compilerargs)
if let compilerArguments = compilerArguments {
for argument in compilerArguments {
switch argument {
// Exclude some arguments which SourceKit doesn't want or need.
case "-Xfrontend":
break
default:
args.add(argument)
}
}
}
}
}

View File

@@ -0,0 +1,258 @@
//===--------------------- 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?
}

View File

@@ -0,0 +1,52 @@
//===------------------------ SourceKitdUID.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 SourceKitd UIDs.
//===----------------------------------------------------------------------===//
import sourcekitd
public struct SourceKitdUID: Equatable, Hashable, CustomStringConvertible {
public let uid: sourcekitd_uid_t
init(uid: sourcekitd_uid_t) {
self.uid = uid
}
public init(string: String) {
self.uid = sourcekitd_uid_get_from_cstr(string)
}
public var description: String {
return String(cString: sourcekitd_uid_get_string_ptr(uid))
}
public var asString: String {
return String(cString: sourcekitd_uid_get_string_ptr(uid))
}
public var hashValue: Int {
return uid.hashValue
}
}
extension SourceKitdUID {
public static let key_request = SourceKitdUID(string: "key.request")
public static let key_compilerargs = SourceKitdUID(string: "key.compilerargs")
public static let key_notification = SourceKitdUID(string: "key.notification")
public static let key_name = SourceKitdUID(string: "key.name")
public static let key_enable_syntax_tree = SourceKitdUID(string: "key.enablesyntaxtree")
public static let key_serialized_syntax_tree = SourceKitdUID(string: "key.serialized_syntax_tree")
public static let key_sourcefile = SourceKitdUID(string: "key.sourcefile")
public static let compilerCrashedNotification = SourceKitdUID(string: "notification.toolchain-compiler-crashed")
public static let source_request_editor_open = SourceKitdUID(string: "source.request.editor.open")
public static let source_notification_editor_documentupdate = SourceKitdUID(string: "source.notification.editor.documentupdate")
}