-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from mblink/PROD-838-scala-3-extends-syntax
Scala 3 extends syntax
- Loading branch information
Showing
7 changed files
with
225 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
.bsp | ||
*.DS_Store | ||
target | ||
.idea | ||
/project |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
scalafix/input/src/main/scala-3/fix/NoWithForExtends.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* | ||
rule = NoWithForExtends | ||
*/ | ||
package fix | ||
|
||
object NoWithForExtends { | ||
trait SuperA {} | ||
|
||
trait SuperB {} | ||
|
||
trait SuperC {} | ||
|
||
trait ChildA extends SuperA with SuperB {}/* assert: NoWithForExtends | ||
^^^^ | ||
The `with` keyword is unnecessary here, replace with a comma | ||
*/ | ||
|
||
trait ChildB extends SuperA, SuperB {} | ||
|
||
trait ChildC extends SuperA with SuperB with SuperC {}/* assert: NoWithForExtends | ||
^^^^ | ||
The `with` keyword is unnecessary here, replace with a comma | ||
*/ | ||
|
||
trait ChildD extends SuperA, SuperB, SuperC {} | ||
|
||
trait SuperWithParamA(a: Int) { | ||
val init = a | ||
} | ||
|
||
case class ChildE(a: Int) extends SuperWithParamA(a) | ||
// with comment | ||
with SuperB {}/* assert: NoWithForExtends | ||
^^^^ | ||
The `with` keyword is unnecessary here, replace with a comma | ||
*/ | ||
|
||
case class ChildF(a: Int) extends SuperWithParamA(a), | ||
// with comment | ||
SuperB {} | ||
|
||
object Outer { | ||
trait ChildG extends SuperA with SuperB {}/* assert: NoWithForExtends | ||
^^^^ | ||
The `with` keyword is unnecessary here, replace with a comma | ||
*/ | ||
|
||
trait ChildH extends SuperA, SuperB {} | ||
|
||
object Inner { | ||
trait Core {} | ||
} | ||
|
||
trait Mantle | ||
} | ||
|
||
trait WithParam[A] {} | ||
|
||
trait WithParamChildA extends WithParam[SuperA with SuperB] with SuperC {}/* assert: NoWithForExtends | ||
^^^^ | ||
The `with` keyword is unnecessary here, replace with a comma | ||
*/ | ||
|
||
trait WithParamChildB extends WithParam[SuperA with SuperB], SuperC {} | ||
|
||
trait DotAccessWith extends Outer.Inner.Core with Outer.Mantle {}/* assert: NoWithForExtends | ||
^^^^ | ||
The `with` keyword is unnecessary here, replace with a comma | ||
*/ | ||
|
||
trait DotAccessComma extends Outer.Inner.Core, Outer.Mantle {} | ||
} |
51 changes: 51 additions & 0 deletions
51
scalafix/output/src/main/scala-3/fix/NoWithForExtends.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package fix | ||
|
||
object NoWithForExtends { | ||
trait SuperA {} | ||
|
||
trait SuperB {} | ||
|
||
trait SuperC {} | ||
|
||
trait ChildA extends SuperA with SuperB {} | ||
|
||
trait ChildB extends SuperA, SuperB {} | ||
|
||
trait ChildC extends SuperA with SuperB with SuperC {} | ||
|
||
trait ChildD extends SuperA, SuperB, SuperC {} | ||
|
||
trait SuperWithParamA(a: Int) { | ||
val init = a | ||
} | ||
|
||
case class ChildE(a: Int) extends SuperWithParamA(a) | ||
// with comment | ||
with SuperB {} | ||
|
||
case class ChildF(a: Int) extends SuperWithParamA(a), | ||
// with comment | ||
SuperB {} | ||
|
||
object Outer { | ||
trait ChildG extends SuperA with SuperB {} | ||
|
||
trait ChildH extends SuperA, SuperB {} | ||
|
||
object Inner { | ||
trait Core {} | ||
} | ||
|
||
trait Mantle | ||
} | ||
|
||
trait WithParam[A] {} | ||
|
||
trait WithParamChildA extends WithParam[SuperA with SuperB] with SuperC {} | ||
|
||
trait WithParamChildB extends WithParam[SuperA with SuperB], SuperC {} | ||
|
||
trait DotAccessWith extends Outer.Inner.Core with Outer.Mantle {} | ||
|
||
trait DotAccessComma extends Outer.Inner.Core, Outer.Mantle {} | ||
} |
1 change: 1 addition & 0 deletions
1
scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
fix.NoUnnecessaryCase | ||
fix.StrictSubclassAccess | ||
fix.NoWithForExtends |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package fix | ||
|
||
import scalafix.v1._ | ||
|
||
import scala.meta._ | ||
import scala.reflect.ClassTag | ||
import scala.meta.tokens.Token.{KwExtends, KwWith, LeftBracket, LeftParen, RightBracket, RightParen, Whitespace, Dot, Comment} | ||
|
||
case class WithForExtends(position: Position) extends Diagnostic { | ||
override def message = "The `with` keyword is unnecessary here, replace with a comma" | ||
} | ||
|
||
class NoWithForExtends extends SyntacticRule("NoWithForExtends") { | ||
|
||
private def cleanPairedTokens[L <: Token : ClassTag, R <: Token : ClassTag](tlist: List[Token]): List[Token] = { | ||
@annotation.tailrec | ||
def recurseWithFlag(tlist: List[Token], acc: List[Token], flag: Int): List[Token] = { | ||
tlist match { | ||
case Nil => acc | ||
case (_: L) :: tail => recurseWithFlag(tail, acc, flag + 1) | ||
case (_ : R) :: tail => recurseWithFlag(tail, acc, flag - 1) | ||
case tok :: tail if flag == 0 => recurseWithFlag(tail, acc :+ tok, flag) | ||
case _ :: tail => recurseWithFlag(tail, acc, flag) | ||
} | ||
} | ||
|
||
recurseWithFlag(tlist, List(), 0) | ||
} | ||
|
||
private def cleanSingleToken[T <: Token : ClassTag](tlist: List[Token]): List[Token] = { | ||
@annotation.tailrec | ||
def recurseOnList(tlist: List[Token], acc: List[Token]): List[Token] = { | ||
tlist match { | ||
case Nil => acc | ||
case (_: T) :: tail => recurseOnList(tail, acc) | ||
case tok :: tail => recurseOnList(tail, acc :+ tok) | ||
} | ||
} | ||
|
||
recurseOnList(tlist, List()) | ||
} | ||
|
||
private def cleanDotAccesses(tlist: List[Token]): List[Token] = { | ||
@annotation.tailrec | ||
def recurseOnList(tlist: List[Token], acc: List[Token]): List[Token] = { | ||
tlist match { | ||
case Nil => acc | ||
case (_: Dot) :: _ :: tail => recurseOnList(tail, acc) | ||
case tok :: tail => recurseOnList(tail, acc :+ tok) | ||
} | ||
} | ||
recurseOnList(tlist, List()) | ||
} | ||
|
||
@annotation.tailrec | ||
private def containsSublist(list: List[Token]): Option[Token] = list match { | ||
case Nil => None | ||
case (_: KwExtends) :: _ :: (wth: KwWith) :: _ => Some(wth) | ||
case _ :: tail => containsSublist(tail) | ||
} | ||
|
||
private def traverseTree(tree: Tree): List[Tokens] = { | ||
@annotation.tailrec | ||
def recTreeAcc(tlist: List[Tree], acc: List[Tokens]): List[Tokens] = { | ||
tlist match { | ||
case Nil => acc | ||
case head :: tail => | ||
val toks = head.children.collect { | ||
case t: Template if t.inits.length > 1 => t.tokens | ||
} | ||
head.children match { | ||
case Nil => recTreeAcc(tail, acc ++ toks) | ||
case _ => recTreeAcc(head.children ++ tail, acc ++ toks) | ||
} | ||
} | ||
} | ||
|
||
recTreeAcc(tree.children, List()) | ||
} | ||
|
||
override def fix(implicit doc: SyntacticDocument): Patch = { | ||
traverseTree(doc.tree) | ||
.map(_.toList) | ||
.map(cleanPairedTokens[LeftParen, RightParen]) | ||
.map(cleanPairedTokens[LeftBracket, RightBracket]) | ||
.map(cleanSingleToken[Comment]) | ||
.map(cleanSingleToken[Whitespace]) | ||
.map(cleanDotAccesses) | ||
.map(containsSublist).collect { | ||
case Some(tok) => Patch.lint(WithForExtends(tok.pos)) | ||
}.asPatch | ||
} | ||
} |