File: MessageHandlingDependencyTracker.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (238 lines) | stat: -rw-r--r-- 8,959 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 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 LSPLogging
import LanguageServerProtocol
import SKSupport
import SwiftExtensions

/// A lightweight way of describing tasks that are created from handling LSP
/// requests or notifications for the purpose of dependency tracking.
enum MessageHandlingDependencyTracker: DependencyTracker {
  /// A task that changes the global configuration of sourcekit-lsp in any way.
  ///
  /// No other tasks must execute simultaneously with this task since they
  /// might be relying on this task to take effect.
  case globalConfigurationChange

  /// A request that depends on the state of all documents.
  ///
  /// These requests wait for `documentUpdate` tasks for all documents to finish before being executed.
  ///
  /// Requests that only read the semantic index and are not affected by changes to the in-memory file contents should
  /// `freestanding` requests.
  case workspaceRequest

  /// Changes the contents of the document with the given URI.
  ///
  /// Any other updates or requests to this document must wait for the
  /// document update to finish before being executed
  case documentUpdate(DocumentURI)

  /// A request that concerns one document.
  ///
  /// Any updates to this document must be processed before the document
  /// request can be handled. Multiple requests to the same document can be
  /// handled simultaneously.
  case documentRequest(DocumentURI)

  /// A request that doesn't have any dependencies other than global
  /// configuration changes.
  case freestanding

  /// Whether this request needs to finish before `other` can start executing.
  func isDependency(of other: MessageHandlingDependencyTracker) -> Bool {
    switch (self, other) {
    // globalConfigurationChange
    case (.globalConfigurationChange, _): return true
    case (_, .globalConfigurationChange): return true

    // globalDocumentState
    case (.workspaceRequest, .workspaceRequest): return false
    case (.documentUpdate, .workspaceRequest): return true
    case (.workspaceRequest, .documentUpdate): return true
    case (.workspaceRequest, .documentRequest): return false
    case (.documentRequest, .workspaceRequest): return false

    // documentUpdate
    case (.documentUpdate(let selfUri), .documentUpdate(let otherUri)):
      return selfUri == otherUri
    case (.documentUpdate(let selfUri), .documentRequest(let otherUri)):
      return selfUri == otherUri
    case (.documentRequest(let selfUri), .documentUpdate(let otherUri)):
      return selfUri == otherUri

    // documentRequest
    case (.documentRequest, .documentRequest):
      return false

    // freestanding
    case (.freestanding, _):
      return false
    case (_, .freestanding):
      return false
    }
  }

  init(_ notification: any NotificationType) {
    switch notification {
    case is CancelRequestNotification:
      self = .freestanding
    case is CancelWorkDoneProgressNotification:
      self = .freestanding
    case is DidChangeConfigurationNotification:
      self = .globalConfigurationChange
    case let notification as DidChangeNotebookDocumentNotification:
      self = .documentUpdate(notification.notebookDocument.uri)
    case let notification as DidChangeTextDocumentNotification:
      self = .documentUpdate(notification.textDocument.uri)
    case is DidChangeWatchedFilesNotification:
      self = .globalConfigurationChange
    case is DidChangeWorkspaceFoldersNotification:
      self = .globalConfigurationChange
    case let notification as DidCloseNotebookDocumentNotification:
      self = .documentUpdate(notification.notebookDocument.uri)
    case let notification as DidCloseTextDocumentNotification:
      self = .documentUpdate(notification.textDocument.uri)
    case is DidCreateFilesNotification:
      self = .freestanding
    case is DidDeleteFilesNotification:
      self = .freestanding
    case let notification as DidOpenNotebookDocumentNotification:
      self = .documentUpdate(notification.notebookDocument.uri)
    case let notification as DidOpenTextDocumentNotification:
      self = .documentUpdate(notification.textDocument.uri)
    case is DidRenameFilesNotification:
      self = .freestanding
    case let notification as DidSaveNotebookDocumentNotification:
      self = .documentUpdate(notification.notebookDocument.uri)
    case let notification as DidSaveTextDocumentNotification:
      self = .documentUpdate(notification.textDocument.uri)
    case is ExitNotification:
      self = .globalConfigurationChange
    case is InitializedNotification:
      self = .globalConfigurationChange
    case is LogMessageNotification:
      self = .freestanding
    case is LogTraceNotification:
      self = .freestanding
    case is PublishDiagnosticsNotification:
      self = .freestanding
    case let notification as ReopenTextDocumentNotification:
      self = .documentUpdate(notification.textDocument.uri)
    case is SetTraceNotification:
      self = .globalConfigurationChange
    case is ShowMessageNotification:
      self = .freestanding
    case let notification as WillSaveTextDocumentNotification:
      self = .documentUpdate(notification.textDocument.uri)
    case is WorkDoneProgress:
      self = .freestanding
    default:
      logger.error(
        """
        Unknown notification \(type(of: notification)). Treating as a freestanding notification. \
        This might lead to out-of-order request handling
        """
      )
      self = .freestanding
    }
  }

  init(_ request: any RequestType) {
    switch request {
    case let request as any TextDocumentRequest: self = .documentRequest(request.textDocument.uri)
    case is ApplyEditRequest:
      self = .freestanding
    case is BarrierRequest:
      self = .globalConfigurationChange
    case is CallHierarchyIncomingCallsRequest:
      self = .freestanding
    case is CallHierarchyOutgoingCallsRequest:
      self = .freestanding
    case is CodeActionResolveRequest:
      self = .freestanding
    case is CodeLensRefreshRequest:
      self = .freestanding
    case is CodeLensResolveRequest:
      self = .freestanding
    case is CompletionItemResolveRequest:
      self = .freestanding
    case is CreateWorkDoneProgressRequest:
      self = .freestanding
    case is DiagnosticsRefreshRequest:
      self = .freestanding
    case is DocumentLinkResolveRequest:
      self = .freestanding
    case let request as ExecuteCommandRequest:
      if let uri = request.textDocument?.uri {
        self = .documentRequest(uri)
      } else {
        self = .freestanding
      }
    case is InitializeRequest:
      self = .globalConfigurationChange
    case is InlayHintRefreshRequest:
      self = .freestanding
    case is InlayHintResolveRequest:
      self = .freestanding
    case is InlineValueRefreshRequest:
      self = .freestanding
    case is PollIndexRequest:
      self = .globalConfigurationChange
    case is RenameRequest:
      // Rename might touch multiple files. Make it a global configuration change so that edits to all files that might
      // be affected have been processed.
      self = .globalConfigurationChange
    case is RegisterCapabilityRequest:
      self = .globalConfigurationChange
    case is ShowMessageRequest:
      self = .freestanding
    case is ShutdownRequest:
      self = .globalConfigurationChange
    case is TriggerReindexRequest:
      self = .globalConfigurationChange
    case is TypeHierarchySubtypesRequest:
      self = .freestanding
    case is TypeHierarchySupertypesRequest:
      self = .freestanding
    case is UnregisterCapabilityRequest:
      self = .globalConfigurationChange
    case is WillCreateFilesRequest:
      self = .freestanding
    case is WillDeleteFilesRequest:
      self = .freestanding
    case is WillRenameFilesRequest:
      self = .freestanding
    case is WorkspaceDiagnosticsRequest:
      self = .freestanding
    case is WorkspaceFoldersRequest:
      self = .freestanding
    case is WorkspaceSemanticTokensRefreshRequest:
      self = .freestanding
    case is WorkspaceSymbolResolveRequest:
      self = .freestanding
    case is WorkspaceSymbolsRequest:
      self = .freestanding
    case is WorkspaceTestsRequest:
      self = .workspaceRequest
    default:
      logger.error(
        """
        Unknown request \(type(of: request)). Treating as a freestanding request. \
        This might lead to out-of-order request handling
        """
      )
      self = .freestanding
    }
  }
}