首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么scala.meta.Term.Param#toString删除修饰符?

为什么scala.meta.Term.Param#toString删除修饰符?
EN

Stack Overflow用户
提问于 2022-03-25 16:19:01
回答 1查看 64关注 0票数 1

我试图用语义scalafix插件重命名匿名函数的参数。相关代码如下:

代码语言:javascript
复制
  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())

问题是,这正在将{ implicit foo =>更改为{ components => (也就是说,它正在删除implicit修饰符)。我最初以为copy方法出于某种原因而删除了它,但我添加了一些println,但事实并非如此:副本上存在implicit修饰符,但是没有包含在toString输出中。有人知道这是怎么回事吗?以及如何将implicit包括在输出中?

printlns:

代码语言:javascript
复制
      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)

产出:

代码语言:javascript
复制
***********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)

(注意,copy在其修饰符列表中包含了implicit,但它没有显示在toStringsyntax的输出中)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-13 15:38:20

问题是,当Scalameta (4.5.13)打印一个Term.Param时,它是跳绳 Mod.ImplicitMod.Using

代码语言:javascript
复制
  case t: Term.Param =>
    // NOTE: `implicit/using` in parameters is skipped as it applies to whole list
    printParam(t, t.mods.filterNot(x => x.is[Mod.Implicit] || x.is[Mod.Using]))

然后打印List[List[Term.Param]] 正确无误

代码语言:javascript
复制
implicit def syntaxParamss: Syntax[List[List[Term.Param]]] = Syntax { paramss =>
  def usingImplicit(params: List[Term.Param]): Show.Result = {
    if (params.exists(_.mods.exists(_.is[Mod.Using])))
      s("using ", r(params, ", "))
    else
      w("implicit ", r(params, ", "), params.exists(_.mods.exists(_.is[Mod.Implicit])))
  }
  r(
    paramss.map(params => {
      s(
        "(",
        usingImplicit(params),
        ")"
      )
    }),
    ""
  )
}

但这帮不了我们。

最简单的解决方法是在必要时添加implicit

代码语言:javascript
复制
doc.tree.collect {
  case Term.Apply(func, args) =>
    args.collect {
      case Term.Block(List(Term.Function(List(arg), _))) =>
        val res = arg.copy(name = Term.Name("components"))
        val prefix = if (res.mods.exists(_.is[Mod.Implicit])) "implicit " else ""
        Patch.replaceTree(arg, prefix + res.toString)
    }.asPatch
}.asPatch

为什么它是印在原稿上,而不是在副本里

因为Scalameta打印的是不同的新解析树和转换/生成的树。对于前者,它用原始格式保留它们的原始字符串表示形式。对于后者,它使用相应的scala.meta.prettyprinters.Show实例打印它们,即跳过参数的implicit等。

arg.toString打电话给scala.meta.internal.prettyprinters.TreeSyntax.apply[Term.Param](Scala213).apply(arg)

方法 TreeSyntax.apply

代码语言:javascript
复制
def apply[T <: Tree](dialect: Dialect): Syntax[T] = {
  // NOTE: This is the current state of the art of smart prettyprinting.
  // If we prettyprint a tree that's just been parsed with the same dialect,
  // then we retain formatting. Otherwise, we don't, even in the tiniest.
  // I expect to improve on this in the nearest future, because we had it much better until recently.
  Syntax { (x: T) =>
    x.origin match {
      // NOTE: Options don't really matter,
      // because if we've parsed a tree, it's not gonna contain lazy seqs anyway.
      // case Origin.Parsed(_, originalDialect, _) if dialect == originalDialect && options == Options.Eager =>
      case o @ Origin.Parsed(_, `dialect`, _) => s(o.position.text)
      case _ => reprint(x)(dialect)
    }
  }
}

Origin.Parsed (新解析树的起源)的模式匹配中,该方法返回Result.Str,对于Origin.None (转换/生成树的起源),它返回Result.Sequence

代码语言:javascript
复制
println(arg) // implicit y: Boolean
println(arg.structure) // Term.Param(List(Mod.Implicit), Term.Name("y"), Some(Type.Name("Boolean")), None)
println(arg.getClass) // class scala.meta.Term$Param$TermParamImpl
println(arg.origin) // Parsed(Input.VirtualFile("fix/Scalafixdemo.scala", "... implicit y: Boolean => ..."),Scala213,TokenStreamPosition(45,51))
println(TreeSyntax.apply[Term.Param](Scala213).apply(arg).getClass) 
// class scala.meta.prettyprinters.Show$Str

val res = arg.copy(name = Term.Name("components"))
println(res) // components: Boolean
println(res.structure) // Term.Param(List(Mod.Implicit), Term.Name("components"), Some(Type.Name("Boolean")), None)
println(res.getClass) // class scala.meta.Term$Param$TermParamImpl
println(res.origin) // None
println(TreeSyntax.apply[Term.Param](Scala213).apply(res).getClass) 
// class scala.meta.prettyprinters.Show$Sequence

方法scala.meta.internal.trees.InternalTree#originprivate[meta],所以如果您使用它,将规则放入包scala.meta中。

Term.Param不是case类,.copy不是case类的方法。argres实际上是宏生成的类Term.Param.TermParamImpl的实例。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71620106

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档