diff --git a/scalafix/input/src/main/scala/fix/SetMapSrc.scala b/scalafix/input/src/main/scala/fix/SetMapSrc.scala index 0597c513..842b0eec 100644 --- a/scalafix/input/src/main/scala/fix/SetMapSrc.scala +++ b/scalafix/input/src/main/scala/fix/SetMapSrc.scala @@ -9,4 +9,6 @@ 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()) + 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 978b0bfa..282b69f5 100644 --- a/scalafix/output/src/main/scala/fix/SetMapSrc.scala +++ b/scalafix/output/src/main/scala/fix/SetMapSrc.scala @@ -9,4 +9,6 @@ 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 + 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 f58a0b11..65e66d75 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") { + // 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 { + 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) + .exists(_.names.headOption.exists(n => symbols.exists(_ == n.symbol))) + } + } + + 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", @@ -77,11 +99,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 +282,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(CollectionMap(), mapZip(_)), List(_)) => + ctx.addRight(ap, ".toMap") + }.asPatch + } def replaceMapMapValues(ctx: RuleCtx): Patch = { ctx.tree.collect { @@ -280,7 +314,7 @@ case class Scalacollectioncompat_newcollections(index: SemanticdbIndex) replaceMutMapUpdated(ctx) + replaceIterableSameElements(ctx) + replaceArrayBuilderMake(ctx) + + replaceMapZip(ctx) + replaceMapMapValues(ctx) - } }