@@ -4,10 +4,20 @@ import scalafix._
4
4
import scalafix .util ._
5
5
import scala .meta ._
6
6
7
+ import scala .collection .mutable
8
+
9
+ trait CrossCompatibility {
10
+ def isCrossCompatible : Boolean
11
+ }
12
+
7
13
// 2.12 Cross-Compatible
8
- trait Stable212Base { self : SemanticRule =>
14
+ trait Stable212Base extends CrossCompatibility { self : SemanticRule =>
15
+
16
+ // Two rules triggers the same rewrite TraversableLike.to and CanBuildFrom
17
+ // we keep track of what is handled in CanBuildFrom and guard against TraversableLike.to
18
+ val handledTo = mutable.Set [Tree ]()
9
19
10
- // == Symbols ==
20
+ // == Symbols ==
11
21
def foldSymbol (isLeft : Boolean ): SymbolMatcher = {
12
22
val op =
13
23
if (isLeft) " /:"
@@ -16,9 +26,11 @@ trait Stable212Base { self: SemanticRule =>
16
26
normalized(s " _root_.scala.collection.TraversableOnce.` $op`. " )
17
27
}
18
28
29
+ val iterator = normalized(" _root_.scala.collection.TraversableLike.toIterator." )
19
30
val toTpe = normalized(" _root_.scala.collection.TraversableLike.to." )
20
31
val copyToBuffer = normalized(" _root_.scala.collection.TraversableOnce.copyToBuffer." )
21
32
val arrayBuilderMake = normalized(" _root_.scala.collection.mutable.ArrayBuilder.make(Lscala/reflect/ClassTag;)Lscala/collection/mutable/ArrayBuilder;." )
33
+ val iterableSameElement = exact(" _root_.scala.collection.IterableLike#sameElements(Lscala/collection/GenIterable;)Z." )
22
34
val collectionCanBuildFrom = exact(" _root_.scala.collection.generic.CanBuildFrom#" )
23
35
val collectionCanBuildFromImport = exact(" _root_.scala.collection.generic.CanBuildFrom.;_root_.scala.collection.generic.CanBuildFrom#" )
24
36
val nothing = exact(" _root_.scala.Nothing#" )
@@ -30,14 +42,48 @@ trait Stable212Base { self: SemanticRule =>
30
42
val foldLeftSymbol = foldSymbol(isLeft = true )
31
43
val foldRightSymbol = foldSymbol(isLeft = false )
32
44
45
+ val traversable = exact(
46
+ " _root_.scala.package.Traversable#" ,
47
+ " _root_.scala.collection.Traversable#" ,
48
+ " _root_.scala.package.Iterable#" ,
49
+ " _root_.scala.collection.Iterable#"
50
+ )
51
+
33
52
// == Rules ==
34
53
54
+ def replaceIterableSameElements (ctx : RuleCtx ): Patch = {
55
+ ctx.tree.collect {
56
+ case Term .Apply (Term .Select (lhs, iterableSameElement(_)), List (_)) =>
57
+ ctx.addRight(lhs, " .iterator" )
58
+ }.asPatch
59
+ }
60
+
61
+
35
62
def replaceSymbols0 (ctx : RuleCtx ): Patch = {
36
- ctx.replaceSymbols(
37
- " scala.collection.LinearSeq" -> " scala.collection.immutable.List" ,
38
- " scala.Traversable" -> " scala.Iterable" ,
39
- " scala.collection.Traversable" -> " scala.collection.Iterable"
40
- )
63
+ val traversableToIterable =
64
+ ctx.replaceSymbols(
65
+ " scala.Traversable" -> " scala.Iterable" ,
66
+ " scala.collection.Traversable" -> " scala.collection.Iterable"
67
+ )
68
+
69
+ val linearSeqToList =
70
+ ctx.replaceSymbols(
71
+ " scala.collection.LinearSeq" -> " scala.collection.immutable.List" ,
72
+ )
73
+
74
+ import scala .meta .contrib ._
75
+ val hasTraversable =
76
+ ctx.tree.exists {
77
+ case traversable(_) => true
78
+ case _ => false
79
+
80
+ }
81
+
82
+ val compatImport =
83
+ if (hasTraversable) addCompatImport(ctx)
84
+ else Patch .empty
85
+
86
+ traversableToIterable + linearSeqToList + compatImport
41
87
}
42
88
43
89
def replaceSymbolicFold (ctx : RuleCtx ): Patch = {
@@ -123,7 +169,7 @@ trait Stable212Base { self: SemanticRule =>
123
169
val useSites =
124
170
ctx.tree.collect {
125
171
case Defn .Def (_, _, _, paramss, _, body) =>
126
- CanBuildFromNothing (paramss, body, ctx, collectionCanBuildFrom, nothing, toTpe) +
172
+ CanBuildFromNothing (paramss, body, ctx, collectionCanBuildFrom, nothing, toTpe, handledTo ) +
127
173
CanBuildFrom (paramss, body, ctx, collectionCanBuildFrom, nothing)
128
174
}.asPatch
129
175
@@ -133,22 +179,41 @@ trait Stable212Base { self: SemanticRule =>
133
179
ctx.removeImportee(i)
134
180
}.asPatch
135
181
136
- val compatImport =
137
- ctx.addGlobalImport(importer " scala.collection.compat._ " )
182
+ val compatImport = addCompatImport(ctx)
138
183
139
184
if (useSites.nonEmpty) useSites + imports + compatImport
140
185
else Patch .empty
141
186
}
142
187
188
+ def replaceToList (ctx : RuleCtx ): Patch = {
189
+ ctx.tree.collect {
190
+ case iterator(t : Name ) =>
191
+ ctx.replaceTree(t, " iterator" )
192
+
193
+ case t @ toTpe(n : Name ) if ! handledTo.contains(n) =>
194
+ trailingBrackets(n, ctx).map { case (open, close) =>
195
+ ctx.replaceToken(open, " (" ) + ctx.replaceToken(close, " )" )
196
+ }.asPatch
197
+ }.asPatch
198
+ }
199
+
200
+
201
+ def addCompatImport (ctx : RuleCtx ): Patch = {
202
+ if (isCrossCompatible) ctx.addGlobalImport(importer " scala.collection.compat._ " )
203
+ else Patch .empty
204
+ }
205
+
143
206
override def fix (ctx : RuleCtx ): Patch = {
144
207
replaceSymbols0(ctx) +
145
208
replaceCanBuildFrom(ctx) +
209
+ replaceToList(ctx) +
146
210
replaceCopyToBuffer(ctx) +
147
211
replaceSymbolicFold(ctx) +
148
212
replaceSetMapPlus2(ctx) +
149
213
replaceMutSetMapPlus(ctx) +
150
214
replaceMutMapUpdated(ctx) +
151
- replaceArrayBuilderMake(ctx)
215
+ replaceArrayBuilderMake(ctx) +
216
+ replaceIterableSameElements(ctx)
152
217
}
153
218
154
219
}
0 commit comments