Skip to content

Commit 2aef942

Browse files
Rewrite collection.{Map, Set}.+ and collection.Set.-
This is incomplete since, it's blocked by scalameta/scalameta#1212 (Add support to query type of a term) iset: immutable.Set[Int] cset: collecion.Set[Int] both have +/- implemented via SetLike given iset + 1 cset + 1 we know that + is from SetLike, but it's not possible to get the type of iset/cset Rewrite collection.Set.+ restrict type of lhs scalafix allow us to match on SetLike.+ but we cannot check the type of the expression on the lhs We can work arround this limitation if the lhs is a identifier (simple case). This allow us to document the expected type on the lhs and prepare the implementation once scalameta/scalameta#1212 is resolved
1 parent a69a407 commit 2aef942

File tree

3 files changed

+91
-15
lines changed

3 files changed

+91
-15
lines changed

scalafix/input/src/main/scala/fix/SetMapSrc.scala

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,27 @@ rule = "scala:fix.Scalacollectioncompat_newcollections"
33
*/
44
package fix
55

6-
class SetMapSrc(set: Set[Int], map: Map[Int, Int]) {
7-
set + (2, 3)
8-
map + (2 -> 3, 3 -> 4)
9-
(set + (2, 3)).map(x => x)
10-
set + (2, 3) - 4
11-
map.mapValues(_ + 1)
12-
map.zip(List())
6+
import scala.collection
7+
import scala.collection.immutable
8+
import scala.collection.mutable.{Map, Set} // Challenge to make sure the scoping is correct
9+
10+
class SetMapSrc(iset: immutable.Set[Int],
11+
cset: collection.Set[Int],
12+
imap: immutable.Map[Int, Int],
13+
cmap: collection.Map[Int, Int]) {
14+
iset + (2, 3)
15+
imap + (2 -> 3, 3 -> 4)
16+
(iset + (2, 3)).toString
17+
iset + (2, 3) - 4
18+
imap.mapValues(_ + 1)
19+
iset + 1
20+
iset - 2
21+
cset + 1
22+
cset - 2
23+
cmap + (2 -> 3)
24+
cmap + ((4, 5))
25+
imap + (2 -> 3)
26+
imap + ((4, 5))
27+
imap.zip(List())
1328
List().zip(List())
1429
}

scalafix/output/src/main/scala/fix/SetMapSrc.scala

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,27 @@
33

44
package fix
55

6-
class SetMapSrc(set: Set[Int], map: Map[Int, Int]) {
7-
set + 2 + 3
8-
map + (2 -> 3) + (3 -> 4)
9-
(set + 2 + 3).map(x => x)
10-
set + 2 + 3 - 4
11-
map.mapValues(_ + 1).toMap
12-
map.zip(List()).toMap
6+
import scala.collection
7+
import scala.collection.immutable
8+
import scala.collection.mutable.{Map, Set} // Challenge to make sure the scoping is correct
9+
10+
class SetMapSrc(iset: immutable.Set[Int],
11+
cset: collection.Set[Int],
12+
imap: immutable.Map[Int, Int],
13+
cmap: collection.Map[Int, Int]) {
14+
iset + 2 + 3
15+
imap + (2 -> 3) + (3 -> 4)
16+
(iset + 2 + 3).toString
17+
iset + 2 + 3 - 4
18+
imap.mapValues(_ + 1).toMap
19+
iset + 1
20+
iset - 2
21+
cset ++ _root_.scala.collection.Set(1)
22+
cset -- _root_.scala.collection.Set(2)
23+
cmap ++ _root_.scala.collection.Map(2 -> 3)
24+
cmap ++ _root_.scala.collection.Map((4, 5))
25+
imap + (2 -> 3)
26+
imap + ((4, 5))
27+
imap.zip(List()).toMap
1328
List().zip(List())
1429
}

scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex)
4949
Symbol("_root_.scala.Predef.Map#")
5050
)
5151

52+
val CollectionSet: TypeMatcher = TypeMatcher(Symbol("_root_.scala.collection.Set#"))
53+
5254
def replaceSymbols(ctx: RuleCtx): Patch = {
5355
ctx.replaceSymbols(
5456
"scala.collection.LinearSeq" -> "scala.collection.immutable.List",
@@ -86,6 +88,18 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex)
8688
Symbol("_root_.scala.runtime.Tuple2Zipped.Ops.zipped."),
8789
Symbol("_root_.scala.runtime.Tuple3Zipped.Ops.zipped.")
8890
)
91+
val setPlus =
92+
SymbolMatcher.exact(
93+
Symbol("_root_.scala.collection.SetLike#`+`(Ljava/lang/Object;)Lscala/collection/Set;.")
94+
)
95+
val setMinus =
96+
SymbolMatcher.exact(
97+
Symbol("_root_.scala.collection.SetLike#`-`(Ljava/lang/Object;)Lscala/collection/Set;.")
98+
)
99+
val mapPlus =
100+
SymbolMatcher.exact(
101+
Symbol("_root_.scala.collection.MapLike#`+`(Lscala/Tuple2;)Lscala/collection/Map;.")
102+
)
89103
val setPlus2 = SymbolMatcher.exact(
90104
Symbol("_root_.scala.collection.SetLike#`+`(Ljava/lang/Object;Ljava/lang/Object;Lscala/collection/Seq;)Lscala/collection/Set;.")
91105
)
@@ -144,6 +158,9 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex)
144158
Symbol("_root_.scala.collection.IterableLike#zip(Lscala/collection/GenIterable;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object;.")
145159
)
146160

161+
def startsWithParens(tree: Tree): Boolean =
162+
tree.tokens.headOption.map(_.is[Token.LeftParen]).getOrElse(false)
163+
147164
def replaceMutableSet(ctx: RuleCtx) =
148165
ctx.tree.collect {
149166
case retainSet(n: Name) =>
@@ -245,7 +262,7 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex)
245262
def replaceSetMapPlus2(ctx: RuleCtx): Patch = {
246263
def rewritePlus(ap: Term.ApplyInfix, lhs: Term, op: Term.Name, rhs1: Term, rhs2: Term): Patch = {
247264
val tokensToReplace =
248-
if(ap.tokens.headOption.map(_.is[Token.LeftParen]).getOrElse(false)) {
265+
if(startsWithParens(ap)) {
249266
// don't drop surrounding parens
250267
ap.tokens.slice(1, ap.tokens.size - 1)
251268
} else ap.tokens
@@ -270,6 +287,34 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex)
270287
}.asPatch
271288
}
272289

290+
def replaceSetMapPlusMinus(ctx: RuleCtx): Patch = {
291+
def rewriteOp(op: Tree, rhs: Tree, doubleOp: String, col0: String): Patch = {
292+
val col = "_root_.scala.collection." + col0
293+
val callSite =
294+
if (startsWithParens(rhs)) {
295+
ctx.addLeft(rhs, col)
296+
}
297+
else {
298+
ctx.addLeft(rhs, col + "(") +
299+
ctx.addRight(rhs, ")")
300+
}
301+
302+
ctx.addRight(op, doubleOp) + callSite
303+
}
304+
305+
ctx.tree.collect {
306+
case Term.ApplyInfix(CollectionSet(), op @ setPlus(_), Nil, List(rhs)) =>
307+
rewriteOp(op, rhs, "+", "Set")
308+
309+
case Term.ApplyInfix(CollectionSet(), op @ setMinus(_), Nil, List(rhs)) =>
310+
rewriteOp(op, rhs, "-", "Set")
311+
312+
case Term.ApplyInfix(_, op @ mapPlus(_), Nil, List(rhs)) =>
313+
rewriteOp(op, rhs, "+", "Map")
314+
}.asPatch
315+
}
316+
317+
273318
def replaceMutSetMapPlus(ctx: RuleCtx): Patch = {
274319
def rewriteMutPlus(lhs: Term, op: Term.Name): Patch = {
275320
ctx.addRight(lhs, ".clone()") +
@@ -517,6 +562,7 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex)
517562
replaceMutableSet(ctx) +
518563
replaceSymbolicFold(ctx) +
519564
replaceSetMapPlus2(ctx) +
565+
replaceSetMapPlusMinus(ctx) +
520566
replaceMutSetMapPlus(ctx) +
521567
replaceMutMapUpdated(ctx) +
522568
replaceArrayBuilderMake(ctx) +

0 commit comments

Comments
 (0)