Repository: scalameta/scalameta (scala)

Issue:
Formatting extension methods with `@targetName` annotation fails
## Configuration ##

```
version = 3.7.6
...
```

## Command-line parameters (required) ##

When I run scalafmt via CLI like this: `scalafmt .`

## Steps

Given code like this:
```scala
  extension [A, B](t: Tree[A])
    @targetName("bottomUpPostfix")
    def bottomUp(f: ((A, LazyList[B]) => B)): Tree[B] =
      outer.bottomUp(t, f)

    @targetName("prunePostfix")
    def prune(f: A => Option[B]): Option[Tree[B]] =
      outer.prune(t, f)
```

## Problem

Scalafmt formats code like this:
```scala
  extension [A, B](t: Tree[A])
    @targetName("bottomUpPostfix")
    def bottomUp(f: ((A, LazyList[B]) => B)): Tree[B] =
      outer.bottomUp(t, f)

  @targetName("prunePostfix")
  def prune(f: A => Option[B]): Option[Tree[B]] =
    outer.prune(t, f)
```

## Expectation

I would like the formatted output to look like this:
```scala
  extension [A, B](t: Tree[A])
    @targetName("bottomUpPostfix")
    def bottomUp(f: ((A, LazyList[B]) => B)): Tree[B] =
      outer.bottomUp(t, f)

    @targetName("prunePostfix")
    def prune(f: A => Option[B]): Option[Tree[B]] =
      outer.prune(t, f)
```

Pull request:
Fixes #3231.

Patch:
diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala
index 95948d86cd..d03926a15c 100644
--- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala
+++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala
@@ -574,7 +574,7 @@ final class ScannerTokens(val tokens: Tokens)(implicit dialect: Dialect) {
           case soft.KwDerives() => getTemplateInherit(sepRegions)
           case soft.KwExtension()
               if next.isAny[LeftParen, LeftBracket] &&
-                prevToken.isAny[StatSep, Indentation, LeftBrace] =>
+                prevToken.isAny[StatSep, Indentation, LeftBrace, RightArrow] =>
             currRef(RegionExtensionMark :: sepRegions)
           case _ => currRef(sepRegions)
         }


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/ExtensionMethodsSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/ExtensionMethodsSuite.scala
index 916573a73f..11c4b372e0 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/ExtensionMethodsSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/ExtensionMethodsSuite.scala
@@ -704,4 +704,120 @@ class ExtensionMethodsSuite extends BaseDottySuite {
     )
   }
 
+  test("#3231 1") {
+    runTestAssert[Stat](
+      """|object A {
+         |  self =>
+         |  extension (x: X)
+         |    @annoFoo
+         |    def foo: Foo =
+         |      getFoo
+         |
+         |    @annoBar
+         |    def bar: Bar =
+         |      getBar
+         |}
+         |""".stripMargin,
+      assertLayout = Some(
+        """|object A { self =>
+           |  extension (x: X){
+           |    @annoFoo def foo: Foo = getFoo
+           |    @annoBar def bar: Bar = getBar
+           |  }
+           |}
+           |""".stripMargin
+      )
+    )(
+      Defn.Object(
+        Nil,
+        tname("A"),
+        Template(
+          Nil,
+          Nil,
+          Self(tname("self"), None),
+          Defn.ExtensionGroup(
+            Nil,
+            List(List(tparam("x", "X"))),
+            Term.Block(
+              List(
+                Defn.Def(
+                  List(Mod.Annot(Init(pname("annoFoo"), Name.Anonymous(), Nil))),
+                  tname("foo"),
+                  Nil,
+                  Some(pname("Foo")),
+                  tname("getFoo")
+                ),
+                Defn.Def(
+                  List(Mod.Annot(Init(pname("annoBar"), Name.Anonymous(), Nil))),
+                  tname("bar"),
+                  Nil,
+                  Some(pname("Bar")),
+                  tname("getBar")
+                )
+              )
+            )
+          ) :: Nil,
+          Nil
+        )
+      )
+    )
+  }
+
+  test("#3231 2") {
+    runTestAssert[Stat](
+      """|object A {
+         |  self =>
+         |  extension (x: X)
+         |    private def foo: Foo =
+         |      getFoo
+         |
+         |    protected def bar: Bar =
+         |      getBar
+         |}
+         |""".stripMargin,
+      assertLayout = Some(
+        """|object A { self =>
+           |  extension (x: X){
+           |    private def foo: Foo = getFoo
+           |    protected def bar: Bar = getBar
+           |  }
+           |}
+           |""".stripMargin
+      )
+    )(
+      Defn.Object(
+        Nil,
+        tname("A"),
+        Template(
+          Nil,
+          Nil,
+          Self(tname("self"), None),
+          Defn.ExtensionGroup(
+            Nil,
+            List(List(tparam("x", "X"))),
+            Term.Block(
+              List(
+                Defn.Def(
+                  List(Mod.Private(Name.Anonymous())),
+                  tname("foo"),
+                  Nil,
+                  Some(pname("Foo")),
+                  tname("getFoo")
+                ),
+                Defn.Def(
+                  List(Mod.Protected(Name.Anonymous())),
+                  tname("bar"),
+                  Nil,
+                  Some(pname("Bar")),
+                  tname("getBar")
+                )
+              )
+            )
+          ) :: Nil,
+          Nil
+        )
+      )
+    )
+  }
+
 }