@@ -20,8 +20,10 @@ import SwiftExtensions
20
20
import SwiftParserDiagnostics
21
21
22
22
actor DiagnosticReportManager {
23
- /// A task to produce diagnostics, either from a diagnostics request to `sourcektid` or by using the built-in swift-syntax.
24
- private typealias ReportTask = RefCountedCancellableTask < RelatedFullDocumentDiagnosticReport >
23
+ /// A task to produce diagnostics, either from a diagnostics request to `sourcekitd` or by using the built-in swift-syntax.
24
+ private typealias ReportTask = RefCountedCancellableTask <
25
+ ( report: RelatedFullDocumentDiagnosticReport , cachable: Bool )
26
+ >
25
27
26
28
private let sourcekitd : SourceKitD
27
29
private let options : SourceKitLSPOptions
@@ -68,7 +70,14 @@ actor DiagnosticReportManager {
68
70
buildSettings: SwiftCompileCommand ?
69
71
) async throws -> RelatedFullDocumentDiagnosticReport {
70
72
if let reportTask = reportTask ( for: snapshot. id, buildSettings: buildSettings) , await !reportTask. isCancelled {
71
- return try await reportTask. value
73
+ do {
74
+ let cachedValue = try await reportTask. value
75
+ if cachedValue. cachable {
76
+ return cachedValue. report
77
+ }
78
+ } catch {
79
+ // Do not cache failed requests
80
+ }
72
81
}
73
82
let reportTask: ReportTask
74
83
if let buildSettings, !buildSettings. isFallback {
@@ -88,7 +97,7 @@ actor DiagnosticReportManager {
88
97
}
89
98
}
90
99
setReportTask ( for: snapshot. id, buildSettings: buildSettings, reportTask: reportTask)
91
- return try await reportTask. value
100
+ return try await reportTask. value. report
92
101
}
93
102
94
103
func removeItemsFromCache( with uri: DocumentURI ) async {
@@ -98,7 +107,7 @@ actor DiagnosticReportManager {
98
107
private func requestReport(
99
108
with snapshot: DocumentSnapshot ,
100
109
compilerArgs: [ String ]
101
- ) async throws -> LanguageServerProtocol . RelatedFullDocumentDiagnosticReport {
110
+ ) async throws -> ( report : RelatedFullDocumentDiagnosticReport , cachable : Bool ) {
102
111
try Task . checkCancellation ( )
103
112
104
113
let keys = self . keys
@@ -119,17 +128,23 @@ actor DiagnosticReportManager {
119
128
)
120
129
} catch SKDError . requestFailed( let sourcekitdError) {
121
130
var errorMessage = sourcekitdError
131
+ if errorMessage. contains ( " semantic editor is disabled " ) {
132
+ throw SKDError . requestFailed ( sourcekitdError)
133
+ }
122
134
if errorMessage. hasPrefix ( " error response (Request Failed): error: " ) {
123
135
errorMessage = String ( errorMessage. dropFirst ( 40 ) )
124
136
}
125
- return RelatedFullDocumentDiagnosticReport ( items: [
137
+ let report = RelatedFullDocumentDiagnosticReport ( items: [
126
138
Diagnostic (
127
139
range: Position ( line: 0 , utf16index: 0 ) ..< Position ( line: 0 , utf16index: 0 ) ,
128
140
severity: . error,
129
141
source: " SourceKit " ,
130
142
message: " Internal SourceKit error: \( errorMessage) "
131
143
)
132
144
] )
145
+ // If generating the diagnostic report failed because of a sourcekitd problem, mark as as non-cachable because
146
+ // executing the sourcekitd request again might succeed (eg. if sourcekitd has been restored after a crash).
147
+ return ( report, cachable: false )
133
148
}
134
149
135
150
try Task . checkCancellation ( )
@@ -144,12 +159,13 @@ actor DiagnosticReportManager {
144
159
)
145
160
} ) ?? [ ]
146
161
147
- return RelatedFullDocumentDiagnosticReport ( items: diagnostics)
162
+ let report = RelatedFullDocumentDiagnosticReport ( items: diagnostics)
163
+ return ( report, cachable: true )
148
164
}
149
165
150
166
private func requestFallbackReport(
151
167
with snapshot: DocumentSnapshot
152
- ) async throws -> LanguageServerProtocol . RelatedFullDocumentDiagnosticReport {
168
+ ) async throws -> ( report : RelatedFullDocumentDiagnosticReport , cachable : Bool ) {
153
169
// If we don't have build settings or we only have fallback build settings,
154
170
// sourcekitd won't be able to give us accurate semantic diagnostics.
155
171
// Fall back to providing syntactic diagnostics from the built-in
@@ -163,7 +179,8 @@ actor DiagnosticReportManager {
163
179
}
164
180
return Diagnostic ( diag, in: snapshot)
165
181
}
166
- return RelatedFullDocumentDiagnosticReport ( items: diagnostics)
182
+ let report = RelatedFullDocumentDiagnosticReport ( items: diagnostics)
183
+ return ( report, cachable: true )
167
184
}
168
185
169
186
/// The reportTask for the given document snapshot and buildSettings.
@@ -184,10 +201,10 @@ actor DiagnosticReportManager {
184
201
buildSettings: SwiftCompileCommand ? ,
185
202
reportTask: ReportTask
186
203
) {
187
- reportTaskCache. insert ( ( snapshotID, buildSettings, reportTask) , at: 0 )
188
-
189
204
// Remove any reportTasks for old versions of this document.
190
- reportTaskCache. removeAll ( where: { $0. snapshotID < snapshotID } )
205
+ reportTaskCache. removeAll ( where: { $0. snapshotID <= snapshotID } )
206
+
207
+ reportTaskCache. insert ( ( snapshotID, buildSettings, reportTask) , at: 0 )
191
208
192
209
// If we still have more than `cacheSize` reportTasks, delete the ones that
193
210
// were produced last. We can always re-request them on-demand.
0 commit comments