Skip to content

Merge main into release/6.0 #1324

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 59 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
d826569
Update README.md
yaroslavyaroslav Apr 18, 2024
18b7c32
Review fixes
yaroslavyaroslav Apr 18, 2024
63fe6c1
Update README.md
yaroslavyaroslav Apr 20, 2024
4d06e65
Update README.md
yaroslavyaroslav Apr 21, 2024
87f9aa4
Update README.md
yaroslavyaroslav Apr 21, 2024
19d1893
Update README.md
yaroslavyaroslav Apr 21, 2024
8e7df19
Update README.md
yaroslavyaroslav Apr 23, 2024
491103d
Update README.md
yaroslavyaroslav Apr 23, 2024
78f6132
Add code actions for adding library/executable/macro targets to a pac…
DougGregor May 8, 2024
f8407b9
Make DiagnoseTests build in Swift 6 mode
ahoppen May 14, 2024
b442195
Make ConnectionTests build in Swift 6 mode
ahoppen May 14, 2024
267b1cd
Make `LanguageServerProtocolJSONRPCTests` build in Swift 6 mode
ahoppen May 14, 2024
ee79512
Make `LSPTestSupport` build in Swift 6 mode
ahoppen May 14, 2024
c09b47f
Make `SKCoreTests` build in Swift 6 mode
ahoppen May 14, 2024
66ecdd3
Make `SKSwiftPMWorkspaceTests` build in Swift 6 mode
ahoppen May 14, 2024
fae712b
Make `SKTestSupport` build in Swift 6 mode
ahoppen May 14, 2024
0b01ede
Make `SourceKitDTests` build in Swift 6 mode
ahoppen May 14, 2024
2270128
Make `SourceKitLSPTests` build in Swift 6 mode
ahoppen May 14, 2024
387ce43
Merge pull request #1294 from ahoppen/build-tests-in-swift-6-mode
ahoppen May 15, 2024
546bb32
Update index as files are modified on disk
ahoppen May 15, 2024
f10eac3
Address review comment to #1216
ahoppen May 15, 2024
0e0f6d3
Merge pull request #1184 from yaroslavyaroslav/patch-2
ahoppen May 15, 2024
b30b972
Merge pull request #1302 from ahoppen/watch-file-changes-index
ahoppen May 15, 2024
597932c
Merge pull request #1303 from ahoppen/review-comments-1216
ahoppen May 15, 2024
c58fa70
Don’t re-index all files that include a header when a header is modified
ahoppen May 16, 2024
012a64f
Merge pull request #1306 from ahoppen/dont-re-index-all-main-files
ahoppen May 16, 2024
61b7720
Track which targets are up-to-date and avoid preparation of targets t…
ahoppen May 16, 2024
7208376
When interacting with a document, prepare the target it belongs to
ahoppen May 16, 2024
490871b
Merge pull request #1307 from ahoppen/background-prepare-targets
ahoppen May 16, 2024
0600809
Address review comments to #1306
ahoppen May 16, 2024
c1073a4
Don't re-prepare a target if there is already a smaller preparation t…
ahoppen May 16, 2024
b30f595
Add folding operator for `IfConfigClauseSyntax`
kimdv May 13, 2024
372673f
Address review comments to #1249
ahoppen May 16, 2024
bcea952
Merge pull request #1287 from kimdv/kimdv/1182-conditional-compile-di…
ahoppen May 17, 2024
195d3af
Move `LocalConnection` to `LSPTestSupport`
ahoppen May 17, 2024
068b6df
Fix non-deterministic test failure in `BackgroundIndexingTests.testPr…
ahoppen May 17, 2024
56640c1
Address review comments to #1302
ahoppen May 17, 2024
5bad2c5
Generalize the removal of compiler argument options during indexing
ahoppen May 17, 2024
a850cb6
When a file is changed, only mark targets that depend on it as out-of…
ahoppen May 16, 2024
5a7ab33
Merge pull request #1310 from ahoppen/review-comments-1249
ahoppen May 17, 2024
c2af2f5
Merge pull request #1240 from DougGregor/code-action-add-target
DougGregor May 17, 2024
fb0801a
Merge pull request #1311 from ahoppen/review-comments-1307
ahoppen May 17, 2024
6695859
Improve handling of main file vs header file during indexing
ahoppen May 16, 2024
6a132ad
Remove status logging from `TaskScheduler`
ahoppen May 17, 2024
c01c676
Extract tuple from `SemanticIndexManager.preparationStatus` into a st…
ahoppen May 17, 2024
2d27d57
Extract `indexTaskDidFinish` in `SourceKitLSPServer.Options` into a `…
ahoppen May 17, 2024
9524753
Introduce test hooks that can be used to monitor when preparation and…
ahoppen May 17, 2024
79d50f3
Merge pull request #1319 from ahoppen/remove-taskscheduler-logging
ahoppen May 20, 2024
0ce2107
Merge pull request #1317 from ahoppen/prepare-target-test-failure
ahoppen May 20, 2024
fcc527f
Merge pull request #1318 from ahoppen/log-in-localconnection
ahoppen May 20, 2024
5e8197c
Merge pull request #1316 from ahoppen/review-comments-1302
ahoppen May 20, 2024
815fea8
Add infrastructure to test which targets are being prepared
ahoppen May 18, 2024
0da0527
Merge pull request #1314 from ahoppen/command-line-sanitization
ahoppen May 20, 2024
af6cdeb
Merge pull request #1313 from ahoppen/only-mark-dependent-targets-as-…
ahoppen May 20, 2024
3f9ff29
Merge pull request #1309 from ahoppen/review-comments-1306
ahoppen May 20, 2024
d12c946
Merge pull request #1321 from ahoppen/target-preparation-testing
ahoppen May 21, 2024
e295a4e
Split up-to-date status tracking and index progress tracking
ahoppen May 21, 2024
0e58ab1
Merge pull request #1322 from ahoppen/split-status-and-progress-tracking
atrick May 21, 2024
9a06737
Merge branch 'main' into 6.0/merge-main-2024-05-21
ahoppen May 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ default.profraw
Package.resolved
/.build
/.index-build
/.linux-build
/Packages
/*.xcodeproj
/*.sublime-project
Expand Down
35 changes: 35 additions & 0 deletions Documentation/Files_To_Reindex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Which files to re-index when a file is modified

## `.swift`

Obviously affects the file itself, which we do re-index.

If an internal declaration was changed, all files within the module might be also affected. If a public declaration was changed, all modules that depend on it might be affected. The effect can only really be in three ways:
1. It might change overload resolution in another file, which is fairly unlikely
2. A new declaration is introduced in this file that is already referenced by another file
3. A declaration is removed in this file that was referenced from other files. In those cases the other files now have an invalid reference.

We decided to not re-index any files other than the file itself because naively re-indexing all files that might depend on the modified file requires too much processing power that will likely have no or very little effect on the index – we are trading accuracy for CPU time here.
We mark the targets of the changed file as well as any dependent targets as out-of-date. The assumption is that most likely the user will go back to any of the affected files shortly afterwards and modify them again. When that happens, the affected file will get re-indexed and bring the index back up to date.

Alternatives would be:
- We could we check the file’s interface hash and re-index other files based on whether it has changed. But at that point we are somewhat implementing a build system. And even if a new public method was introduced it’s very likely that the user hasn’t actually used it anywhere yet, which means that re-indexing all dependent modules would still be doing unnecessary work.
- To cover case (2) from above, we could re-index only dependencies that previously indexed with errors. This is an alternative that hasn’t been fully explored.

## `.h`

All files that include the header (including via other headers) might be affected by the change, similar to how all `.swift` files that import a module might be affected. Similar to modules, we choose to not re-index all files that include the header because of the same considerations mentioned above.

To re-index the header, we pick one main file that includes the header and re-index that, which will effectively update the index for the header. For existing headers, we know which files import a header from the existing index. For new header files, we assume that it hasn’t been included in any file yet and thus don't index it. If the user wrote an include to the new header before creating the header itself, we don't know about that include from the existing index. But it’s likely that the user will modify the file that includes the new header file shortly after, which will index the header and establish the header to main file connection.

## `.c` / `.cpp` / `.m`

This is the easy case since only the file itself is affected.

## Compiler settings (`compile_commands.json` / `Package.swift`)

Ideally, we would like to consider a file as changed when its compile commands have changed, if they changed in a meaningful way (ie. in a way that would also trigger re-compilation in an incremental build). Non-meaningful changes would be:
- If compiler arguments that aren't order dependent are shuffled around. We could have a really quick check for compiler arguments equality by comparing them unordered. Any real compiler argument change will most likely do more than rearranging the arguments.
- The addition of a new Swift file to a target is equivalent to that file being modified and shouldn’t trigger a re-index of the entire target.

At the moment, unit files don’t include information about the compiler arguments with which they were created, so it’s impossible to know whether the compiler arguments have changed when a project is opened. Thus, for now, we don’t re-index any files on compiler settings changing.
53 changes: 1 addition & 52 deletions Editors/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,58 +22,7 @@ The [Swift for Visual Studio Code extension](https://marketplace.visualstudio.co

## Sublime Text

Before using SourceKit-LSP with Sublime Text, you will need to install the LSP package from Package Control. To configure SourceKit-LSP, open the LSP package's settings. The following snippet should be enough to get started with Swift.

You will need the path to the `sourcekit-lsp` executable for the "command" section.

```json
{
"clients":
{
"SourceKit-LSP":
{
"enabled": true,
"command": [
"<sourcekit-lsp command>"
],
"env": {
// To override the toolchain, uncomment the following:
// "SOURCEKIT_TOOLCHAIN_PATH": "<path to toolchain>",
},
"languages": [
{
"scopes": ["source.swift"],
"syntaxes": [
"Packages/Swift/Syntaxes/Swift.tmLanguage",
"Packages/Decent Swift Syntax/Swift.sublime-syntax",
],
"languageId": "swift"
},
{
"scopes": ["source.c"],
"syntaxes": ["Packages/C++/C.sublime-syntax"],
"languageId": "c"
},
{
"scopes": ["source.c++"],
"syntaxes": ["Packages/C++/C++.sublime-syntax"],
"languageId": "cpp"
},
{
"scopes": ["source.objc"],
"syntaxes": ["Packages/Objective-C/Objective-C.sublime-syntax"],
"languageId": "objective-c"
},
{
"scopes": ["source.objc++"],
"syntaxes": ["Packages/Objective-C/Objective-C++.sublime-syntax"],
"languageId": "objective-cpp"
},
]
}
}
}
```
Before using SourceKit-LSP with Sublime Text, you will need to install the [LSP](https://packagecontrol.io/packages/LSP), [LSP-SourceKit](https://github.com/sublimelsp/LSP-SourceKit) and [Swift-Next](https://github.com/Swift-Next/Swift-Next) packages from Package Control. Then toggle the server on by typing in command palette `LSP: Enable Language Server Globally` or `LSP: Enable Language Server in Project`.

## Emacs

Expand Down
7 changes: 7 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,13 @@ let package = Package(
exclude: ["CMakeLists.txt"]
),

.testTarget(
name: "SemanticIndexTests",
dependencies: [
"SemanticIndex"
]
),

// MARK: SKCore
// Data structures and algorithms useful across the project, but not necessarily
// suitable for use in other packages.
Expand Down
11 changes: 11 additions & 0 deletions Sources/LSPLogging/NonDarwinLogging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,17 @@ public struct NonDarwinLogInterpolation: StringInterpolationProtocol, Sendable {
append(description: message.description, redactedDescription: message.redactedDescription, privacy: privacy)
}

public mutating func appendInterpolation(
_ message: (some CustomLogStringConvertibleWrapper & Sendable)?,
privacy: NonDarwinLogPrivacy = .private
) {
if let message {
self.appendInterpolation(message, privacy: privacy)
} else {
self.appendLiteral("<nil>")
}
}

public mutating func appendInterpolation(_ type: Any.Type, privacy: NonDarwinLogPrivacy = .public) {
append(description: String(reflecting: type), redactedDescription: "<private>", privacy: privacy)
}
Expand Down
133 changes: 133 additions & 0 deletions Sources/LSPTestSupport/LocalConnection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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
//
//===----------------------------------------------------------------------===//

import Dispatch
import LSPLogging
import LanguageServerProtocol

/// A connection between two message handlers in the same process.
///
/// You must call `start(handler:)` before sending any messages, and must call `close()` when finished to avoid a memory leak.
///
/// ```
/// let client: MessageHandler = ...
/// let server: MessageHandler = ...
/// let conn = LocalConnection()
/// conn.start(handler: server)
/// conn.send(...) // handled by server
/// conn.close()
/// ```
///
/// - Note: Unchecked sendable conformance because shared state is guarded by `queue`.
public final class LocalConnection: Connection, @unchecked Sendable {
enum State {
case ready, started, closed
}

/// A name of the endpoint for this connection, used for logging, e.g. `clangd`.
private let name: String

/// The queue guarding `_nextRequestID`.
let queue: DispatchQueue = DispatchQueue(label: "local-connection-queue")

var _nextRequestID: Int = 0

var state: State = .ready

var handler: MessageHandler? = nil

public init(name: String) {
self.name = name
}

deinit {
if state != .closed {
close()
}
}

public func start(handler: MessageHandler) {
precondition(state == .ready)
state = .started
self.handler = handler
}

public func close() {
precondition(state != .closed)
handler = nil
state = .closed
}

func nextRequestID() -> RequestID {
return queue.sync {
_nextRequestID += 1
return .number(_nextRequestID)
}
}

public func send<Notification: NotificationType>(_ notification: Notification) {
logger.info(
"""
Sending notification to \(self.name, privacy: .public)
\(notification.forLogging)
"""
)
self.handler?.handle(notification)
}

public func send<Request: RequestType>(
_ request: Request,
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
) -> RequestID {
let id = nextRequestID()

logger.info(
"""
Sending request to \(self.name, privacy: .public) (id: \(id, privacy: .public)):
\(request.forLogging)
"""
)

guard let handler = self.handler else {
logger.info(
"""
Replying to request \(id, privacy: .public) with .serverCancelled because no handler is specified in \(self.name, privacy: .public)
"""
)
reply(.failure(.serverCancelled))
return id
}

precondition(self.state == .started)
handler.handle(request, id: id) { result in
switch result {
case .success(let response):
logger.info(
"""
Received reply for request \(id, privacy: .public) from \(self.name, privacy: .public)
\(response.forLogging)
"""
)
case .failure(let error):
logger.error(
"""
Received error for request \(id, privacy: .public) from \(self.name, privacy: .public)
\(error.forLogging)
"""
)
}
reply(result)
}

return id
}
}
8 changes: 4 additions & 4 deletions Sources/LSPTestSupport/TestJSONRPCConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import XCTest

import class Foundation.Pipe

public final class TestJSONRPCConnection {
public final class TestJSONRPCConnection: Sendable {
public let clientToServer: Pipe = Pipe()
public let serverToClient: Pipe = Pipe()

Expand Down Expand Up @@ -76,9 +76,9 @@ public final class TestJSONRPCConnection {

public struct TestLocalConnection {
public let client: TestClient
public let clientConnection: LocalConnection = LocalConnection()
public let clientConnection: LocalConnection = LocalConnection(name: "Test")
public let server: TestServer
public let serverConnection: LocalConnection = LocalConnection()
public let serverConnection: LocalConnection = LocalConnection(name: "Test")

public init(allowUnexpectedNotification: Bool = true) {
client = TestClient(connectionToServer: serverConnection, allowUnexpectedNotification: allowUnexpectedNotification)
Expand Down Expand Up @@ -151,7 +151,7 @@ public actor TestClient: MessageHandler {
/// Send a request to the LSP server and (asynchronously) receive a reply.
public nonisolated func send<Request: RequestType>(
_ request: Request,
reply: @escaping (LSPResult<Request.Response>) -> Void
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
) -> RequestID {
return connectionToServer.send(request, reply: reply)
}
Expand Down
82 changes: 0 additions & 82 deletions Sources/LanguageServerProtocol/Connection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
//
//===----------------------------------------------------------------------===//

import Dispatch

/// An abstract connection, allow messages to be sent to a (potentially remote) `MessageHandler`.
public protocol Connection: AnyObject, Sendable {

Expand Down Expand Up @@ -47,83 +45,3 @@ public protocol MessageHandler: AnyObject, Sendable {
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
)
}

/// A connection between two message handlers in the same process.
///
/// You must call `start(handler:)` before sending any messages, and must call `close()` when finished to avoid a memory leak.
///
/// ```
/// let client: MessageHandler = ...
/// let server: MessageHandler = ...
/// let conn = LocalConnection()
/// conn.start(handler: server)
/// conn.send(...) // handled by server
/// conn.close()
/// ```
///
/// - Note: Unchecked sendable conformance because shared state is guarded by `queue`.
public final class LocalConnection: Connection, @unchecked Sendable {

enum State {
case ready, started, closed
}

/// The queue guarding `_nextRequestID`.
let queue: DispatchQueue = DispatchQueue(label: "local-connection-queue")

var _nextRequestID: Int = 0

var state: State = .ready

var handler: MessageHandler? = nil

public init() {}

deinit {
if state != .closed {
close()
}
}

public func start(handler: MessageHandler) {
precondition(state == .ready)
state = .started
self.handler = handler
}

public func close() {
precondition(state != .closed)
handler = nil
state = .closed
}

func nextRequestID() -> RequestID {
return queue.sync {
_nextRequestID += 1
return .number(_nextRequestID)
}
}

public func send<Notification>(_ notification: Notification) where Notification: NotificationType {
self.handler?.handle(notification)
}

public func send<Request: RequestType>(
_ request: Request,
reply: @Sendable @escaping (LSPResult<Request.Response>) -> Void
) -> RequestID {
let id = nextRequestID()

guard let handler = self.handler else {
reply(.failure(.serverCancelled))
return id
}

precondition(self.state == .started)
handler.handle(request, id: id) { result in
reply(result)
}

return id
}
}
Loading