@@ -15,6 +15,26 @@ import SwiftDiagnostics
15
15
@_spi ( RawSyntax) import SwiftSyntax
16
16
17
17
fileprivate func getTokens( between first: TokenSyntax , and second: TokenSyntax ) -> [ TokenSyntax ] {
18
+ var first = first
19
+ if first. presence == . missing {
20
+ let nextPresentToken = first. nextToken ( viewMode: . sourceAccurate)
21
+ guard let nextPresentToken else {
22
+ return [ ]
23
+ }
24
+ first = nextPresentToken
25
+ }
26
+ precondition ( first. presence == . present)
27
+
28
+ var second = second
29
+ if second. presence == . missing {
30
+ let previousPresentToken = second. previousToken ( viewMode: . sourceAccurate)
31
+ guard let previousPresentToken else {
32
+ return [ ]
33
+ }
34
+ second = previousPresentToken
35
+ }
36
+ precondition ( second. presence == . present)
37
+
18
38
var tokens : [ TokenSyntax ] = [ ]
19
39
var currentToken = first
20
40
@@ -149,7 +169,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
149
169
removeRedundantFixIt: ( _ misplacedTokens: [ TokenSyntax ] ) -> FixItMessage ? = { _ in nil }
150
170
) {
151
171
guard let incorrectContainer = unexpected,
152
- let misplacedTokens = incorrectContainer. onlyTokens ( satisfying: unexpectedTokenCondition)
172
+ let misplacedTokens = incorrectContainer. onlyPresentTokens ( satisfying: unexpectedTokenCondition)
153
173
else {
154
174
// If there are no unexpected nodes or the unexpected contain multiple tokens, don't emit a diagnostic.
155
175
return
@@ -197,7 +217,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
197
217
message: ( TokenSyntax ) -> some DiagnosticMessage
198
218
) {
199
219
guard let unexpected = unexpected,
200
- let misplacedToken = unexpected. onlyToken ( where: predicate)
220
+ let misplacedToken = unexpected. onlyPresentToken ( where: predicate)
201
221
else {
202
222
// If there is no unexpected node or the unexpected doesn't have the
203
223
// expected token, don't emit a diagnostic.
@@ -279,7 +299,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
279
299
}
280
300
if specifier. presence == . present {
281
301
for case . some( let unexpected) in unexpectedNodes {
282
- for duplicateSpecifier in unexpected. tokens ( satisfying: isOfSameKind) {
302
+ for duplicateSpecifier in unexpected. presentTokens ( satisfying: isOfSameKind) {
283
303
addDiagnostic (
284
304
duplicateSpecifier,
285
305
DuplicateEffectSpecifiers ( correctSpecifier: specifier, unexpectedSpecifier: duplicateSpecifier) ,
@@ -315,29 +335,36 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
315
335
suppressRemainingDiagnostics = true
316
336
return . skipChildren
317
337
}
318
- if let tryKeyword = node. onlyToken ( where: { $0. tokenKind == . keyword( . try ) } ) ,
338
+ if let tryKeyword = node. onlyPresentToken ( where: { $0. tokenKind == . keyword( . try ) } ) ,
319
339
let nextToken = tryKeyword. nextToken ( viewMode: . sourceAccurate) ,
320
340
nextToken. tokenKind. isLexerClassifiedKeyword,
321
341
!( node. parent? . is ( TypeEffectSpecifiersSyntax . self) ?? false )
322
342
{
323
343
addDiagnostic ( node, TryCannotBeUsed ( nextToken: nextToken) )
324
- } else if let semicolons = node. onlyTokens ( satisfying: { $0. tokenKind == . semicolon } ) {
344
+ } else if let semicolons = node. onlyPresentTokens ( satisfying: { $0. tokenKind == . semicolon } ) {
325
345
addDiagnostic (
326
346
node,
327
347
. unexpectedSemicolon,
328
348
fixIts: [
329
349
FixIt ( message: RemoveNodesFixIt ( semicolons) , changes: semicolons. map { FixIt . MultiNodeChange. makeMissing ( $0) } )
330
350
]
331
351
)
332
- } else if node. first? . as ( TokenSyntax . self) ? . tokenKind. isIdentifier == true ,
352
+ } else if let firstToken = node. first? . as ( TokenSyntax . self) ,
353
+ firstToken. tokenKind. isIdentifier == true ,
354
+ firstToken. presence == . present,
333
355
let previousToken = node. previousToken ( viewMode: . sourceAccurate) ,
334
356
previousToken. tokenKind. isIdentifier,
335
357
previousToken. parent? . is ( DeclSyntax . self) == true || previousToken. parent? . is ( IdentifierPatternSyntax . self) == true
336
358
{
337
359
// If multiple identifiers are used for a declaration name, offer to join them together.
338
360
let tokens =
339
361
node
340
- . prefix ( while: { $0. as ( TokenSyntax . self) ? . tokenKind. isIdentifier == true } )
362
+ . prefix ( while: {
363
+ guard let token = $0. as ( TokenSyntax . self) else {
364
+ return false
365
+ }
366
+ return token. tokenKind. isIdentifier == true && token. presence == . present
367
+ } )
341
368
. map ( { $0. as ( TokenSyntax . self) ! } )
342
369
let joined = previousToken. text + tokens. map ( \. text) . joined ( )
343
370
var fixIts : [ FixIt ] = [
@@ -494,7 +521,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
494
521
}
495
522
496
523
if let unexpectedAfterRightParen = node. unexpectedAfterRightParen,
497
- let ( _, falseKeyword) = unexpectedAfterRightParen. twoTokens (
524
+ let ( _, falseKeyword) = unexpectedAfterRightParen. twoPresentTokens (
498
525
firstSatisfying: { $0. tokenKind == . binaryOperator( " == " ) } ,
499
526
secondSatisfying: { $0. tokenKind == . keyword( . false ) }
500
527
)
@@ -531,7 +558,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
531
558
return . skipChildren
532
559
}
533
560
if let unexpected = node. unexpectedBetweenPlatformAndVersion,
534
- unexpected. onlyToken ( where: { $0. tokenKind == . binaryOperator( " >= " ) } ) != nil
561
+ unexpected. onlyPresentToken ( where: { $0. tokenKind == . binaryOperator( " >= " ) } ) != nil
535
562
{
536
563
addDiagnostic (
537
564
unexpected,
@@ -678,7 +705,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
678
705
}
679
706
680
707
if let unexpected = node. unexpectedBetweenBodyAndTrailingComma,
681
- let token = unexpected. tokens ( satisfying: { $0. tokenKind == . binaryOperator( " && " ) } ) . first,
708
+ let token = unexpected. presentTokens ( satisfying: { $0. tokenKind == . binaryOperator( " && " ) } ) . first,
682
709
let trailingComma = node. trailingComma,
683
710
trailingComma. presence == . missing,
684
711
let previous = node. unexpectedBetweenBodyAndTrailingComma? . previousToken ( viewMode: . sourceAccurate)
@@ -709,7 +736,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
709
736
return . skipChildren
710
737
}
711
738
if let unexpected = node. unexpectedBetweenDeinitKeywordAndBody,
712
- let name = unexpected. filter ( { $0. as ( TokenSyntax . self ) ? . tokenKind. isIdentifier == true } ) . only? . as ( TokenSyntax . self)
739
+ let name = unexpected. presentTokens ( satisfying : { $0. tokenKind. isIdentifier == true } ) . only? . as ( TokenSyntax . self)
713
740
{
714
741
addDiagnostic (
715
742
name,
@@ -741,7 +768,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
741
768
return . skipChildren
742
769
}
743
770
if node. floatingDigits. presence == . missing,
744
- let ( period, integerLiteral) = node. unexpectedAfterFloatingDigits? . twoTokens (
771
+ let ( period, integerLiteral) = node. unexpectedAfterFloatingDigits? . twoPresentTokens (
745
772
firstSatisfying: { $0. tokenKind == . period } ,
746
773
secondSatisfying: { $0. tokenKind. isIntegerLiteral }
747
774
)
@@ -772,7 +799,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
772
799
// Detect C-style for loops based on two semicolons which could not be parsed between the 'for' keyword and the '{'
773
800
// This is mostly a proof-of-concept implementation to produce more complex diagnostics.
774
801
if let unexpectedCondition = node. body. unexpectedBeforeLeftBrace,
775
- unexpectedCondition. tokens ( withKind: . semicolon) . count == 2
802
+ unexpectedCondition. presentTokens ( withKind: . semicolon) . count == 2
776
803
{
777
804
// FIXME: This is aweful. We should have a way to either get all children between two cursors in a syntax node or highlight a range from one node to another.
778
805
addDiagnostic (
@@ -855,7 +882,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
855
882
message: { _ in . typeParameterPackEllipsis }
856
883
)
857
884
} else if let unexpected = node. unexpectedBetweenNameAndColon,
858
- let unexpectedEllipsis = unexpected. onlyToken ( where: { $0. tokenKind == . ellipsis } ) ,
885
+ let unexpectedEllipsis = unexpected. onlyPresentToken ( where: { $0. tokenKind == . ellipsis } ) ,
859
886
let each = node. each
860
887
{
861
888
addDiagnostic (
@@ -1105,7 +1132,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1105
1132
if shouldSkip ( node) {
1106
1133
return . skipChildren
1107
1134
}
1108
- if let token = node. unexpectedBetweenModuleLabelAndColon? . onlyToken ( where: { $0. tokenKind. isIdentifier } ) ,
1135
+ if let token = node. unexpectedBetweenModuleLabelAndColon? . onlyPresentToken ( where: { $0. tokenKind. isIdentifier } ) ,
1109
1136
node. moduleLabel. presence == . missing
1110
1137
{
1111
1138
addDiagnostic (
@@ -1172,9 +1199,9 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1172
1199
return
1173
1200
}
1174
1201
let message : DiagnosticMessage ?
1175
- if let identifier = unexpected. onlyToken ( where: { $0. tokenKind. isIdentifier } ) {
1202
+ if let identifier = unexpected. onlyPresentToken ( where: { $0. tokenKind. isIdentifier } ) {
1176
1203
message = IdentifierNotAllowedInOperatorName ( identifier: identifier)
1177
- } else if let tokens = unexpected. onlyTokens ( satisfying: { _ in true } ) {
1204
+ } else if let tokens = unexpected. onlyPresentTokens ( satisfying: { _ in true } ) {
1178
1205
message = TokensNotAllowedInOperatorName ( tokens: tokens)
1179
1206
} else {
1180
1207
message = nil
@@ -1265,7 +1292,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1265
1292
return . skipChildren
1266
1293
}
1267
1294
// recover from Objective-C style literals
1268
- if let atSign = node. unexpectedBetweenOpenDelimiterAndOpenQuote? . onlyToken ( where: { $0. tokenKind == . atSign } ) {
1295
+ if let atSign = node. unexpectedBetweenOpenDelimiterAndOpenQuote? . onlyPresentToken ( where: { $0. tokenKind == . atSign } ) {
1269
1296
addDiagnostic (
1270
1297
node,
1271
1298
. stringLiteralAtSign,
@@ -1275,7 +1302,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1275
1302
handledNodes: [ atSign. id]
1276
1303
)
1277
1304
}
1278
- if let singleQuote = node. unexpectedBetweenOpenDelimiterAndOpenQuote? . onlyToken ( where: { $0. tokenKind == . singleQuote } ) {
1305
+ if let singleQuote = node. unexpectedBetweenOpenDelimiterAndOpenQuote? . onlyPresentToken ( where: { $0. tokenKind == . singleQuote } ) {
1279
1306
let fixIt = FixIt (
1280
1307
message: ReplaceTokensFixIt ( replaceTokens: [ singleQuote] , replacements: [ node. openQuote] ) ,
1281
1308
changes: [
@@ -1325,7 +1352,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1325
1352
addDiagnostic ( diagnostic, handledNodes: handledNodes)
1326
1353
}
1327
1354
if case . stringSegment( let segment) = node. segments. last {
1328
- if let invalidContent = segment. unexpectedBeforeContent? . onlyToken ( where: { $0. trailingTrivia. contains ( where: { $0. isBackslash } ) } ) {
1355
+ if let invalidContent = segment. unexpectedBeforeContent? . onlyPresentToken ( where: { $0. trailingTrivia. contains ( where: { $0. isBackslash } ) } ) {
1329
1356
let fixIt = FixIt (
1330
1357
message: . removeBackslash,
1331
1358
changes: [
@@ -1350,7 +1377,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1350
1377
return . skipChildren
1351
1378
}
1352
1379
if let unexpected = node. unexpectedBetweenSubscriptKeywordAndGenericParameterClause,
1353
- let nameTokens = unexpected. onlyTokens ( satisfying: { !$0. tokenKind. isLexerClassifiedKeyword } )
1380
+ let nameTokens = unexpected. onlyPresentTokens ( satisfying: { !$0. tokenKind. isLexerClassifiedKeyword } )
1354
1381
{
1355
1382
addDiagnostic (
1356
1383
unexpected,
@@ -1362,7 +1389,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1362
1389
)
1363
1390
}
1364
1391
if let unexpected = node. indices. unexpectedBeforeLeftParen,
1365
- let nameTokens = unexpected. onlyTokens ( satisfying: { !$0. tokenKind. isLexerClassifiedKeyword } )
1392
+ let nameTokens = unexpected. onlyPresentTokens ( satisfying: { !$0. tokenKind. isLexerClassifiedKeyword } )
1366
1393
{
1367
1394
addDiagnostic (
1368
1395
unexpected,
@@ -1471,7 +1498,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1471
1498
}
1472
1499
1473
1500
if let unexpected = node. unexpectedBeforeColon,
1474
- let leftParen = unexpected. onlyToken ( where: { $0. tokenKind == . leftParen } )
1501
+ let leftParen = unexpected. onlyPresentToken ( where: { $0. tokenKind == . leftParen } )
1475
1502
{
1476
1503
1477
1504
var handledNodes : [ SyntaxIdentifier ] = [
@@ -1486,7 +1513,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1486
1513
1487
1514
var replaceTokens = [ leftParen]
1488
1515
1489
- if let rightParen = node. unexpectedAfterInheritedTypeCollection? . onlyToken ( where: { $0. tokenKind == . rightParen } ) {
1516
+ if let rightParen = node. unexpectedAfterInheritedTypeCollection? . onlyPresentToken ( where: { $0. tokenKind == . rightParen } ) {
1490
1517
handledNodes += [ rightParen. id]
1491
1518
changes += [
1492
1519
. makeMissing( rightParen)
@@ -1531,7 +1558,8 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1531
1558
return . skipChildren
1532
1559
}
1533
1560
1534
- if let token = node. unexpectedBetweenMessageLabelAndColon? . onlyToken ( where: { $0. tokenKind. isIdentifier } ) ,
1561
+ if let token = node. unexpectedBetweenMessageLabelAndColon? . onlyPresentToken ( where: { $0. tokenKind. isIdentifier } ) ,
1562
+ token. presence == . present,
1535
1563
node. messageLabel. presence == . missing
1536
1564
{
1537
1565
addDiagnostic (
@@ -1605,7 +1633,7 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
1605
1633
}
1606
1634
1607
1635
let unexpectedTokens : [ TokenSyntax ] = [ detail. unexpectedBetweenLeftParenAndDetail, detail. unexpectedBetweenDetailAndRightParen]
1608
- . compactMap { $0? . tokens ( viewMode: . all ) }
1636
+ . compactMap { $0? . tokens ( viewMode: . sourceAccurate ) }
1609
1637
. flatMap { $0 }
1610
1638
1611
1639
// If there is no unexpected tokens it means we miss a paren or set keyword.
0 commit comments