@@ -14,6 +14,22 @@ import SwiftDiagnostics
14
14
import SwiftParser
15
15
@_spi ( RawSyntax) import SwiftSyntax
16
16
17
+ fileprivate func getTokens( between first: TokenSyntax , and second: TokenSyntax ) -> [ TokenSyntax ] {
18
+ var tokens : [ TokenSyntax ] = [ ]
19
+ var currentToken = first
20
+
21
+ while currentToken != second {
22
+ tokens. append ( currentToken)
23
+ guard let nextToken = currentToken. nextToken ( viewMode: . sourceAccurate) else {
24
+ assertionFailure ( " second Token must occur after first Token " )
25
+ return tokens
26
+ }
27
+ currentToken = nextToken
28
+ }
29
+ tokens. append ( second)
30
+ return tokens
31
+ }
32
+
17
33
fileprivate extension TokenSyntax {
18
34
/// Assuming this token is a `poundAvailableKeyword` or `poundUnavailableKeyword`
19
35
/// returns the opposite keyword.
@@ -239,7 +255,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
239
255
unexpectedTokenCondition: isOfSameKind,
240
256
correctTokens: [ specifier] ,
241
257
message: { _ in misspelledError } ,
242
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : specifier) } ,
258
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ specifier] ) } ,
243
259
removeRedundantFixIt: { RemoveRedundantFixIt ( removeTokens: $0) }
244
260
)
245
261
}
@@ -434,7 +450,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
434
450
unexpectedTokenCondition: { $0. text == " || " } ,
435
451
correctTokens: [ node. trailingComma] ,
436
452
message: { _ in . joinPlatformsUsingComma } ,
437
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : trailingComma) }
453
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ trailingComma] ) }
438
454
)
439
455
}
440
456
return . visitChildren
@@ -463,13 +479,42 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
463
479
if shouldSkip ( node) {
464
480
return . skipChildren
465
481
}
482
+ if let unexpected = node. unexpectedBetweenConditionAndTrailingComma,
483
+ let availability = node. condition. as ( AvailabilityConditionSyntax . self) ,
484
+ let ( _, falseKeyword) = unexpected. twoTokens (
485
+ firstSatisfying: { $0. tokenKind == . binaryOperator( " == " ) } ,
486
+ secondSatisfying: { $0. tokenKind == . keyword( . false ) }
487
+ )
488
+ {
489
+ // Diagnose #available used as an expression
490
+ let negatedAvailabilityKeyword = availability. availabilityKeyword. negatedAvailabilityKeyword
491
+ let negatedCoditionElement = ConditionElementSyntax (
492
+ condition: . availability( availability. with ( \. availabilityKeyword, negatedAvailabilityKeyword) ) ,
493
+ trailingComma: node. trailingComma
494
+ )
495
+ if let negatedAvailability = negatedCoditionElement. condition. as ( AvailabilityConditionSyntax . self) {
496
+ addDiagnostic (
497
+ unexpected,
498
+ AvailabilityConditionAsExpression ( availabilityToken: availability. availabilityKeyword, negatedAvailabilityToken: negatedAvailabilityKeyword) ,
499
+ fixIts: [
500
+ FixIt (
501
+ message: ReplaceTokensFixIt ( replaceTokens: getTokens ( between: availability. availabilityKeyword, and: falseKeyword) , replacements: getTokens ( between: negatedAvailability. availabilityKeyword, and: negatedAvailability. rightParen) ) ,
502
+ changes: [
503
+ . replace( oldNode: Syntax ( node) , newNode: Syntax ( negatedCoditionElement) )
504
+ ]
505
+ )
506
+ ] ,
507
+ handledNodes: [ unexpected. id]
508
+ )
509
+ }
510
+ }
466
511
if let trailingComma = node. trailingComma {
467
512
exchangeTokens (
468
513
unexpected: node. unexpectedBetweenConditionAndTrailingComma,
469
514
unexpectedTokenCondition: { $0. text == " && " } ,
470
515
correctTokens: [ node. trailingComma] ,
471
516
message: { _ in . joinConditionsUsingComma } ,
472
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : trailingComma) }
517
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ trailingComma] ) }
473
518
)
474
519
}
475
520
return . visitChildren
@@ -662,7 +707,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
662
707
. typeParameterPackEllipsis,
663
708
fixIts: [
664
709
FixIt (
665
- message: ReplaceTokensFixIt ( replaceTokens: [ unexpectedEllipsis] , replacement : . keyword( . each) ) ,
710
+ message: ReplaceTokensFixIt ( replaceTokens: [ unexpectedEllipsis] , replacements : [ . keyword( . each) ] ) ,
666
711
changes: [
667
712
. makeMissing( unexpected) ,
668
713
. makePresent( each, trailingTrivia: . space) ,
@@ -678,7 +723,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
678
723
unexpectedTokenCondition: { $0. tokenKind == . keyword( . class) } ,
679
724
correctTokens: [ inheritedTypeName] ,
680
725
message: { _ in StaticParserError . classConstraintCanOnlyBeUsedInProtocol } ,
681
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : inheritedTypeName) }
726
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ inheritedTypeName] ) }
682
727
)
683
728
}
684
729
return . visitChildren
@@ -709,7 +754,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
709
754
NegatedAvailabilityCondition ( avaialabilityCondition: availability, negatedAvailabilityKeyword: negatedAvailabilityKeyword) ,
710
755
fixIts: [
711
756
FixIt (
712
- message: ReplaceTokensFixIt ( replaceTokens: [ operatorToken, availability. availabilityKeyword] , replacement : negatedAvailabilityKeyword) ,
757
+ message: ReplaceTokensFixIt ( replaceTokens: [ operatorToken, availability. availabilityKeyword] , replacements : [ negatedAvailabilityKeyword] ) ,
713
758
changes: [
714
759
. replace( oldNode: Syntax ( conditionElement) , newNode: Syntax ( negatedCoditionElement) )
715
760
]
@@ -741,7 +786,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
741
786
StaticParserError . unexpectedPoundElseSpaceIf,
742
787
fixIts: [
743
788
FixIt (
744
- message: ReplaceTokensFixIt ( replaceTokens: unexpectedTokens, replacement : clause. poundKeyword) ,
789
+ message: ReplaceTokensFixIt ( replaceTokens: unexpectedTokens, replacements : [ clause. poundKeyword] ) ,
745
790
changes: [
746
791
. makeMissing( unexpectedBeforePoundKeyword, transferTrivia: false ) ,
747
792
. makePresent( clause. poundKeyword, leadingTrivia: unexpectedBeforePoundKeyword. leadingTrivia) ,
@@ -785,7 +830,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
785
830
. expectedAssignmentInsteadOfComparisonOperator,
786
831
fixIts: [
787
832
FixIt (
788
- message: ReplaceTokensFixIt ( replaceTokens: [ . binaryOperator( " == " ) ] , replacement : node. equal) ,
833
+ message: ReplaceTokensFixIt ( replaceTokens: [ . binaryOperator( " == " ) ] , replacements : [ node. equal] ) ,
789
834
changes: [ . makeMissing( unexpected) , . makePresent( node. equal, leadingTrivia: [ ] ) ]
790
835
)
791
836
] ,
@@ -799,7 +844,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
799
844
unexpectedTokenCondition: { $0. tokenKind == . colon } ,
800
845
correctTokens: [ node. equal] ,
801
846
message: { _ in StaticParserError . initializerInPattern } ,
802
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : node. equal) }
847
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ node. equal] ) }
803
848
)
804
849
}
805
850
return . visitChildren
@@ -1005,7 +1050,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1005
1050
}
1006
1051
if let singleQuote = node. unexpectedBetweenOpenDelimiterAndOpenQuote? . onlyToken ( where: { $0. tokenKind == . singleQuote } ) {
1007
1052
let fixIt = FixIt (
1008
- message: ReplaceTokensFixIt ( replaceTokens: [ singleQuote] , replacement : node. openQuote) ,
1053
+ message: ReplaceTokensFixIt ( replaceTokens: [ singleQuote] , replacements : [ node. openQuote] ) ,
1009
1054
changes: [
1010
1055
. makeMissing( singleQuote, transferTrivia: false ) ,
1011
1056
. makePresent( node. openQuote, leadingTrivia: singleQuote. leadingTrivia ?? [ ] ) ,
@@ -1181,7 +1226,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1181
1226
unexpectedTokenCondition: { $0. tokenKind == . colon } ,
1182
1227
correctTokens: [ node. equal] ,
1183
1228
message: { _ in MissingNodesError ( missingNodes: [ Syntax ( node. equal) ] ) } ,
1184
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : node. equal) }
1229
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ node. equal] ) }
1185
1230
)
1186
1231
}
1187
1232
return . visitChildren
0 commit comments