Repository: swiftlang/swift-syntax (swift)

Issue:
If an attribute is put on a statement, the entire statement is classified as unexpected
### Issue Kind

Bad Diagnostic Produced

### Source Code

```swift
func test1() {
  #^TEST_1^#@s return
}
```
(from `testAttributesOnStatements`)

### Description

This should eat `@s` as unexpected tokens and parse `return` as a statement instead of complaining
```
Unexpected text '@s return' found in function
```

Pull request description:
Fixes apple/swift-syntax#714
rdar://99594971

Patch:
diff --git a/Sources/SwiftParser/Statements.swift b/Sources/SwiftParser/Statements.swift
index 8ec998c94bc..63148912979 100644
--- a/Sources/SwiftParser/Statements.swift
+++ b/Sources/SwiftParser/Statements.swift
@@ -20,6 +20,11 @@ extension TokenConsumer {
   /// - Seealso: ``Parser/parseStatement()``
   func atStartOfStatement(allowRecovery: Bool = false) -> Bool {
     var lookahead = self.lookahead()
+    if allowRecovery {
+      // Attributes are not allowed on statements. But for recovery, skip over
+      // misplaced attributes.
+      _ = lookahead.consumeAttributeList()
+    }
     return lookahead.isStartOfStatement(allowRecovery: allowRecovery)
   }
 }
diff --git a/Sources/SwiftParser/TokenPrecedence.swift b/Sources/SwiftParser/TokenPrecedence.swift
index a698fdd7033..817ac84ab3d 100644
--- a/Sources/SwiftParser/TokenPrecedence.swift
+++ b/Sources/SwiftParser/TokenPrecedence.swift
@@ -135,7 +135,7 @@ public enum TokenPrecedence: Comparable {
     case  // Chaining punctuators
     .infixQuestionMark, .period, .postfixQuestionMark, .exclamationMark,
       // Misc
-      .backslash, .backtick, .colon, .comma, .ellipsis, .equal, .prefixAmpersand:
+      .atSign, .backslash, .backtick, .colon, .comma, .ellipsis, .equal, .prefixAmpersand:
       self = .weakPunctuator
 
     // MARK: Weak bracket close
@@ -159,8 +159,6 @@ public enum TokenPrecedence: Comparable {
     .semicolon,
       // Arrow is a strong indicator in a function type that we are now in the return type
       .arrow,
-      // '@' typically occurs at the start of declarations
-      .atSign,
       // EOF is here because it is a very stong marker and doesn't belong anywhere else
       .eof:
       self = .strongPunctuator


Test patch:
diff --git a/Tests/SwiftParserTest/StatementTests.swift b/Tests/SwiftParserTest/StatementTests.swift
index 6679c107f95..ea4a2b1b371 100644
--- a/Tests/SwiftParserTest/StatementTests.swift
+++ b/Tests/SwiftParserTest/StatementTests.swift
@@ -265,8 +265,8 @@ final class StatementTests: XCTestCase {
       }
       """,
       diagnostics: [
-        DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '@s return' in function"),
-        DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '@unknown return' in function"),
+        DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '@s' before 'return' statement"),
+        DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '@unknown' before 'return' statement"),
       ]
     )
   }
diff --git a/Tests/SwiftParserTest/translated/SwitchTests.swift b/Tests/SwiftParserTest/translated/SwitchTests.swift
index 6dde8667781..eab3bbb49d1 100644
--- a/Tests/SwiftParserTest/translated/SwitchTests.swift
+++ b/Tests/SwiftParserTest/translated/SwitchTests.swift
@@ -950,7 +950,7 @@ final class SwitchTests: XCTestCase {
       }
       """,
       diagnostics: [
-        DiagnosticSpec(message: "expected label in switch case")
+        DiagnosticSpec(message: "unexpected code '@moreGarbage' in switch case")
       ]
     )
   }
@@ -986,22 +986,21 @@ final class SwitchTests: XCTestCase {
       switch Whatever.Thing {
       case .Thing:
         break
-      @unknown2️⃣
       @unknown
+      2️⃣@unknown
       case _:
         break
       }
       switch Whatever.Thing { 
-      @unknown 3️⃣@garbage4️⃣(foobar)
+      @unknown 3️⃣@garbage(foobar)
       case _:
         break
       }
       """,
       diagnostics: [
         DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '(garbage)' in switch case"),
-        DiagnosticSpec(locationMarker: "2️⃣", message: "expected label in switch case"),
-        DiagnosticSpec(locationMarker: "3️⃣", message: "expected label in switch case"),
-        DiagnosticSpec(locationMarker: "4️⃣", message: "unexpected code '(foobar)' in switch case"),
+        DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '@unknown' in switch case"),
+        DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected code '@garbage(foobar)' in switch case"),
       ]
     )
   }