From 07db055e744366dbeb8b0e375a5b90aff0781cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Fri, 22 Jun 2018 16:54:21 +0200 Subject: [PATCH 1/2] Rewrite `immutable.Set/Map`: the `+` operation no longer has an overload accepting multiple values --- .../input/src/main/scala/fix/SetMapSrc.scala | 9 ++++++ .../output/src/main/scala/fix/SetMapSrc.scala | 9 ++++++ ...Scalacollectioncompat_newcollections.scala | 32 ++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 scalafix/input/src/main/scala/fix/SetMapSrc.scala create mode 100644 scalafix/output/src/main/scala/fix/SetMapSrc.scala diff --git a/scalafix/input/src/main/scala/fix/SetMapSrc.scala b/scalafix/input/src/main/scala/fix/SetMapSrc.scala new file mode 100644 index 00000000..c521e18d --- /dev/null +++ b/scalafix/input/src/main/scala/fix/SetMapSrc.scala @@ -0,0 +1,9 @@ +/* +rule = "scala:fix.Scalacollectioncompat_newcollections" + */ +package fix + +class SetMapSrc(set: Set[Int], map: Map[Int, Int]) { + set + (2, 3) + map + (2 -> 3, 3 -> 4) +} \ No newline at end of file diff --git a/scalafix/output/src/main/scala/fix/SetMapSrc.scala b/scalafix/output/src/main/scala/fix/SetMapSrc.scala new file mode 100644 index 00000000..6cecf73a --- /dev/null +++ b/scalafix/output/src/main/scala/fix/SetMapSrc.scala @@ -0,0 +1,9 @@ + + + +package fix + +class SetMapSrc(set: Set[Int], map: Map[Int, Int]) { + set + 2 + 3 + map + (2 -> 3) + (3 -> 4) +} \ No newline at end of file diff --git a/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala b/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala index a310662f..020d3220 100644 --- a/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala +++ b/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala @@ -29,6 +29,13 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) Symbol("_root_.scala.runtime.Tuple2Zipped.Ops.zipped."), Symbol("_root_.scala.runtime.Tuple3Zipped.Ops.zipped.") ) + val setPlus2 = SymbolMatcher.exact( + Symbol("_root_.scala.collection.SetLike#`+`(Ljava/lang/Object;Ljava/lang/Object;Lscala/collection/Seq;)Lscala/collection/Set;.") + ) + val mapPlus2 = SymbolMatcher.exact( + Symbol("_root_.scala.collection.immutable.MapLike#`+`(Lscala/Tuple2;Lscala/Tuple2;Lscala/collection/Seq;)Lscala/collection/immutable/Map;.") + ) + def foldSymbol(isLeft: Boolean): SymbolMatcher = { val op = if (isLeft) "/:" @@ -156,6 +163,28 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) ctx.replaceTree(t, "lazyAppendedAll") }.asPatch + def replaceSetMapPlus2(ctx: RuleCtx): Patch = { + def rewritePlus(ap: Term.ApplyInfix, lhs: Term, op: Term.Name, rhs1: Term, rhs2: Term): Patch = { + ctx.replaceTree( + ap, + Term.ApplyInfix( + Term.ApplyInfix(lhs, op, Nil, List(rhs1)), + op, + Nil, + List(rhs2) + ).toString + ) + } + + ctx.tree.collect { + case ap @ Term.ApplyInfix(lhs, op @ mapPlus2(_), _, List(a, b)) => + rewritePlus(ap, lhs, op, a, b) + + case ap @ Term.ApplyInfix(lhs, op @ setPlus2(_), _, List(a, b)) => + rewritePlus(ap, lhs, op, a, b) + }.asPatch + } + override def fix(ctx: RuleCtx): Patch = { // println(ctx.index.database) @@ -166,6 +195,7 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) replaceStreamAppend(ctx) + replaceMutableMap(ctx) + replaceMutableSet(ctx) + - replaceSymbolicFold(ctx) + replaceSymbolicFold(ctx) + + replaceSetMapPlus2(ctx) } } From 4c51cf37d48c9bf649565736c5b7b3d32eccfb23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Fri, 22 Jun 2018 17:36:21 +0200 Subject: [PATCH 2/2] Rewrite `immutable.Set/Map.+` corner case --- .../input/src/main/scala/fix/SetMapSrc.scala | 2 ++ .../output/src/main/scala/fix/SetMapSrc.scala | 2 ++ .../Scalacollectioncompat_newcollections.scala | 16 ++++++++++++---- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/scalafix/input/src/main/scala/fix/SetMapSrc.scala b/scalafix/input/src/main/scala/fix/SetMapSrc.scala index c521e18d..c894923e 100644 --- a/scalafix/input/src/main/scala/fix/SetMapSrc.scala +++ b/scalafix/input/src/main/scala/fix/SetMapSrc.scala @@ -6,4 +6,6 @@ package fix class SetMapSrc(set: Set[Int], map: Map[Int, Int]) { set + (2, 3) map + (2 -> 3, 3 -> 4) + (set + (2, 3)).map(x => x) + set + (2, 3) - 4 } \ No newline at end of file diff --git a/scalafix/output/src/main/scala/fix/SetMapSrc.scala b/scalafix/output/src/main/scala/fix/SetMapSrc.scala index 6cecf73a..d2de35de 100644 --- a/scalafix/output/src/main/scala/fix/SetMapSrc.scala +++ b/scalafix/output/src/main/scala/fix/SetMapSrc.scala @@ -6,4 +6,6 @@ package fix class SetMapSrc(set: Set[Int], map: Map[Int, Int]) { set + 2 + 3 map + (2 -> 3) + (3 -> 4) + (set + 2 + 3).map(x => x) + set + 2 + 3 - 4 } \ No newline at end of file diff --git a/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala b/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala index 020d3220..40579b3a 100644 --- a/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala +++ b/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala @@ -165,15 +165,23 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) def replaceSetMapPlus2(ctx: RuleCtx): Patch = { def rewritePlus(ap: Term.ApplyInfix, lhs: Term, op: Term.Name, rhs1: Term, rhs2: Term): Patch = { - ctx.replaceTree( - ap, + + val tokensToReplace = + if(ap.tokens.headOption.map(_.is[Token.LeftParen]).getOrElse(false)) { + // don't drop surrounding parens + ap.tokens.slice(1, ap.tokens.size - 1) + } else ap.tokens + + val newTree = Term.ApplyInfix( Term.ApplyInfix(lhs, op, Nil, List(rhs1)), op, Nil, List(rhs2) - ).toString - ) + ).syntax + + ctx.removeTokens(tokensToReplace) + + tokensToReplace.headOption.map(x => ctx.addRight(x, newTree)) } ctx.tree.collect {