From 22fcbcb2b2c1f3c3ca7fd6b5013bf70cd06de706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Mon, 25 Jun 2018 14:22:24 +0200 Subject: [PATCH 1/3] Rewrite Map.zip -> Map.zip.toMap --- .../input/src/main/scala/fix/SetMapSrc.scala | 1 + .../output/src/main/scala/fix/SetMapSrc.scala | 1 + .../Scalacollectioncompat_newcollections.scala | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/scalafix/input/src/main/scala/fix/SetMapSrc.scala b/scalafix/input/src/main/scala/fix/SetMapSrc.scala index 0597c513..b0758173 100644 --- a/scalafix/input/src/main/scala/fix/SetMapSrc.scala +++ b/scalafix/input/src/main/scala/fix/SetMapSrc.scala @@ -9,4 +9,5 @@ class SetMapSrc(set: Set[Int], map: Map[Int, Int]) { (set + (2, 3)).map(x => x) set + (2, 3) - 4 map.mapValues(_ + 1) + map.zip(List()) } \ 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 978b0bfa..2661ed49 100644 --- a/scalafix/output/src/main/scala/fix/SetMapSrc.scala +++ b/scalafix/output/src/main/scala/fix/SetMapSrc.scala @@ -9,4 +9,5 @@ class SetMapSrc(set: Set[Int], map: Map[Int, Int]) { (set + 2 + 3).map(x => x) set + 2 + 3 - 4 map.mapValues(_ + 1).toMap + map.zip(List()).toMap } \ 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 f58a0b11..02e48dcc 100644 --- a/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala +++ b/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala @@ -77,11 +77,17 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) Symbol("_root_.scala.collection.mutable.SetLike.retain.") ) + val arrayBuilderMake = SymbolMatcher.normalized( Symbol("_root_.scala.collection.mutable.ArrayBuilder.make(Lscala/reflect/ClassTag;)Lscala/collection/mutable/ArrayBuilder;.") ) + val mapZip = + SymbolMatcher.exact( + Symbol("_root_.scala.collection.IterableLike#zip(Lscala/collection/GenIterable;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object;.") + ) + def replaceMutableSet(ctx: RuleCtx) = ctx.tree.collect { case retainSet(n: Name) => @@ -254,10 +260,16 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) case ap @ Term.Apply(at @ Term.ApplyType(Term.Select(lhs, arrayBuilderMake(_)), args), Nil) => val extraParens = ap.tokens.slice(at.tokens.size, ap.tokens.size) - ctx.removeTokens(extraParens) }.asPatch } + + def replaceMapZip(ctx: RuleCtx): Patch = { + ctx.tree.collect { + case ap @ Term.Apply(Term.Select(_, mapZip(_)), List(_)) => + ctx.addRight(ap, ".toMap") + }.asPatch + } def replaceMapMapValues(ctx: RuleCtx): Patch = { ctx.tree.collect { @@ -280,7 +292,7 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) replaceMutMapUpdated(ctx) + replaceIterableSameElements(ctx) + replaceArrayBuilderMake(ctx) + + replaceMapZip(ctx) + replaceMapMapValues(ctx) - } } From 5af2308f1d652c6f7a0265fac14b71b7d94ce7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Mon, 25 Jun 2018 16:07:06 +0200 Subject: [PATCH 2/3] Rewrite Map.zip. make sure we target Map --- .../input/src/main/scala/fix/SetMapSrc.scala | 1 + .../output/src/main/scala/fix/SetMapSrc.scala | 1 + ...Scalacollectioncompat_newcollections.scala | 24 ++++++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/scalafix/input/src/main/scala/fix/SetMapSrc.scala b/scalafix/input/src/main/scala/fix/SetMapSrc.scala index b0758173..842b0eec 100644 --- a/scalafix/input/src/main/scala/fix/SetMapSrc.scala +++ b/scalafix/input/src/main/scala/fix/SetMapSrc.scala @@ -10,4 +10,5 @@ class SetMapSrc(set: Set[Int], map: Map[Int, Int]) { set + (2, 3) - 4 map.mapValues(_ + 1) map.zip(List()) + List().zip(List()) } \ 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 2661ed49..282b69f5 100644 --- a/scalafix/output/src/main/scala/fix/SetMapSrc.scala +++ b/scalafix/output/src/main/scala/fix/SetMapSrc.scala @@ -10,4 +10,5 @@ class SetMapSrc(set: Set[Int], map: Map[Int, Int]) { set + 2 + 3 - 4 map.mapValues(_ + 1).toMap map.zip(List()).toMap + List().zip(List()) } \ 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 02e48dcc..9fd776a5 100644 --- a/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala +++ b/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala @@ -8,6 +8,28 @@ import scala.meta._ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) extends SemanticRule(index, "Scalacollectioncompat_newcollections") { + // terms dont give us terms https://github.com/scalameta/scalameta/issues/1212 + // if we have a simple identifier, we can look at his definition at query it's type + // this should be improved in future version of scalameta + object TypeMatcher { + def apply(symbols: Symbol*)(implicit index: SemanticdbIndex): TypeMatcher = + new TypeMatcher(symbols: _*)(index) + } + + final class TypeMatcher(symbols: Symbol*)(implicit index: SemanticdbIndex) { + def unapply(tree: Tree): Boolean = { + index.denotation(tree) + .map(_.names.headOption.exists(n => symbols.exists(_ == n.symbol))) + .getOrElse(false) + } + } + + val CollectionMap: TypeMatcher = TypeMatcher( + Symbol("_root_.scala.collection.immutable.Map#"), + Symbol("_root_.scala.collection.mutable.Map#"), + Symbol("_root_.scala.Predef.Map#") + ) + def replaceSymbols(ctx: RuleCtx): Patch = { ctx.replaceSymbols( "scala.collection.LinearSeq" -> "scala.collection.immutable.List", @@ -266,7 +288,7 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) def replaceMapZip(ctx: RuleCtx): Patch = { ctx.tree.collect { - case ap @ Term.Apply(Term.Select(_, mapZip(_)), List(_)) => + case ap @ Term.Apply(Term.Select(CollectionMap(), mapZip(_)), List(_)) => ctx.addRight(ap, ".toMap") }.asPatch } From 9804a1685aa526a80a6f4cb3824f6885539900fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Mon, 25 Jun 2018 17:03:04 +0200 Subject: [PATCH 3/3] Rewrite: TypeMatcher warning about hack --- .../scala/fix/Scalacollectioncompat_newcollections.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala b/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala index 9fd776a5..65e66d75 100644 --- a/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala +++ b/scalafix/rules/src/main/scala/fix/Scalacollectioncompat_newcollections.scala @@ -8,7 +8,8 @@ import scala.meta._ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) extends SemanticRule(index, "Scalacollectioncompat_newcollections") { - // terms dont give us terms https://github.com/scalameta/scalameta/issues/1212 + // WARNING: TOTAL HACK + // this is only to unblock us until Term.tpe is available: https://github.com/scalameta/scalameta/issues/1212 // if we have a simple identifier, we can look at his definition at query it's type // this should be improved in future version of scalameta object TypeMatcher { @@ -19,8 +20,7 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) final class TypeMatcher(symbols: Symbol*)(implicit index: SemanticdbIndex) { def unapply(tree: Tree): Boolean = { index.denotation(tree) - .map(_.names.headOption.exists(n => symbols.exists(_ == n.symbol))) - .getOrElse(false) + .exists(_.names.headOption.exists(n => symbols.exists(_ == n.symbol))) } }