【问题标题】:Scalafix: resolving object apply methodScalafix:解析对象应用方法
【发布时间】:2021-01-06 16:42:41
【问题描述】:

我有一个对象定义了一些应用方法,然后使用它

object Ob {
  def apply(i: Int) = ()
  def apply(s: String) = ()
}

object Use {
  def someMethod(i: Int) = ()

  Ob(1)
  someMethod(1)
}

使用 scalafix/scalameta 时,我无法找到获取实际 apply 方法句柄的方法(在我的情况下,我正在尝试检查参数名称和类型以查找 scalafix 规则)

当我匹配并打印解析的 SymbolInformation 时,我会得到一个对象的引用。 所以这个

import scalafix.v1._
import scala.meta._

class NamedLiteralArguments extends SemanticRule("NamedLiteralArguments") {
  val minParam = 2

  override def fix(implicit doc: SemanticDocument): Patch = {
    doc.tree
      .collect {
        case Term.Apply(fun, args) =>
          println(fun.symbol.info)

          Patch.empty
      }
  }

打印

Some(test/Ob. => final object Ob extends AnyRef { +2 decls })
Some(test/Use.someMethod(). => method someMethod(i: Int): Unit)

但我希望它能够解析确切的 apply 方法。

(Scalafix 版本 0.9.20)

【问题讨论】:

    标签: scala scalameta scalafix


    【解决方案1】:

    build.sbt 中打开"-P:semanticdb:synthetics:on"

    scalacOptions ++= List(
      "-Yrangepos",
      "-P:semanticdb:synthetics:on",
    )
    

    然后

    import scalafix.v1._
    import scala.meta._
    
    class MyRule extends SemanticRule("MyRule") {
      override def fix(implicit doc: SemanticDocument): Patch = {
        doc.tree
          .collect {
            case t: Term =>
              println(s"t=$t=${t.structure}, t.symbol.info=${t.symbol.info}, t.synthetics=${t.synthetics.map(_.symbol.map(_.info))}")
    
              Patch.empty
          }.asPatch
      }
    }
    

    打印

    t=Ob=Term.Name("Ob"), t.symbol.info=Some(_empty_/Ob. => final object Ob extends AnyRef { +2 decls }), t.synthetics=List()
    t=apply=Term.Name("apply"), t.symbol.info=Some(_empty_/Ob.apply(). => method apply(i: Int): Unit), t.synthetics=List()
    t=i=Term.Name("i"), t.symbol.info=Some(_empty_/Ob.apply().(i) => param i: Int), t.synthetics=List()
    t=()=Lit.Unit, t.symbol.info=None, t.synthetics=List()
    t=apply=Term.Name("apply"), t.symbol.info=Some(_empty_/Ob.apply(+1). => method apply(s: String): Unit), t.synthetics=List()
    t=s=Term.Name("s"), t.symbol.info=Some(_empty_/Ob.apply(+1).(s) => param s: String), t.synthetics=List()
    t=()=Lit.Unit, t.symbol.info=None, t.synthetics=List()
    t=Use=Term.Name("Use"), t.symbol.info=Some(_empty_/Use. => final object Use extends AnyRef { +1 decls }), t.synthetics=List()
    t=someMethod=Term.Name("someMethod"), t.symbol.info=Some(_empty_/Use.someMethod(). => method someMethod(i: Int): Unit), t.synthetics=List()
    t=i=Term.Name("i"), t.symbol.info=Some(_empty_/Use.someMethod().(i) => param i: Int), t.synthetics=List()
    t=()=Lit.Unit, t.symbol.info=None, t.synthetics=List()
    t=Ob(1)=Term.Apply(Term.Name("Ob"), List(Lit.Int(1))), t.symbol.info=Some(_empty_/Ob. => final object Ob extends AnyRef { +2 decls }), t.synthetics=List()
    t=Ob=Term.Name("Ob"), t.symbol.info=Some(_empty_/Ob. => final object Ob extends AnyRef { +2 decls }), t.synthetics=List(Some(Some(_empty_/Ob.apply(). => method apply(i: Int): Unit)))
    t=1=Lit.Int(1), t.symbol.info=None, t.synthetics=List()
    t=someMethod(1)=Term.Apply(Term.Name("someMethod"), List(Lit.Int(1))), t.symbol.info=Some(_empty_/Use.someMethod(). => method someMethod(i: Int): Unit), t.synthetics=List()
    t=someMethod=Term.Name("someMethod"), t.symbol.info=Some(_empty_/Use.someMethod(). => method someMethod(i: Int): Unit), t.synthetics=List()
    t=1=Lit.Int(1), t.symbol.info=None, t.synthetics=List()
    

    注意这条线

    t=Ob=Term.Name("Ob"), ..., t.synthetics=List(Some(Some(_empty_/Ob.apply(). => method apply(i: Int): Unit)))
    

    见:

    https://scalameta.org/docs/semanticdb/specification.html#synthetic

    https://scalameta.org/docs/semanticdb/specification.html#synthetic-1

    https://scalacenter.github.io/scalafix/docs/developers/semantic-tree.html#look-up-inferred-type-parameter

    所以

    class MyRule extends SemanticRule("MyRule") {
      override def fix(implicit doc: SemanticDocument): Patch = {
        doc.tree
          .collect {
            case Term.Apply(fun, args) =>
              println(fun.symbol.info + ", " + fun.synthetics.map(_.symbol.map(_.info)))
              Patch.empty
          }.asPatch
      }
    }
    

    将打印

    Some(_empty_/Ob. => final object Ob extends AnyRef { +2 decls }), List(Some(Some(_empty_/Ob.apply(). => method apply(i: Int): Unit)))
    Some(_empty_/Use.someMethod(). => method someMethod(i: Int): Unit), List()
    

    【讨论】:

    • 啊,所以 scalac 选项是我所缺少的(想知道为什么合成都是空的......)。干杯
    猜你喜欢
    • 2013-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 2014-05-16
    • 1970-01-01
    • 2023-01-30
    • 2012-11-08
    相关资源
    最近更新 更多