Skip to content
This repository was archived by the owner on Sep 3, 2020. It is now read-only.

Commit 2baf089

Browse files
committed
Implement methods not only from the selected template but also from its ancestry.
1 parent 2cc2155 commit 2baf089

File tree

2 files changed

+137
-8
lines changed

2 files changed

+137
-8
lines changed

src/main/scala/scala/tools/refactoring/implementations/ImplementMethods.scala

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,47 @@ abstract class ImplementMethods extends MultiStageRefactoring with analysis.Inde
3535
}
3636
}
3737

38+
private def templateAncestry(template: Template): List[Template] =
39+
template :: {
40+
for {
41+
parent <- template.parents
42+
parentImp <- index.declaration(parent.symbol).toList collect {
43+
case ClassDef(_, _, _, impl) => impl
44+
}
45+
ancestor <- templateAncestry(parentImp)
46+
} yield ancestor
47+
}
48+
3849
override def prepare(s: Selection): Either[PreparationError, PreparationResult] = {
3950

4051

4152
// Expand the selection to the concrete type when a kind was initially selected.
4253
val maybeSelectedTemplate = (s::s.expandToNextEnclosingTree.toList) flatMap { sel: Selection =>
4354
index.declaration(sel.enclosingTree.symbol)
4455
} collectFirst {
45-
case templateDeclaration: ClassDef => templateDeclaration
56+
case templateDeclaration: ClassDef => templateDeclaration.impl
4657
}
4758

4859
// Get a sequence of methods found in the selected mixed trait.
49-
val methodsToImplement = for {
50-
selectedTemplateDeclaration <- maybeSelectedTemplate.toList
51-
unimplementedMethod <- selectedTemplateDeclaration.impl.body collect {
52-
case methodDeclaration: DefDef if methodDeclaration.rhs.isEmpty =>
53-
methodDeclaration
54-
}
55-
} yield unimplementedMethod
60+
val methodsToImplement = {
61+
62+
val rawList = for {
63+
selectedTemplate <- maybeSelectedTemplate.toList
64+
selectedDeclaration <- templateAncestry(selectedTemplate)
65+
unimplementedMethod <- selectedDeclaration.body collect {
66+
case methodDeclaration: DefDef if methodDeclaration.rhs.isEmpty =>
67+
methodDeclaration
68+
}
69+
} yield unimplementedMethod;
70+
71+
val (uniqueMethods, _) =
72+
rawList.foldRight((List.empty[DefDef], Set.empty[OverloadedMethod])) {
73+
case (method, (l, visited)) if !visited.contains(method) =>
74+
(method::l, visited + method)
75+
case (_, st) => st
76+
}
77+
uniqueMethods
78+
}
5679

5780
// Use the selection to find the template where the methods should be implemented.
5881
val targetTemplate = s.expandToNextEnclosingTree.flatMap {

src/test/scala/scala/tools/refactoring/tests/implementations/ImplementMethodsTest.scala

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,4 +223,110 @@ class ImplementMethodsTest extends TestHelper with TestRefactoring {
223223
} applyRefactoring implementMethods
224224

225225

226+
@Test
227+
def implementMethodFromAncestry() = new FileSet() {
228+
"""
229+
|package implementMethods
230+
|
231+
|trait R {
232+
| def k: Unit
233+
|}
234+
|
235+
|trait T {
236+
| def f(x: Int): String
237+
|}
238+
|
239+
|trait S extends T {
240+
| def g(x: Int): Int
241+
|}
242+
|
243+
|object Obj extends /*(*/S/*)*/ with R {
244+
| val x: Int = ???
245+
|}
246+
""".stripMargin becomes
247+
"""
248+
|package implementMethods
249+
|
250+
|trait R {
251+
| def k: Unit
252+
|}
253+
|
254+
|trait T {
255+
| def f(x: Int): String
256+
|}
257+
|
258+
|trait S extends T {
259+
| def g(x: Int): Int
260+
|}
261+
|
262+
|object Obj extends /*(*/S/*)*/ with R {
263+
| val x: Int = ???
264+
|
265+
| def g(x: Int): Int = {
266+
| ???
267+
| }
268+
|
269+
| def f(x: Int): String = {
270+
| ???
271+
| }
272+
|}
273+
""".stripMargin
274+
275+
} applyRefactoring implementMethods
276+
277+
@Test
278+
def implementMethodFromCyclicAncestry() = new FileSet() {
279+
"""
280+
|package implementMethods
281+
|
282+
|trait R {
283+
| def k: Unit
284+
|}
285+
|
286+
|trait T extends R {
287+
| def f(x: Int): String
288+
|}
289+
|
290+
|trait S extends T with R {
291+
| def g(x: Int): Int
292+
|}
293+
|
294+
|object Obj extends /*(*/S/*)*/ with R {
295+
| val x: Int = ???
296+
|}
297+
""".stripMargin becomes
298+
"""
299+
|package implementMethods
300+
|
301+
|trait R {
302+
| def k: Unit
303+
|}
304+
|
305+
|trait T extends R {
306+
| def f(x: Int): String
307+
|}
308+
|
309+
|trait S extends T with R {
310+
| def g(x: Int): Int
311+
|}
312+
|
313+
|object Obj extends /*(*/S/*)*/ with R {
314+
| val x: Int = ???
315+
|
316+
| def g(x: Int): Int = {
317+
| ???
318+
| }
319+
|
320+
| def f(x: Int): String = {
321+
| ???
322+
| }
323+
|
324+
| def k: Unit = {
325+
| ???
326+
| }
327+
|}
328+
""".stripMargin
329+
330+
} applyRefactoring implementMethods
331+
226332
}

0 commit comments

Comments
 (0)