Skip to content

Commit 871c9da

Browse files
authored
SwiftSyntax: Teach SwiftSyntax to use SourceKitd to serialize syntax trees. (#14424)
When using SwiftSyntax as a standalone tool, we invoke Swiftc internally to get serialized syntax trees. This is not ideal for several reasons: (1) we have to hard-code the relative path of swiftc to invoke it; (2) we have to rely on standard input/output to pass the tree across the process boundaries; and (3) we have to maintain two different ways to get syntax tree (swiftc and sourcekitd). This patch attempts to teach SwiftSyntax to use SourceKitd to get the tree just like other clients. We first add a SourceKitd client library written in Swift; and next teach SwiftSyntax to adopt this SourceKitd client-side library. For platforms other than MacOS, we still use Swiftc to get syntax trees. This client library also allows us to add SourceKitd tests in Swift. This patch also re-enables several flaky tests.
1 parent 22da6dd commit 871c9da

File tree

12 files changed

+550
-14
lines changed

12 files changed

+550
-14
lines changed

cmake/modules/AddSwift.cmake

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ function(_add_variant_c_compile_flags)
255255
else()
256256
list(APPEND result "-DNDEBUG")
257257
endif()
258-
258+
259259
if(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS)
260260
list(APPEND result "-DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS")
261261
endif()
@@ -320,7 +320,7 @@ function(_add_variant_swift_compile_flags
320320
if (SWIFT_ENABLE_GUARANTEED_NORMAL_ARGUMENTS)
321321
list(APPEND result "-Xfrontend" "-enable-guaranteed-normal-arguments")
322322
endif()
323-
323+
324324
if(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS)
325325
list(APPEND result "-D" "SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS")
326326
endif()
@@ -1605,7 +1605,7 @@ function(add_swift_library name)
16051605
if(SWIFTLIB_IS_SDK_OVERLAY)
16061606
list(APPEND swiftlib_swift_compile_flags_all "-Fsystem" "${SWIFT_SDK_${sdk}_PATH}/System/Library/PrivateFrameworks/")
16071607
endif()
1608-
1608+
16091609
if("${sdk}" STREQUAL "IOS_SIMULATOR")
16101610
if("${name}" STREQUAL "swiftMediaPlayer")
16111611
message("DISABLING AUTOLINK FOR swiftMediaPlayer")
@@ -1854,7 +1854,7 @@ function(add_swift_library name)
18541854
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
18551855
RUNTIME DESTINATION bin)
18561856
swift_is_installing_component(dev is_installing)
1857-
1857+
18581858
if(NOT is_installing)
18591859
set_property(GLOBAL APPEND PROPERTY SWIFT_BUILDTREE_EXPORTS ${name})
18601860
else()
@@ -2177,7 +2177,7 @@ function(add_swift_host_tool executable)
21772177

21782178
swift_is_installing_component(${ADDSWIFTHOSTTOOL_SWIFT_COMPONENT}
21792179
is_installing)
2180-
2180+
21812181
if(NOT is_installing)
21822182
set_property(GLOBAL APPEND PROPERTY SWIFT_BUILDTREE_EXPORTS ${executable})
21832183
else()

test/SwiftSyntax/ParseFile.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// REQUIRES: executable_test
33
// REQUIRES: OS=macosx
44
// REQUIRES: objc_interop
5-
// REQUIRES: rdar36740859
65

76
import Foundation
87
import StdlibUnittest

test/SwiftSyntax/VisitorTest.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
// REQUIRES: OS=macosx
44
// REQUIRES: objc_interop
55

6-
// FIXME: This test fails occassionally in CI with invalid json.
7-
// REQUIRES: disabled
8-
96
import StdlibUnittest
107
import Foundation
118
import SwiftSyntax

test/lit.cfg

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ else:
286286
test_resource_dir = os.path.join(config.swift_lib_dir, 'swift')
287287
resource_dir_opt = ""
288288
stdlib_resource_dir_opt = resource_dir_opt
289+
sourcekitd_framework_dir = config.swift_lib_dir
289290
lit_config.note('Using resource dir: ' + test_resource_dir)
290291

291292
# Parse the variant triple.
@@ -670,12 +671,13 @@ if run_vendor == 'apple':
670671
(run_cpu, run_os, run_vers, clang_mcp_opt))
671672

672673
config.target_build_swift = (
673-
"%s %s %s -F %s -Xlinker -rpath -Xlinker %s %s %s %s %s"
674+
"%s %s %s -F %s -Xlinker -rpath -Xlinker %s %s %s %s %s -F %s -Xlinker -rpath -Xlinker %s"
674675
% (xcrun_prefix, config.swiftc, target_options,
675676
extra_frameworks_dir, extra_frameworks_dir,
676677
sdk_overlay_linker_opt, config.swift_test_options,
677678
config.swift_driver_test_options,
678-
swift_execution_tests_extra_flags))
679+
swift_execution_tests_extra_flags, sourcekitd_framework_dir,
680+
sourcekitd_framework_dir))
679681
config.target_run = ""
680682

681683
if 'interpret' in lit_config.params:

tools/CMakeLists.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,27 @@ add_swift_tool_subdirectory(swift-api-digester)
1616
add_swift_tool_subdirectory(swift-syntax-test)
1717
add_swift_tool_subdirectory(swift-refactor)
1818

19+
if (SWIFT_BUILD_SOURCEKIT AND SWIFT_BUILD_STDLIB AND SWIFT_BUILD_SDK_OVERLAY)
20+
set(BUILD_SOURCEKIT_SWIFT_CLIENT TRUE)
21+
else()
22+
set(BUILD_SOURCEKIT_SWIFT_CLIENT FALSE)
23+
endif()
24+
1925
if(SWIFT_BUILD_SOURCEKIT)
2026
add_swift_tool_subdirectory(SourceKit)
27+
if(BUILD_SOURCEKIT_SWIFT_CLIENT)
28+
add_subdirectory(SwiftSourceKitClient)
29+
endif()
2130
endif()
2231

23-
2432
if(SWIFT_HOST_VARIANT STREQUAL "macosx")
2533
# Only build Darwin-specific tools when deploying to OS X.
2634
add_swift_tool_subdirectory(swift-stdlib-tool)
2735

2836
# SwiftSyntax depends on both the standard library (because it's a
2937
# Swift module), and the SDK overlays (because it depends on Foundation).
3038
# Ensure we only build SwiftSyntax when we're building both.
31-
if(SWIFT_BUILD_STDLIB AND SWIFT_BUILD_SDK_OVERLAY)
39+
if(BUILD_SOURCEKIT_SWIFT_CLIENT)
3240
add_subdirectory(SwiftSyntax)
3341
endif()
3442
endif()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
set(EXTRA_COMPILE_FLAGS "-F" "${SWIFT_LIBRARY_OUTPUT_INTDIR}")
2+
set(EXTRA_LINKER_FLAGS "-Xlinker" "-rpath" "-Xlinker" "${SWIFT_LIBRARY_OUTPUT_INTDIR}"
3+
"-Xlinker" "-F" "-Xlinker" "${SWIFT_LIBRARY_OUTPUT_INTDIR}")
4+
5+
add_swift_library(swiftSwiftSourceKit SHARED
6+
# This file should be listed the first. Module name is inferred from the
7+
# filename.
8+
SourceKitdClient.swift
9+
SourceKitdRequest.swift
10+
SourceKitdResponse.swift
11+
SourceKitdUID.swift
12+
13+
SWIFT_COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS}
14+
LINK_FLAGS ${EXTRA_LINKER_FLAGS}
15+
SWIFT_MODULE_DEPENDS Foundation
16+
INSTALL_IN_COMPONENT swift-syntax
17+
TARGET_SDKS OSX
18+
IS_STDLIB)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===--------------------- SourceKitdClient.swift -------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
// This file provides a wrapper of SourceKitd service.
13+
//===----------------------------------------------------------------------===//
14+
15+
import sourcekitd
16+
17+
public class SourceKitdService {
18+
19+
public init() {
20+
sourcekitd_initialize()
21+
}
22+
deinit {
23+
sourcekitd_shutdown()
24+
}
25+
public func sendSyn(request: SourceKitdRequest) -> SourceKitdResponse {
26+
return SourceKitdResponse(resp: sourcekitd_send_request_sync(request.rawRequest))
27+
}
28+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
//===--------------- SourceKitdRequest.swift ------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
// This file provides a convenient way to build a sourcekitd request.
13+
//===----------------------------------------------------------------------===//
14+
15+
import sourcekitd
16+
17+
public struct SourceKitdRequest: CustomStringConvertible {
18+
19+
public class Dictionary: CustomStringConvertible {
20+
let dict: sourcekitd_object_t
21+
22+
public init() {
23+
dict = sourcekitd_request_dictionary_create(nil, nil, 0)
24+
}
25+
26+
deinit {
27+
sourcekitd_request_release(UnsafeMutableRawPointer(dict))
28+
}
29+
30+
public func add(_ key: SourceKitdUID, value: String) {
31+
sourcekitd_request_dictionary_set_string(dict, key.uid, value)
32+
}
33+
34+
public func add(_ key: SourceKitdUID, value: Int) {
35+
sourcekitd_request_dictionary_set_int64(dict, key.uid, Int64(value))
36+
}
37+
38+
public func add(_ key: SourceKitdUID, value: SourceKitdUID) {
39+
sourcekitd_request_dictionary_set_uid(dict, key.uid, value.uid)
40+
}
41+
42+
public func add(_ key: SourceKitdUID, value: Array) {
43+
sourcekitd_request_dictionary_set_value(dict, key.uid, value.arr)
44+
}
45+
46+
public func add(_ key: SourceKitdUID, value: Dictionary) {
47+
sourcekitd_request_dictionary_set_value(dict, key.uid, value.dict)
48+
}
49+
50+
public func add(_ key: SourceKitdUID, value: Bool) {
51+
sourcekitd_request_dictionary_set_int64(dict, key.uid, value ? 1 : 0)
52+
}
53+
54+
public var description: String {
55+
let utf8Str = sourcekitd_request_description_copy(dict)!
56+
let result = String(cString: utf8Str)
57+
free(utf8Str)
58+
return result
59+
}
60+
61+
}
62+
63+
public class Array: CustomStringConvertible {
64+
let arr: sourcekitd_object_t
65+
private let Append: Int = -1
66+
67+
public init() {
68+
arr = sourcekitd_request_array_create(nil, 0)
69+
}
70+
71+
deinit {
72+
sourcekitd_request_release(arr)
73+
}
74+
75+
public func add(_ value: String) {
76+
sourcekitd_request_array_set_string(arr, Append, value)
77+
}
78+
79+
public func add(_ value: Int) {
80+
sourcekitd_request_array_set_int64(arr, Append, Int64(value))
81+
}
82+
83+
public func add(_ value: SourceKitdUID) {
84+
sourcekitd_request_array_set_uid(arr, Append, value.uid)
85+
}
86+
87+
public func add(_ value: Dictionary) {
88+
sourcekitd_request_array_set_value(arr, Append, value.dict)
89+
}
90+
91+
public var description: String {
92+
let utf8Str = sourcekitd_request_description_copy(arr)!
93+
let result = String(cString: utf8Str)
94+
free(utf8Str)
95+
return result
96+
}
97+
98+
}
99+
100+
private let req = Dictionary()
101+
102+
public init(uid: SourceKitdUID) {
103+
req.add(SourceKitdUID.key_request, value: uid)
104+
}
105+
106+
public func addParameter(_ key: SourceKitdUID, value: String) {
107+
req.add(key, value: value)
108+
}
109+
110+
public func addParameter(_ key: SourceKitdUID, value: Int) {
111+
req.add(key, value: value)
112+
}
113+
114+
public func addParameter(_ key: SourceKitdUID, value: SourceKitdUID) {
115+
req.add(key, value: value)
116+
}
117+
118+
public func addArrayParameter(_ key: SourceKitdUID) -> Array {
119+
let arr = Array()
120+
req.add(key, value: arr)
121+
return arr
122+
}
123+
124+
public func addDictionaryParameter(_ key: SourceKitdUID) -> Dictionary {
125+
let dict = Dictionary()
126+
req.add(key, value: dict)
127+
return dict
128+
}
129+
130+
public var description: String {
131+
return req.description
132+
}
133+
134+
public var rawRequest: sourcekitd_object_t {
135+
return req.dict
136+
}
137+
138+
public func addCompilerArgsToRequest(_ compilerArguments: [String]?,
139+
_ bufferName: String? = nil) {
140+
let args = self.addArrayParameter(SourceKitdUID.key_compilerargs)
141+
142+
if let compilerArguments = compilerArguments {
143+
for argument in compilerArguments {
144+
switch argument {
145+
// Exclude some arguments which SourceKit doesn't want or need.
146+
case "-Xfrontend":
147+
break
148+
default:
149+
args.add(argument)
150+
}
151+
}
152+
}
153+
}
154+
}

0 commit comments

Comments
 (0)