Skip to content

Commit 5833797

Browse files
committed
Add diagnostic message for identifier editor placeholder
1 parent 39b3336 commit 5833797

File tree

8 files changed

+52
-22
lines changed

8 files changed

+52
-22
lines changed

Sources/SwiftParser/Lexer/Cursor.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,7 @@ extension Lexer.Cursor {
20442044
extension Lexer.Cursor {
20452045
mutating func tryLexEditorPlaceholder(sourceBufferStart: Lexer.Cursor) -> Lexer.Result {
20462046
precondition(self.is(at: "<") && self.is(offset: 1, at: "#"))
2047+
let start = self
20472048
var ptr = self
20482049
let leftAngleConsumed = ptr.advance(matching: "<")
20492050
let poundConsumed = ptr.advance(matching: "#")
@@ -2058,7 +2059,10 @@ extension Lexer.Cursor {
20582059
let closingAngleConsumed = ptr.advance(matching: ">")
20592060
precondition(closingAngleConsumed)
20602061
self = ptr
2061-
return Lexer.Result(.identifier)
2062+
return Lexer.Result(
2063+
.identifier,
2064+
error: LexingDiagnostic(.editorPlaceholder, position: start)
2065+
)
20622066
default:
20632067
break
20642068
}

Sources/SwiftParserDiagnostics/LexerDiagnosticMessages.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public extension TokenError {
3838

3939
/// Please order the cases in this enum alphabetically by case name.
4040
public enum StaticTokenError: String, DiagnosticMessage {
41+
case editorPlaceholder = "editor placeholder in source file"
4142
case expectedBinaryExponentInHexFloatLiteral = "hexadecimal floating point literal must end with an exponent"
4243
case expectedClosingBraceInUnicodeEscape = #"expected '}' in \u{...} escape sequence"#
4344
case expectedDigitInFloatLiteral = "expected a digit in floating point exponent"
@@ -132,6 +133,7 @@ public extension SwiftSyntax.TokenDiagnostic {
132133
}
133134

134135
switch self.kind {
136+
case .editorPlaceholder: return StaticTokenError.editorPlaceholder
135137
case .expectedBinaryExponentInHexFloatLiteral: return StaticTokenError.expectedBinaryExponentInHexFloatLiteral
136138
case .expectedClosingBraceInUnicodeEscape: return StaticTokenError.expectedClosingBraceInUnicodeEscape
137139
case .expectedDigitInFloatLiteral: return StaticTokenError.expectedDigitInFloatLiteral

Sources/SwiftSyntax/TokenDiagnostic.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public struct TokenDiagnostic: Hashable {
2222
public enum Kind {
2323
// Please order these alphabetically
2424

25+
case editorPlaceholder
2526
case expectedBinaryExponentInHexFloatLiteral
2627
case expectedClosingBraceInUnicodeEscape
2728
case expectedDigitInFloatLiteral
@@ -94,6 +95,7 @@ public struct TokenDiagnostic: Hashable {
9495

9596
public var severity: Severity {
9697
switch kind {
98+
case .editorPlaceholder: return .error
9799
case .expectedBinaryExponentInHexFloatLiteral: return .error
98100
case .expectedClosingBraceInUnicodeEscape: return .error
99101
case .expectedDigitInFloatLiteral: return .error

Tests/SwiftParserTest/Assertions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ private func assertTokens(
8787
var lexemeStartOffset = 0
8888
for (actualLexeme, expectedLexeme) in zip(actual, expected) {
8989
defer {
90-
lexemeStartOffset = actualLexeme.byteLength
90+
lexemeStartOffset += actualLexeme.byteLength
9191
}
9292
if actualLexeme.rawTokenKind != expectedLexeme.rawTokenKind {
9393
XCTFail(

Tests/SwiftParserTest/DeclarationTests.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,12 +1379,15 @@ final class DeclarationTests: XCTestCase {
13791379
assertParse(
13801380
"""
13811381
class Foo {
1382-
<#code#>
1382+
1️⃣<#code#>
13831383
}
13841384
""",
13851385
substructure: Syntax(
13861386
MemberDeclListItemSyntax(decl: EditorPlaceholderDeclSyntax(identifier: .identifier("<#code#>")))
1387-
)
1387+
),
1388+
diagnostics: [
1389+
DiagnosticSpec(message: "editor placeholder in source file")
1390+
]
13881391
)
13891392
}
13901393

Tests/SwiftParserTest/ExpressionTests.swift

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -838,9 +838,28 @@ final class ExpressionTests: XCTestCase {
838838
}
839839

840840
func testCodeCompletionExpressions() {
841-
assertParse("if !<#b1#> && !<#b2#> {}")
842-
assertParse("if <#test#> {}")
843-
assertParse("if <#b1#>, <#b2#> {}")
841+
assertParse(
842+
"if !1️⃣<#b1#> && !2️⃣<#b2#> {}",
843+
diagnostics: [
844+
DiagnosticSpec(locationMarker: "1️⃣", message: "editor placeholder in source file"),
845+
DiagnosticSpec(locationMarker: "2️⃣", message: "editor placeholder in source file"),
846+
]
847+
)
848+
849+
assertParse(
850+
"if 1️⃣<#test#> {}",
851+
diagnostics: [
852+
DiagnosticSpec(locationMarker: "1️⃣", message: "editor placeholder in source file")
853+
]
854+
)
855+
856+
assertParse(
857+
"if 1️⃣<#b1#>, 2️⃣<#b2#> {}",
858+
diagnostics: [
859+
DiagnosticSpec(locationMarker: "1️⃣", message: "editor placeholder in source file"),
860+
DiagnosticSpec(locationMarker: "2️⃣", message: "editor placeholder in source file"),
861+
]
862+
)
844863
}
845864

846865
func testKeywordApplyExpression() {

Tests/SwiftParserTest/LexerTests.swift

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fileprivate func lex(_ sourceBytes: [UInt8], body: ([Lexer.Lexeme]) throws -> Vo
3232
/// values for trivia and text. While this is good for most cases, string
3333
/// literals can't contain invalid UTF-8. Thus, we need a different assert
3434
/// function working on byte arrays to test source code containing invalid UTF-8.
35-
fileprivate func assertRawBytesLexeme(
35+
fileprivate func AssertRawBytesLexeme(
3636
_ lexeme: Lexer.Lexeme,
3737
kind: RawTokenKind,
3838
leadingTrivia: [UInt8] = [],
@@ -663,20 +663,20 @@ public class LexerTests: XCTestCase {
663663

664664
func testEditorPlaceholders() {
665665
assertLexemes(
666-
"!<#b1#> && !<#b2#>",
666+
"!1️⃣<#b1#> && !2️⃣<#b2#>",
667667
lexemes: [
668668
LexemeSpec(.prefixOperator, text: "!"),
669-
LexemeSpec(.identifier, text: "<#b1#>", trailing: " "),
669+
LexemeSpec(.identifier, text: "<#b1#>", trailing: " ", errorLocationMarker: "1️⃣", diagnostic: "editor placeholder in source file"),
670670
LexemeSpec(.binaryOperator, text: "&&", trailing: " "),
671671
LexemeSpec(.prefixOperator, text: "!"),
672-
LexemeSpec(.identifier, text: "<#b2#>"),
672+
LexemeSpec(.identifier, text: "<#b2#>", errorLocationMarker: "2️⃣", diagnostic: "editor placeholder in source file"),
673673
]
674674
)
675675

676676
assertLexemes(
677-
"<##>",
677+
"1️⃣<##>",
678678
lexemes: [
679-
LexemeSpec(.identifier, text: "<##>", trailing: "")
679+
LexemeSpec(.identifier, text: "<##>", trailing: "", diagnostic: "editor placeholder in source file")
680680
]
681681
)
682682
}
@@ -812,7 +812,7 @@ public class LexerTests: XCTestCase {
812812
return XCTFail("Expected 1 lexeme, got \(lexemes.count)")
813813
}
814814

815-
assertRawBytesLexeme(
815+
AssertRawBytesLexeme(
816816
lexemes[0],
817817
kind: .eof,
818818
leadingTrivia: sourceBytes,
@@ -828,7 +828,7 @@ public class LexerTests: XCTestCase {
828828
return XCTFail("Expected 2 lexemes, got \(lexemes.count)")
829829
}
830830

831-
assertRawBytesLexeme(
831+
AssertRawBytesLexeme(
832832
lexemes[0],
833833
kind: .identifier,
834834
text: sourceBytes
@@ -843,7 +843,7 @@ public class LexerTests: XCTestCase {
843843
return XCTFail("Expected 4 lexemes, got \(lexemes.count)")
844844
}
845845

846-
assertRawBytesLexeme(
846+
AssertRawBytesLexeme(
847847
lexemes[1],
848848
kind: .binaryOperator,
849849
text: [UInt8(ascii: "+")],
@@ -859,7 +859,7 @@ public class LexerTests: XCTestCase {
859859
guard lexemes.count == 1 else {
860860
return XCTFail("Expected 1 lexeme, got \(lexemes.count)")
861861
}
862-
assertRawBytesLexeme(
862+
AssertRawBytesLexeme(
863863
lexemes[0],
864864
kind: .eof,
865865
leadingTrivia: sourceBytes,
@@ -876,7 +876,7 @@ public class LexerTests: XCTestCase {
876876
guard lexemes.count == 1 else {
877877
return XCTFail("Expected 1 lexeme, got \(lexemes.count)")
878878
}
879-
assertRawBytesLexeme(
879+
AssertRawBytesLexeme(
880880
lexemes[0],
881881
kind: .eof,
882882
leadingTrivia: sourceBytes,
@@ -893,7 +893,7 @@ public class LexerTests: XCTestCase {
893893
guard lexemes.count == 2 else {
894894
return XCTFail("Expected 2 lexemes, got \(lexemes.count)")
895895
}
896-
assertRawBytesLexeme(
896+
AssertRawBytesLexeme(
897897
lexemes[0],
898898
kind: .identifier,
899899
leadingTrivia: [0xfd],
@@ -1080,7 +1080,7 @@ public class LexerTests: XCTestCase {
10801080
return XCTFail("Expected 4 lexemes")
10811081
}
10821082

1083-
assertRawBytesLexeme(
1083+
AssertRawBytesLexeme(
10841084
lexemes[1],
10851085
kind: .stringSegment,
10861086
text: [0xef],

Tests/SwiftParserTest/translated/IdentifiersTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ final class IdentifiersTests: XCTestCase {
8383
assertParse(
8484
"""
8585
// Placeholders are recognized as identifiers but with error.
86-
func <#some name#>() {}
86+
func 1️⃣<#some name#>() {}
8787
""",
8888
diagnostics: [
89-
// TODO: (good first issue) Old parser expected error on line 2: editor placeholder in source file
89+
DiagnosticSpec(message: "editor placeholder in source file")
9090
]
9191
)
9292
}

0 commit comments

Comments
 (0)