Skip to content

Commit fcc527f

Browse files
authored
Merge pull request #1318 from ahoppen/log-in-localconnection
Move `LocalConnection` to `LSPTestSupport`
2 parents 0ce2107 + 195d3af commit fcc527f

File tree

5 files changed

+136
-86
lines changed

5 files changed

+136
-86
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 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+
13+
import Dispatch
14+
import LSPLogging
15+
import LanguageServerProtocol
16+
17+
/// A connection between two message handlers in the same process.
18+
///
19+
/// You must call `start(handler:)` before sending any messages, and must call `close()` when finished to avoid a memory leak.
20+
///
21+
/// ```
22+
/// let client: MessageHandler = ...
23+
/// let server: MessageHandler = ...
24+
/// let conn = LocalConnection()
25+
/// conn.start(handler: server)
26+
/// conn.send(...) // handled by server
27+
/// conn.close()
28+
/// ```
29+
///
30+
/// - Note: Unchecked sendable conformance because shared state is guarded by `queue`.
31+
public final class LocalConnection: Connection, @unchecked Sendable {
32+
enum State {
33+
case ready, started, closed
34+
}
35+
36+
/// A name of the endpoint for this connection, used for logging, e.g. `clangd`.
37+
private let name: String
38+
39+
/// The queue guarding `_nextRequestID`.
40+
let queue: DispatchQueue = DispatchQueue(label: "local-connection-queue")
41+
42+
var _nextRequestID: Int = 0
43+
44+
var state: State = .ready
45+
46+
var handler: MessageHandler? = nil
47+
48+
public init(name: String) {
49+
self.name = name
50+
}
51+
52+
deinit {
53+
if state != .closed {
54+
close()
55+
}
56+
}
57+
58+
public func start(handler: MessageHandler) {
59+
precondition(state == .ready)
60+
state = .started
61+
self.handler = handler
62+
}
63+
64+
public func close() {
65+
precondition(state != .closed)
66+
handler = nil
67+
state = .closed
68+
}
69+
70+
func nextRequestID() -> RequestID {
71+
return queue.sync {
72+
_nextRequestID += 1
73+
return .number(_nextRequestID)
74+
}
75+
}
76+
77+
public func send<Notification: NotificationType>(_ notification: Notification) {
78+
logger.info(
79+
"""
80+
Sending notification to \(self.name, privacy: .public)
81+
\(notification.forLogging)
82+
"""
83+
)
84+
self.handler?.handle(notification)
85+
}
86+
87+
public func send<Request: RequestType>(
88+
_ request: Request,
89+
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
90+
) -> RequestID {
91+
let id = nextRequestID()
92+
93+
logger.info(
94+
"""
95+
Sending request to \(self.name, privacy: .public) (id: \(id, privacy: .public)):
96+
\(request.forLogging)
97+
"""
98+
)
99+
100+
guard let handler = self.handler else {
101+
logger.info(
102+
"""
103+
Replying to request \(id, privacy: .public) with .serverCancelled because no handler is specified in \(self.name, privacy: .public)
104+
"""
105+
)
106+
reply(.failure(.serverCancelled))
107+
return id
108+
}
109+
110+
precondition(self.state == .started)
111+
handler.handle(request, id: id) { result in
112+
switch result {
113+
case .success(let response):
114+
logger.info(
115+
"""
116+
Received reply for request \(id, privacy: .public) from \(self.name, privacy: .public)
117+
\(response.forLogging)
118+
"""
119+
)
120+
case .failure(let error):
121+
logger.error(
122+
"""
123+
Received error for request \(id, privacy: .public) from \(self.name, privacy: .public)
124+
\(error.forLogging)
125+
"""
126+
)
127+
}
128+
reply(result)
129+
}
130+
131+
return id
132+
}
133+
}

Sources/LSPTestSupport/TestJSONRPCConnection.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ public final class TestJSONRPCConnection: Sendable {
7676

7777
public struct TestLocalConnection {
7878
public let client: TestClient
79-
public let clientConnection: LocalConnection = LocalConnection()
79+
public let clientConnection: LocalConnection = LocalConnection(name: "Test")
8080
public let server: TestServer
81-
public let serverConnection: LocalConnection = LocalConnection()
81+
public let serverConnection: LocalConnection = LocalConnection(name: "Test")
8282

8383
public init(allowUnexpectedNotification: Bool = true) {
8484
client = TestClient(connectionToServer: serverConnection, allowUnexpectedNotification: allowUnexpectedNotification)

Sources/LanguageServerProtocol/Connection.swift

Lines changed: 0 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
import Dispatch
14-
1513
/// An abstract connection, allow messages to be sent to a (potentially remote) `MessageHandler`.
1614
public protocol Connection: AnyObject, Sendable {
1715

@@ -47,83 +45,3 @@ public protocol MessageHandler: AnyObject, Sendable {
4745
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
4846
)
4947
}
50-
51-
/// A connection between two message handlers in the same process.
52-
///
53-
/// You must call `start(handler:)` before sending any messages, and must call `close()` when finished to avoid a memory leak.
54-
///
55-
/// ```
56-
/// let client: MessageHandler = ...
57-
/// let server: MessageHandler = ...
58-
/// let conn = LocalConnection()
59-
/// conn.start(handler: server)
60-
/// conn.send(...) // handled by server
61-
/// conn.close()
62-
/// ```
63-
///
64-
/// - Note: Unchecked sendable conformance because shared state is guarded by `queue`.
65-
public final class LocalConnection: Connection, @unchecked Sendable {
66-
67-
enum State {
68-
case ready, started, closed
69-
}
70-
71-
/// The queue guarding `_nextRequestID`.
72-
let queue: DispatchQueue = DispatchQueue(label: "local-connection-queue")
73-
74-
var _nextRequestID: Int = 0
75-
76-
var state: State = .ready
77-
78-
var handler: MessageHandler? = nil
79-
80-
public init() {}
81-
82-
deinit {
83-
if state != .closed {
84-
close()
85-
}
86-
}
87-
88-
public func start(handler: MessageHandler) {
89-
precondition(state == .ready)
90-
state = .started
91-
self.handler = handler
92-
}
93-
94-
public func close() {
95-
precondition(state != .closed)
96-
handler = nil
97-
state = .closed
98-
}
99-
100-
func nextRequestID() -> RequestID {
101-
return queue.sync {
102-
_nextRequestID += 1
103-
return .number(_nextRequestID)
104-
}
105-
}
106-
107-
public func send<Notification>(_ notification: Notification) where Notification: NotificationType {
108-
self.handler?.handle(notification)
109-
}
110-
111-
public func send<Request: RequestType>(
112-
_ request: Request,
113-
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
114-
) -> RequestID {
115-
let id = nextRequestID()
116-
117-
guard let handler = self.handler else {
118-
reply(.failure(.serverCancelled))
119-
return id
120-
}
121-
122-
precondition(self.state == .started)
123-
handler.handle(request, id: id) { result in
124-
reply(result)
125-
}
126-
127-
return id
128-
}
129-
}

Sources/SKTestSupport/TestSourceKitLSPClient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public final class TestSourceKitLSPClient: MessageHandler {
117117
}
118118
self.notificationYielder = notificationYielder
119119

120-
let serverToClientConnection = LocalConnection()
120+
let serverToClientConnection = LocalConnection(name: "client")
121121
self.serverToClientConnection = serverToClientConnection
122122
server = SourceKitLSPServer(
123123
client: serverToClientConnection,

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,6 @@ public actor SourceKitLSPServer {
699699

700700
/// Send the given notification to the editor.
701701
public func sendNotificationToClient(_ notification: some NotificationType) {
702-
logger.log("Sending notification: \(notification.forLogging)")
703702
client.send(notification)
704703
}
705704

0 commit comments

Comments
 (0)