@@ -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
}
@@ -438,7 +454,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
438
454
unexpectedTokenCondition: { $0. text == " || " } ,
439
455
correctTokens: [ node. trailingComma] ,
440
456
message: { _ in . joinPlatformsUsingComma } ,
441
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : trailingComma) }
457
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ trailingComma] ) }
442
458
)
443
459
}
444
460
return . visitChildren
@@ -467,13 +483,42 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
467
483
if shouldSkip ( node) {
468
484
return . skipChildren
469
485
}
486
+ if let unexpected = node. unexpectedBetweenConditionAndTrailingComma,
487
+ let availability = node. condition. as ( AvailabilityConditionSyntax . self) ,
488
+ let ( _, falseKeyword) = unexpected. twoTokens (
489
+ firstSatisfying: { $0. tokenKind == . binaryOperator( " == " ) } ,
490
+ secondSatisfying: { $0. tokenKind == . keyword( . false ) }
491
+ )
492
+ {
493
+ // Diagnose #available used as an expression
494
+ let negatedAvailabilityKeyword = availability. availabilityKeyword. negatedAvailabilityKeyword
495
+ let negatedCoditionElement = ConditionElementSyntax (
496
+ condition: . availability( availability. with ( \. availabilityKeyword, negatedAvailabilityKeyword) ) ,
497
+ trailingComma: node. trailingComma
498
+ )
499
+ if let negatedAvailability = negatedCoditionElement. condition. as ( AvailabilityConditionSyntax . self) {
500
+ addDiagnostic (
501
+ unexpected,
502
+ AvailabilityConditionAsExpression ( availabilityToken: availability. availabilityKeyword, negatedAvailabilityToken: negatedAvailabilityKeyword) ,
503
+ fixIts: [
504
+ FixIt (
505
+ message: ReplaceTokensFixIt ( replaceTokens: getTokens ( between: availability. availabilityKeyword, and: falseKeyword) , replacements: getTokens ( between: negatedAvailability. availabilityKeyword, and: negatedAvailability. rightParen) ) ,
506
+ changes: [
507
+ . replace( oldNode: Syntax ( node) , newNode: Syntax ( negatedCoditionElement) )
508
+ ]
509
+ )
510
+ ] ,
511
+ handledNodes: [ unexpected. id]
512
+ )
513
+ }
514
+ }
470
515
if let trailingComma = node. trailingComma {
471
516
exchangeTokens (
472
517
unexpected: node. unexpectedBetweenConditionAndTrailingComma,
473
518
unexpectedTokenCondition: { $0. text == " && " } ,
474
519
correctTokens: [ node. trailingComma] ,
475
520
message: { _ in . joinConditionsUsingComma } ,
476
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : trailingComma) }
521
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ trailingComma] ) }
477
522
)
478
523
}
479
524
return . visitChildren
@@ -563,7 +608,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
563
608
. expectedCommaInWhereClause,
564
609
fixIts: [
565
610
FixIt (
566
- message: ReplaceTokensFixIt ( replaceTokens: [ token] , replacement : . commaToken( ) ) ,
611
+ message: ReplaceTokensFixIt ( replaceTokens: [ token] , replacements : [ . commaToken( ) ] ) ,
567
612
changes: [
568
613
. makeMissing( token) ,
569
614
. makePresent( trailingComma) ,
@@ -698,7 +743,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
698
743
. typeParameterPackEllipsis,
699
744
fixIts: [
700
745
FixIt (
701
- message: ReplaceTokensFixIt ( replaceTokens: [ unexpectedEllipsis] , replacement : . keyword( . each) ) ,
746
+ message: ReplaceTokensFixIt ( replaceTokens: [ unexpectedEllipsis] , replacements : [ . keyword( . each) ] ) ,
702
747
changes: [
703
748
. makeMissing( unexpected) ,
704
749
. makePresent( each, trailingTrivia: . space) ,
@@ -714,7 +759,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
714
759
unexpectedTokenCondition: { $0. tokenKind == . keyword( . class) } ,
715
760
correctTokens: [ inheritedTypeName] ,
716
761
message: { _ in StaticParserError . classConstraintCanOnlyBeUsedInProtocol } ,
717
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : inheritedTypeName) }
762
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ inheritedTypeName] ) }
718
763
)
719
764
}
720
765
return . visitChildren
@@ -745,7 +790,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
745
790
NegatedAvailabilityCondition ( avaialabilityCondition: availability, negatedAvailabilityKeyword: negatedAvailabilityKeyword) ,
746
791
fixIts: [
747
792
FixIt (
748
- message: ReplaceTokensFixIt ( replaceTokens: [ operatorToken, availability. availabilityKeyword] , replacement : negatedAvailabilityKeyword) ,
793
+ message: ReplaceTokensFixIt ( replaceTokens: [ operatorToken, availability. availabilityKeyword] , replacements : [ negatedAvailabilityKeyword] ) ,
749
794
changes: [
750
795
. replace( oldNode: Syntax ( conditionElement) , newNode: Syntax ( negatedCoditionElement) )
751
796
]
@@ -777,7 +822,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
777
822
StaticParserError . unexpectedPoundElseSpaceIf,
778
823
fixIts: [
779
824
FixIt (
780
- message: ReplaceTokensFixIt ( replaceTokens: unexpectedTokens, replacement : clause. poundKeyword) ,
825
+ message: ReplaceTokensFixIt ( replaceTokens: unexpectedTokens, replacements : [ clause. poundKeyword] ) ,
781
826
changes: [
782
827
. makeMissing( unexpectedBeforePoundKeyword, transferTrivia: false ) ,
783
828
. makePresent( clause. poundKeyword, leadingTrivia: unexpectedBeforePoundKeyword. leadingTrivia) ,
@@ -821,7 +866,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
821
866
. expectedAssignmentInsteadOfComparisonOperator,
822
867
fixIts: [
823
868
FixIt (
824
- message: ReplaceTokensFixIt ( replaceTokens: [ . binaryOperator( " == " ) ] , replacement : node. equal) ,
869
+ message: ReplaceTokensFixIt ( replaceTokens: [ . binaryOperator( " == " ) ] , replacements : [ node. equal] ) ,
825
870
changes: [ . makeMissing( unexpected) , . makePresent( node. equal, leadingTrivia: [ ] ) ]
826
871
)
827
872
] ,
@@ -835,7 +880,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
835
880
unexpectedTokenCondition: { $0. tokenKind == . colon } ,
836
881
correctTokens: [ node. equal] ,
837
882
message: { _ in StaticParserError . initializerInPattern } ,
838
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : node. equal) }
883
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ node. equal] ) }
839
884
)
840
885
}
841
886
return . visitChildren
@@ -1052,7 +1097,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1052
1097
}
1053
1098
if let singleQuote = node. unexpectedBetweenOpenDelimiterAndOpenQuote? . onlyToken ( where: { $0. tokenKind == . singleQuote } ) {
1054
1099
let fixIt = FixIt (
1055
- message: ReplaceTokensFixIt ( replaceTokens: [ singleQuote] , replacement : node. openQuote) ,
1100
+ message: ReplaceTokensFixIt ( replaceTokens: [ singleQuote] , replacements : [ node. openQuote] ) ,
1056
1101
changes: [
1057
1102
. makeMissing( singleQuote, transferTrivia: false ) ,
1058
1103
. makePresent( node. openQuote, leadingTrivia: singleQuote. leadingTrivia) ,
@@ -1228,7 +1273,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1228
1273
unexpectedTokenCondition: { $0. tokenKind == . colon } ,
1229
1274
correctTokens: [ node. equal] ,
1230
1275
message: { _ in MissingNodesError ( missingNodes: [ Syntax ( node. equal) ] ) } ,
1231
- moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacement : node. equal) }
1276
+ moveFixIt: { ReplaceTokensFixIt ( replaceTokens: $0, replacements : [ node. equal] ) }
1232
1277
)
1233
1278
}
1234
1279
return . visitChildren
0 commit comments