Skip to content

Commit 87e7ac6

Browse files
committed
Fix Regression in Leading Trivia for Declarations
This was introduced while migrating their introducers from eat to expect.
1 parent 689eb41 commit 87e7ac6

File tree

3 files changed

+155
-0
lines changed

3 files changed

+155
-0
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ extension Parser {
577577
return RawClassDeclSyntax(
578578
attributes: attrs.attributes,
579579
modifiers: attrs.modifiers,
580+
unexpectedBeforeClassKeyword,
580581
classKeyword: classKeyword,
581582
unexpectedBeforeName,
582583
identifier: name,
@@ -694,6 +695,7 @@ extension Parser {
694695
let members = self.parseMemberDeclList()
695696
return RawEnumDeclSyntax(
696697
attributes: attrs.attributes, modifiers: attrs.modifiers,
698+
unexpectedBeforeEnumKeyword,
697699
enumKeyword: enumKeyword,
698700
unexpectedBeforeName,
699701
identifier: name,
@@ -831,6 +833,7 @@ extension Parser {
831833
let members = self.parseMemberDeclList()
832834
return RawStructDeclSyntax(
833835
attributes: attrs.attributes, modifiers: attrs.modifiers,
836+
unexpectedBeforeStructKeyword,
834837
structKeyword: structKeyword,
835838
identifier: name,
836839
genericParameterClause: generics,
@@ -938,6 +941,7 @@ extension Parser {
938941

939942
return RawProtocolDeclSyntax(
940943
attributes: attrs.attributes, modifiers: attrs.modifiers,
944+
unexpectedBeforeProtocolKeyword,
941945
protocolKeyword: protocolKeyword,
942946
identifier: name,
943947
primaryAssociatedTypeClause: primaries,
@@ -1003,6 +1007,7 @@ extension Parser {
10031007

10041008
return RawAssociatedtypeDeclSyntax(
10051009
attributes: attrs.attributes, modifiers: attrs.modifiers,
1010+
unexpectedBeforeAssocKeyword,
10061011
associatedtypeKeyword: assocKeyword,
10071012
identifier: name,
10081013
inheritanceClause: inheritance,

Tests/SwiftParserTest/Declarations.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,55 @@ final class DeclarationTests: XCTestCase {
782782
}
783783
"""##)
784784
}
785+
786+
func testLeadingUnexpectedTokens() {
787+
AssertParse("#^DIAG_1^#}class C#^DIAG_2^#",
788+
diagnostics: [
789+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Unexpected text '}' found in class"),
790+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '{' to start class"),
791+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '}' to end class"),
792+
])
793+
AssertParse("#^DIAG_1^#}enum C#^DIAG_2^#",
794+
diagnostics: [
795+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Unexpected text '}' found in enum"),
796+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '{' to start enum"),
797+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '}' to end enum"),
798+
])
799+
AssertParse("#^DIAG_1^#}protocol C#^DIAG_2^#",
800+
diagnostics: [
801+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Unexpected text '}' found in protocol"),
802+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '{' to start protocol"),
803+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '}' to end protocol"),
804+
])
805+
AssertParse("#^DIAG_1^#}actor C#^DIAG_2^#",
806+
diagnostics: [
807+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Unexpected text '}' found in actor"),
808+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '{' to start actor"),
809+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '}' to end actor"),
810+
])
811+
AssertParse("#^DIAG_1^#}struct C#^DIAG_2^#",
812+
diagnostics: [
813+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Unexpected text '}' found in struct"),
814+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '{' to start struct"),
815+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '}' to end struct"),
816+
])
817+
AssertParse("#^DIAG_1^#}func C#^DIAG_2^#",
818+
diagnostics: [
819+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Unexpected text '}' found in function"),
820+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected argument list in function declaration"),
821+
])
822+
AssertParse("#^DIAG_1^#}init#^DIAG_2^#",
823+
diagnostics: [
824+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Unexpected text '}' found in initializer"),
825+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected argument list in function declaration"),
826+
])
827+
AssertParse("#^DIAG_1^#}subscript#^DIAG_2^#",
828+
diagnostics: [
829+
DiagnosticSpec(locationMarker: "DIAG_1", message: "Unexpected text '}' found in subscript"),
830+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected argument list in function declaration"),
831+
DiagnosticSpec(locationMarker: "DIAG_2", message: "Expected '->' in return clause"),
832+
])
833+
}
785834
}
786835

787836
extension Parser.DeclAttributes {

Tests/SwiftParserTest/ParserTests.swift

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,105 @@ public class ParserTests: XCTestCase {
3838
}())
3939
}
4040
}
41+
42+
func testSDKParse() throws {
43+
if #available(macOS 13.0, *) {
44+
let platformsRoot = URL(fileURLWithPath: "/Applications/Xcode-SummitE.app/Contents/Developer/Platforms")
45+
let platformURLs = try FileManager.default
46+
.contentsOfDirectory(at: platformsRoot, includingPropertiesForKeys: nil)
47+
.filter({$0.pathExtension == "platform"})
48+
for platformURL in platformURLs {
49+
print("====================== STARTING \(platformURL.lastPathComponent) ========================")
50+
defer {
51+
print("====================== LEAVING \(platformURL.lastPathComponent) ========================")
52+
}
53+
let sdkRoot = platformURL
54+
.appending(path: "Developer")
55+
.appending(path: "SDKs")
56+
guard
57+
let sdkURLs = try? FileManager.default
58+
.contentsOfDirectory(at: sdkRoot, includingPropertiesForKeys: nil)
59+
.filter({$0.pathExtension == "sdk"})
60+
else {
61+
print("====================== SKIPPING \(platformURL.lastPathComponent) ========================")
62+
continue
63+
}
64+
for sdkURL in sdkURLs {
65+
var passed = 0
66+
var failed = 0
67+
var skipped = 0
68+
print("====================== STARTING \(sdkURL.lastPathComponent) ========================")
69+
defer {
70+
print(">>> STATS Passed: \(passed), Failed: \(failed), Skipped: \(skipped)")
71+
print("====================== LEAVING \(sdkURL.lastPathComponent) ========================")
72+
}
73+
74+
let frameworksRoot = sdkURL
75+
.appending(path: "System")
76+
.appending(path: "Library")
77+
.appending(path: "Frameworks")
78+
guard
79+
let frameworkURLs = try? FileManager.default
80+
.contentsOfDirectory(at: frameworksRoot, includingPropertiesForKeys: nil)
81+
.filter({$0.pathExtension == "framework"})
82+
else {
83+
continue
84+
}
85+
for frameworkURL in frameworkURLs {
86+
let modulesRoot = frameworkURL
87+
.appending(path: "Modules")
88+
var isDir: ObjCBool = false
89+
guard FileManager.default.fileExists(atPath: modulesRoot.path(), isDirectory: &isDir), isDir.boolValue else {
90+
print(">>> Skipping \(frameworkURL.lastPathComponent): It is not modular")
91+
skipped += 1
92+
continue
93+
}
94+
95+
let expectedSwiftModuleName = frameworkURL.deletingPathExtension().lastPathComponent.appending(".swiftmodule")
96+
let swiftModuleRoot = modulesRoot.appending(path: expectedSwiftModuleName)
97+
guard FileManager.default.fileExists(atPath: swiftModuleRoot.path(), isDirectory: &isDir), isDir.boolValue else {
98+
print(">>> Skipping \(frameworkURL.lastPathComponent): It does not contain Swift")
99+
skipped += 1
100+
continue
101+
}
102+
103+
let interfaceURLs = FileManager.default
104+
.enumerator(at: swiftModuleRoot, includingPropertiesForKeys: nil)!
105+
.compactMap({ $0 as? URL })
106+
.filter({$0.pathExtension == "swiftinterface"})
107+
108+
for interfaceURL in interfaceURLs {
109+
XCTAssertNoThrow(try {
110+
let fileContents = try String(contentsOf: interfaceURL)
111+
let parsed = try Parser.parse(source: fileContents)
112+
AssertStringsEqualWithDiff("\(parsed)", fileContents)
113+
let diagnostics = ParseDiagnosticsGenerator.diagnostics(for: parsed)
114+
if !diagnostics.isEmpty {
115+
var locationAndDiagnostics: [String] = []
116+
let locationConverter = SourceLocationConverter(file: interfaceURL.lastPathComponent, tree: parsed)
117+
for diag in diagnostics {
118+
let location = diag.location(converter: locationConverter)
119+
let message = diag.message
120+
locationAndDiagnostics.append("\(location): \(message)")
121+
}
122+
XCTFail("""
123+
Received the following diagnostics while parsing \(interfaceURL)
124+
\(locationAndDiagnostics.joined(separator: "\n"))
125+
""")
126+
failed += 1
127+
} else {
128+
passed += 1
129+
}
130+
}())
131+
}
132+
}
133+
134+
let privateFrameworksRoot = sdkURL
135+
.appending(path: "System")
136+
.appending(path: "Library")
137+
.appending(path: "PrivateFrameworks")
138+
}
139+
}
140+
}
141+
}
41142
}

0 commit comments

Comments
 (0)