I'm trying to rename the parameter of an anonymous function using a semantic scalafix plugin. The relevant code looks like this:
case Term.Apply(func, args) =>
args.collect { case Term.Block(List(Term.Function(List(arg), _))) =>
Patch.replaceTree(arg, arg.copy(name = Term.Name("components")).toString())
The problem is, this is changing { implicit foo =>
to { components =>
(i.e. it's dropping the implicit
modifier). I initially thought it was being dropped by the copy
method for some reason, but I added some println
s and that's not the case: the implicit
modifier exists on the copy, but just isn't being included in the toString
output. Anyone know what's going on here? And how I can get the implicit
to be included in the output?
println
s:
println("***********ORIGINAL***********")
println("toString:\t" + arg.toString())
println("name:\t\t" + arg.name)
println("modifiers:\t" + arg.mods)
println("syntax:\t\t" + arg.syntax)
println("structure:\t" + arg.structure)
println("***********COPY***********")
val copy = arg.copy(name = Term.Name("components"))
println("toString:\t" + copy.toString())
println("name:\t\t" + copy.name)
println("modifiers:\t" + copy.mods)
println("syntax:\t\t" + copy.syntax)
println("structure:\t" + copy.structure)
output:
***********ORIGINAL***********
toString: implicit app
name: app
modifiers: List(implicit)
syntax: implicit app
structure: Term.Param(List(Mod.Implicit), Term.Name("app"), None, None)
***********COPY***********
toString: components
name: components
modifiers: List(implicit)
syntax: components
structure: Term.Param(List(Mod.Implicit), Term.Name("components"), None, None)
(notice that the copy
has implicit
in its list of modifiers, but it doesn't show up in the outputs of toString
or syntax
)
The thing is that when Scalameta (4.5.13) prints a
Term.Param
it skipsMod.Implicit
andMod.Using
Then it prints
List[List[Term.Param]]
correctlybut this doesn't help us.
The easiest fix is just to add
implicit
when necessaryBecause Scalameta prints differently newly parsed trees and transformed/generated trees. For the former it preserves their original string representation with original formatting. For the latter it prints them with corresponding instance of
scala.meta.prettyprinters.Show
i.e. skipsimplicit
for a parameter etc.arg.toString
callsscala.meta.internal.prettyprinters.TreeSyntax.apply[Term.Param](Scala213).apply(arg)
.The method
TreeSyntax.apply
isHere in the pattern matching for
Origin.Parsed
(the origin of a newly parsed tree) the method returnsResult.Str
, forOrigin.None
(the origin of a transformed/generated tree) it returnsResult.Sequence
.The method
scala.meta.internal.trees.InternalTree#origin
isprivate[meta]
so if you play with it put your rule into the packagescala.meta
.Term.Param
is not a case class and.copy
is not a method of a case class.arg
andres
are actually instances of macro-generated classTerm.Param.TermParamImpl
.