@@ -14,6 +14,17 @@ 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
+ while currentToken != second {
21
+ tokens. append ( currentToken)
22
+ currentToken = currentToken. nextToken ?? second
23
+ }
24
+ tokens. append ( second)
25
+ return tokens
26
+ }
27
+
17
28
fileprivate extension TokenSyntax {
18
29
/// Assuming this token is a `poundAvailableKeyword` or `poundUnavailableKeyword`
19
30
/// returns the opposite keyword.
@@ -239,7 +250,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
239
250
unexpectedTokenCondition: isOfSameKind,
240
251
correctTokens: [ specifier] ,
241
252
message: { _ in misspelledError } ,
242
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : specifier) } ,
253
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ specifier] ) } ,
243
254
removeRedundantFixIt: { RemoveRedundantFixIt ( removeTokens: $0) }
244
255
)
245
256
}
@@ -434,7 +445,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
434
445
unexpectedTokenCondition: { $0. text == " || " } ,
435
446
correctTokens: [ node. trailingComma] ,
436
447
message: { _ in . joinPlatformsUsingComma } ,
437
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : trailingComma) }
448
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ trailingComma] ) }
438
449
)
439
450
}
440
451
return . visitChildren
@@ -463,13 +474,42 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
463
474
if shouldSkip ( node) {
464
475
return . skipChildren
465
476
}
477
+ if let unexpected = node. unexpectedBetweenConditionAndTrailingComma,
478
+ let availability = node. condition. as ( AvailabilityConditionSyntax . self) ,
479
+ let ( _, falseKeyword) = unexpected. twoTokens (
480
+ firstSatisfying: { $0. tokenKind == . binaryOperator( " == " ) } ,
481
+ secondSatisfying: { $0. tokenKind == . keyword( . false ) }
482
+ )
483
+ {
484
+ // Diagnose #available used as an expression
485
+ let negatedAvailabilityKeyword = availability. availabilityKeyword. negatedAvailabilityKeyword
486
+ let negatedCoditionElement = ConditionElementSyntax (
487
+ condition: . availability( availability. with ( \. availabilityKeyword, negatedAvailabilityKeyword) ) ,
488
+ trailingComma: node. trailingComma
489
+ )
490
+ if let negatedAvailability = negatedCoditionElement. condition. as ( AvailabilityConditionSyntax . self) {
491
+ addDiagnostic (
492
+ unexpected,
493
+ AvailabilityConditionAsExpression ( availabilityToken: availability. availabilityKeyword, negatedAvailabilityToken: negatedAvailabilityKeyword) ,
494
+ fixIts: [
495
+ FixIt (
496
+ message: ReplaceTokensFixIt ( replaceTokens: getTokens ( between: availability. availabilityKeyword, and: falseKeyword) , replacements: getTokens ( between: negatedAvailability. availabilityKeyword, and: negatedAvailability. rightParen) ) ,
497
+ changes: [
498
+ . replace( oldNode: Syntax ( node) , newNode: Syntax ( negatedCoditionElement) )
499
+ ]
500
+ )
501
+ ] ,
502
+ handledNodes: [ unexpected. id]
503
+ )
504
+ }
505
+ }
466
506
if let trailingComma = node. trailingComma {
467
507
exchangeTokens (
468
508
unexpected: node. unexpectedBetweenConditionAndTrailingComma,
469
509
unexpectedTokenCondition: { $0. text == " && " } ,
470
510
correctTokens: [ node. trailingComma] ,
471
511
message: { _ in . joinConditionsUsingComma } ,
472
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : trailingComma) }
512
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ trailingComma] ) }
473
513
)
474
514
}
475
515
return . visitChildren
@@ -662,7 +702,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
662
702
. typeParameterPackEllipsis,
663
703
fixIts: [
664
704
FixIt (
665
- message: ReplaceTokensFixIt ( replaceTokens: [ unexpectedEllipsis] , replacement : . keyword( . each) ) ,
705
+ message: ReplaceTokensFixIt ( replaceTokens: [ unexpectedEllipsis] , replacements : [ . keyword( . each) ] ) ,
666
706
changes: [
667
707
. makeMissing( unexpected) ,
668
708
. makePresent( each, trailingTrivia: . space) ,
@@ -678,7 +718,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
678
718
unexpectedTokenCondition: { $0. tokenKind == . keyword( . class) } ,
679
719
correctTokens: [ inheritedTypeName] ,
680
720
message: { _ in StaticParserError . classConstraintCanOnlyBeUsedInProtocol } ,
681
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : inheritedTypeName) }
721
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ inheritedTypeName] ) }
682
722
)
683
723
}
684
724
return . visitChildren
@@ -709,7 +749,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
709
749
NegatedAvailabilityCondition ( avaialabilityCondition: availability, negatedAvailabilityKeyword: negatedAvailabilityKeyword) ,
710
750
fixIts: [
711
751
FixIt (
712
- message: ReplaceTokensFixIt ( replaceTokens: [ operatorToken, availability. availabilityKeyword] , replacement : negatedAvailabilityKeyword) ,
752
+ message: ReplaceTokensFixIt ( replaceTokens: [ operatorToken, availability. availabilityKeyword] , replacements : [ negatedAvailabilityKeyword] ) ,
713
753
changes: [
714
754
. replace( oldNode: Syntax ( conditionElement) , newNode: Syntax ( negatedCoditionElement) )
715
755
]
@@ -741,7 +781,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
741
781
StaticParserError . unexpectedPoundElseSpaceIf,
742
782
fixIts: [
743
783
FixIt (
744
- message: ReplaceTokensFixIt ( replaceTokens: unexpectedTokens, replacement : clause. poundKeyword) ,
784
+ message: ReplaceTokensFixIt ( replaceTokens: unexpectedTokens, replacements : [ clause. poundKeyword] ) ,
745
785
changes: [
746
786
. makeMissing( unexpectedBeforePoundKeyword, transferTrivia: false ) ,
747
787
. makePresent( clause. poundKeyword, leadingTrivia: unexpectedBeforePoundKeyword. leadingTrivia) ,
@@ -785,7 +825,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
785
825
. expectedAssignmentInsteadOfComparisonOperator,
786
826
fixIts: [
787
827
FixIt (
788
- message: ReplaceTokensFixIt ( replaceTokens: [ . binaryOperator( " == " ) ] , replacement : node. equal) ,
828
+ message: ReplaceTokensFixIt ( replaceTokens: [ . binaryOperator( " == " ) ] , replacements : [ node. equal] ) ,
789
829
changes: [ . makeMissing( unexpected) , . makePresent( node. equal, leadingTrivia: [ ] ) ]
790
830
)
791
831
] ,
@@ -799,7 +839,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
799
839
unexpectedTokenCondition: { $0. tokenKind == . colon } ,
800
840
correctTokens: [ node. equal] ,
801
841
message: { _ in StaticParserError . initializerInPattern } ,
802
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : node. equal) }
842
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ node. equal] ) }
803
843
)
804
844
}
805
845
return . visitChildren
@@ -1005,7 +1045,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1005
1045
}
1006
1046
if let singleQuote = node. unexpectedBetweenOpenDelimiterAndOpenQuote? . onlyToken ( where: { $0. tokenKind == . singleQuote } ) {
1007
1047
let fixIt = FixIt (
1008
- message: ReplaceTokensFixIt ( replaceTokens: [ singleQuote] , replacement : node. openQuote) ,
1048
+ message: ReplaceTokensFixIt ( replaceTokens: [ singleQuote] , replacements : [ node. openQuote] ) ,
1009
1049
changes: [
1010
1050
. makeMissing( singleQuote, transferTrivia: false ) ,
1011
1051
. makePresent( node. openQuote, leadingTrivia: singleQuote. leadingTrivia ?? [ ] ) ,
@@ -1181,7 +1221,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1181
1221
unexpectedTokenCondition: { $0. tokenKind == . colon } ,
1182
1222
correctTokens: [ node. equal] ,
1183
1223
message: { _ in MissingNodesError ( missingNodes: [ Syntax ( node. equal) ] ) } ,
1184
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : node. equal) }
1224
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ node. equal] ) }
1185
1225
)
1186
1226
}
1187
1227
return . visitChildren
0 commit comments