@@ -26,9 +26,22 @@ interface ParsedDiagnostic {
2626
2727type DiagnosticsMap = Map < string , vscode . Diagnostic [ ] > ;
2828
29+ type SourcePredicate = ( source : string ) => boolean ;
30+
31+ type DiagnosticPredicate = ( diagnostic : vscode . Diagnostic ) => boolean ;
32+
2933const isEqual = ( d1 : vscode . Diagnostic , d2 : vscode . Diagnostic ) =>
3034 d1 . range . start . isEqual ( d2 . range . start ) && d1 . message === d2 . message ;
3135
36+ const isSource = ( diagnostic : vscode . Diagnostic , sourcesPredicate : SourcePredicate ) =>
37+ sourcesPredicate ( diagnostic . source ?? "" ) ;
38+
39+ const isSwiftc : DiagnosticPredicate = diagnostic =>
40+ isSource ( diagnostic , DiagnosticsManager . isSwiftc ) ;
41+
42+ const isSourceKit : DiagnosticPredicate = diagnostic =>
43+ isSource ( diagnostic , DiagnosticsManager . isSourcekit ) ;
44+
3245/**
3346 * Handles the collection and deduplication of diagnostics from
3447 * various {@link vscode.Diagnostic.source | Diagnostic sources}.
@@ -38,9 +51,9 @@ const isEqual = (d1: vscode.Diagnostic, d2: vscode.Diagnostic) =>
3851 * thier own diagnostics.
3952 */
4053export class DiagnosticsManager implements vscode . Disposable {
41- // Prior to Swift 6 "sourcekitd" was the source
42- static sourcekit : string [ ] = [ "SourceKit" , "sourcekitd" ] ;
43- static swiftc : string [ ] = [ " swiftc" ] ;
54+ private static swiftc : string = "swiftc" ;
55+ static isSourcekit : SourcePredicate = source => this . swiftc !== source ;
56+ static isSwiftc : SourcePredicate = source => this . swiftc === source ;
4457
4558 private diagnosticCollection : vscode . DiagnosticCollection =
4659 vscode . languages . createDiagnosticCollection ( "swift" ) ;
@@ -57,15 +70,15 @@ export class DiagnosticsManager implements vscode.Disposable {
5770 } ) ;
5871 this . onDidStartTaskDisposible = vscode . tasks . onDidStartTask ( event => {
5972 // Will only try to provide diagnostics for `swift` tasks
60- const execution = event . execution . task . execution ;
61- if ( ! ( execution && execution instanceof SwiftExecution ) ) {
73+ const task = event . execution . task ;
74+ if ( task . definition . type !== "swift" ) {
6275 return ;
6376 }
6477 if ( ! this . includeSwiftcDiagnostics ( ) ) {
6578 return ;
6679 }
6780 // Provide new list of diagnostics
68- const swiftExecution = execution as SwiftExecution ;
81+ const swiftExecution = task . execution as SwiftExecution ;
6982 const provideDiagnostics : Promise < DiagnosticsMap > =
7083 this . parseDiagnostics ( swiftExecution ) ;
7184
@@ -76,7 +89,7 @@ export class DiagnosticsManager implements vscode.Disposable {
7689 map . forEach ( ( diagnostics , uri ) =>
7790 this . handleDiagnostics (
7891 vscode . Uri . file ( uri ) ,
79- DiagnosticsManager . swiftc ,
92+ DiagnosticsManager . isSwiftc ,
8093 diagnostics
8194 )
8295 ) ;
@@ -91,25 +104,25 @@ export class DiagnosticsManager implements vscode.Disposable {
91104 * Provide a new list of diagnostics for a given file
92105 *
93106 * @param uri {@link vscode.Uri Uri } of the file these diagonstics apply to
94- * @param sources The source of the diagnostics which will apply for cleaning
95- * up diagnostics that have been removed. See {@link swiftc } and {@link sourcekit }
96- * @param newDiagnostics Array of {@link vscode.Diagnostic}. This can be empty to remove old diagnostics for the specified `sources `.
107+ * @param sourcePredicate Diagnostics of a source that satisfies the predicate will apply for cleaning
108+ * up diagnostics that have been removed. See {@link isSwiftc } and {@link isSourceKit }
109+ * @param newDiagnostics Array of {@link vscode.Diagnostic}. This can be empty to remove old diagnostics satisfying `sourcePredicate `.
97110 */
98111 handleDiagnostics (
99112 uri : vscode . Uri ,
100- sources : string [ ] ,
113+ sourcePredicate : SourcePredicate ,
101114 newDiagnostics : vscode . Diagnostic [ ]
102115 ) : void {
103- const isFromSourceKit = ! ! DiagnosticsManager . sourcekit . find ( s => sources . includes ( s ) ) ;
116+ const isFromSourceKit = ! sourcePredicate ( DiagnosticsManager . swiftc ) ;
104117 // Is a descrepency between SourceKit-LSP and older versions
105118 // of Swift as to whether the first letter is capitalized or not,
106119 // so we'll always display messages capitalized to user and this
107120 // also will allow comparing messages when merging
108- newDiagnostics = newDiagnostics . map ( this . capitalizeMessage ) ;
121+ newDiagnostics = newDiagnostics . map ( this . capitalizeMessage ) . map ( this . cleanMessage ) ;
109122 const allDiagnostics = this . allDiagnostics . get ( uri . fsPath ) ?. slice ( ) || [ ] ;
110123 // Remove the old set of diagnostics from this source
111124 const removedDiagnostics = this . removeDiagnostics ( allDiagnostics , d =>
112- this . isSource ( d , sources )
125+ isSource ( d , sourcePredicate )
113126 ) ;
114127 // Clean up any "fixed" swiftc diagnostics
115128 if ( isFromSourceKit ) {
@@ -119,7 +132,7 @@ export class DiagnosticsManager implements vscode.Disposable {
119132 ) ;
120133 this . removeDiagnostics (
121134 allDiagnostics ,
122- d1 => this . isSwiftc ( d1 ) && ! ! removedDiagnostics . find ( d2 => isEqual ( d1 , d2 ) )
135+ d1 => isSwiftc ( d1 ) && ! ! removedDiagnostics . find ( d2 => isEqual ( d1 , d2 ) )
123136 ) ;
124137 }
125138 // Append the new diagnostics we just received
@@ -131,25 +144,17 @@ export class DiagnosticsManager implements vscode.Disposable {
131144
132145 private updateDiagnosticsCollection ( uri : vscode . Uri ) : void {
133146 const diagnostics = this . allDiagnostics . get ( uri . fsPath ) ?? [ ] ;
134- const swiftcDiagnostics = diagnostics . filter ( d => this . isSwiftc ( d ) ) ;
135- const sourceKitDiagnostics = diagnostics . filter ( d => this . isSourceKit ( d ) ) ;
147+ const swiftcDiagnostics = diagnostics . filter ( isSwiftc ) ;
148+ const sourceKitDiagnostics = diagnostics . filter ( isSourceKit ) ;
136149 const mergedDiagnostics : vscode . Diagnostic [ ] = [ ] ;
137150 switch ( configuration . diagnosticsCollection ) {
138151 case "keepSourceKit" :
139152 mergedDiagnostics . push ( ...swiftcDiagnostics ) ;
140- this . mergeDiagnostics (
141- mergedDiagnostics ,
142- sourceKitDiagnostics ,
143- DiagnosticsManager . sourcekit
144- ) ;
153+ this . mergeDiagnostics ( mergedDiagnostics , sourceKitDiagnostics , isSourceKit ) ;
145154 break ;
146155 case "keepSwiftc" :
147156 mergedDiagnostics . push ( ...sourceKitDiagnostics ) ;
148- this . mergeDiagnostics (
149- mergedDiagnostics ,
150- swiftcDiagnostics ,
151- DiagnosticsManager . swiftc
152- ) ;
157+ this . mergeDiagnostics ( mergedDiagnostics , swiftcDiagnostics , isSwiftc ) ;
153158 break ;
154159 case "onlySourceKit" :
155160 mergedDiagnostics . push ( ...sourceKitDiagnostics ) ;
@@ -168,7 +173,7 @@ export class DiagnosticsManager implements vscode.Disposable {
168173 private mergeDiagnostics (
169174 mergedDiagnostics : vscode . Diagnostic [ ] ,
170175 newDiagnostics : vscode . Diagnostic [ ] ,
171- precedence : string [ ]
176+ precedencePredicate : DiagnosticPredicate
172177 ) : void {
173178 for ( const diagnostic of newDiagnostics ) {
174179 // See if a duplicate diagnostic exists
@@ -178,11 +183,11 @@ export class DiagnosticsManager implements vscode.Disposable {
178183 }
179184
180185 // Perform de-duplication
181- if ( precedence . includes ( diagnostic . source || "" ) ) {
186+ if ( precedencePredicate ( diagnostic ) ) {
182187 mergedDiagnostics . push ( diagnostic ) ;
183188 continue ;
184189 }
185- if ( ! currentDiagnostic || ! precedence . includes ( currentDiagnostic . source || "" ) ) {
190+ if ( ! currentDiagnostic || ! precedencePredicate ( currentDiagnostic ) ) {
186191 mergedDiagnostics . push ( diagnostic ) ;
187192 continue ;
188193 }
@@ -193,29 +198,17 @@ export class DiagnosticsManager implements vscode.Disposable {
193198 private removeSwiftcDiagnostics ( ) {
194199 this . allDiagnostics . forEach ( ( diagnostics , path ) => {
195200 const newDiagnostics = diagnostics . slice ( ) ;
196- this . removeDiagnostics ( newDiagnostics , d => this . isSwiftc ( d ) ) ;
201+ this . removeDiagnostics ( newDiagnostics , isSwiftc ) ;
197202 if ( diagnostics . length !== newDiagnostics . length ) {
198203 this . allDiagnostics . set ( path , newDiagnostics ) ;
199204 }
200205 this . updateDiagnosticsCollection ( vscode . Uri . file ( path ) ) ;
201206 } ) ;
202207 }
203208
204- private isSource ( diagnostic : vscode . Diagnostic , sources : string [ ] ) : boolean {
205- return sources . includes ( diagnostic . source || "" ) ;
206- }
207-
208- private isSwiftc ( diagnostic : vscode . Diagnostic ) : boolean {
209- return this . isSource ( diagnostic , DiagnosticsManager . swiftc ) ;
210- }
211-
212- private isSourceKit ( diagnostic : vscode . Diagnostic ) : boolean {
213- return this . isSource ( diagnostic , DiagnosticsManager . sourcekit ) ;
214- }
215-
216209 private removeDiagnostics (
217210 diagnostics : vscode . Diagnostic [ ] ,
218- matches : ( d : vscode . Diagnostic ) => boolean
211+ matches : DiagnosticPredicate
219212 ) : vscode . Diagnostic [ ] {
220213 const removed : vscode . Diagnostic [ ] = [ ] ;
221214 let i = diagnostics . length ;
@@ -323,13 +316,13 @@ export class DiagnosticsManager implements vscode.Disposable {
323316 private parseDiagnostic (
324317 line : string
325318 ) : ParsedDiagnostic | vscode . DiagnosticRelatedInformation | undefined {
326- const diagnosticRegex = / ^ ( .* ?) : ( \d + ) (?: : ( \d + ) ) ? : \s + ( w a r n i n g | e r r o r | n o t e ) : \s + ( . * ) $ / g;
319+ const diagnosticRegex = / ^ ( .* ?) : ( \d + ) (?: : ( \d + ) ) ? : \s + ( w a r n i n g | e r r o r | n o t e ) : \s + ( [ ^ \\ [ ] * ) / g;
327320 const match = diagnosticRegex . exec ( line ) ;
328321 if ( ! match ) {
329322 return ;
330323 }
331324 const uri = match [ 1 ] ;
332- const message = this . capitalize ( match [ 5 ] ) ;
325+ const message = this . capitalize ( match [ 5 ] ) . trim ( ) ;
333326 const range = this . range ( match [ 2 ] , match [ 3 ] ) ;
334327 const severity = this . severity ( match [ 4 ] ) ;
335328 if ( severity === vscode . DiagnosticSeverity . Information ) {
@@ -339,7 +332,7 @@ export class DiagnosticsManager implements vscode.Disposable {
339332 ) ;
340333 }
341334 const diagnostic = new vscode . Diagnostic ( range , message , severity ) ;
342- diagnostic . source = DiagnosticsManager . swiftc [ 0 ] ;
335+ diagnostic . source = DiagnosticsManager . swiftc ;
343336 return { uri, diagnostic } ;
344337 }
345338
@@ -377,6 +370,12 @@ export class DiagnosticsManager implements vscode.Disposable {
377370 return diagnostic ;
378371 } ;
379372
373+ private cleanMessage = ( diagnostic : vscode . Diagnostic ) => {
374+ diagnostic = { ...diagnostic } ;
375+ diagnostic . message = diagnostic . message . replace ( "(fix available)" , "" ) . trim ( ) ;
376+ return diagnostic ;
377+ } ;
378+
380379 private onDidStartTaskDisposible : vscode . Disposable ;
381380 private onDidChangeConfigurationDisposible : vscode . Disposable ;
382381}
0 commit comments