我正在编写一个Scala编译器插件,其中包含一个在";jvm";需要知道方法被重写的阶段。以下是我正在处理的一个测试用例的提炼版本:
abstract class GenericController[T] {
def getPath():String
def save(entity:T):String = "parent"
}
class StatusController extends GenericController[String] {
override def getPath():String = "/statuses"
override def save(entity:String):String = "child"
}
在遍历AST时,我对类和方法进行迭代,确保只处理未被重写的方法。应用于StatusController.getPath
方法的符号的scala.reflect.internal.Symbols.MethodSymbol.overrides()
方法将包括用于GenericController.getPath
的方法。
然而,MethodSymbol.overrides()
未能返回用于StatusController.save
符号的GenericController.save
方法。似乎泛型类型使这种行为复杂化了,这应该在另一个编译器阶段之后完成吗?
让我们定义测试编译器插件。
core/src/main/scala/main.scala
abstract class GenericController[T] {
def getPath():String
def save(entity:T):String = "parent"
}
class StatusController extends GenericController[String] {
override def getPath():String = "/statuses"
override def save(entity:String):String = "child"
}
plugin/src/main/resources/scalac plugin.xml
<plugin>
<name>MyCompilerPlugin</name>
<classname>compilerPlugin.MyCompilerPlugin</classname>
</plugin>
plugin/src/main/scala/compilerPlugin/MyCompilerPlugin.scala
package compilerPlugin
import scala.tools.nsc.{Global, Phase}
import scala.tools.nsc.plugins.{Plugin, PluginComponent}
class MyCompilerPlugin(val global: Global) extends Plugin {
import global._
val name = "MyCompilerPlugin"
val description = "My compiler plugin"
val components: List[PluginComponent] = List[PluginComponent](MyComponent)
private object MyComponent extends PluginComponent {
val global: MyCompilerPlugin.this.global.type = MyCompilerPlugin.this.global
val runsAfter: List[String] = List[String](/*"typer"*/"jvm")
val phaseName: String = MyCompilerPlugin.this.name
def newPhase(_prev: Phase) = new MyPhase(_prev)
class MyPhase(prev: Phase) extends StdPhase(prev) {
override def name: String = MyCompilerPlugin.this.name
def apply(unit: CompilationUnit): Unit = {
for (tree@q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" <- unit.body) {
println(s"tree=$tree, symbol=${tree.symbol.fullName}, symbol.overrides=${tree.symbol.overrides.map(_.fullName)}")
}
}
}
}
}
build.sbt
ThisBuild / name := "compiler-plugin-demo"
lazy val commonSettings = Seq(
scalaVersion := "2.13.3",
version := "1.0",
)
lazy val plugin = project
.settings(
commonSettings,
libraryDependencies ++= Seq(
scalaOrganization.value % "scala-reflect" % scalaVersion.value,
scalaOrganization.value % "scala-compiler" % scalaVersion.value,
)
)
lazy val core = project
.settings(
commonSettings,
scalacOptions ++= Seq(
"-Xplugin:plugin/target/scala-2.13/plugin_2.13-1.0.jar",
"-Xplugin-require:MyCompilerPlugin"
)
)
如果你在typer
阶段之后运行(sbt reload; clean; plugin/package; core/compile
(这个编译器插件,它会打印
tree=def <init>(): GenericController[T] = {
GenericController.super.<init>();
()
}, symbol=GenericController.<init>, symbol.overrides=List()
tree=def getPath(): String, symbol=GenericController.getPath, symbol.overrides=List()
tree=def save(entity: T): String = "parent", symbol=GenericController.save, symbol.overrides=List()
tree=def <init>(): StatusController = {
StatusController.super.<init>();
()
}, symbol=StatusController.<init>, symbol.overrides=List()
tree=override def getPath(): String = "/statuses", symbol=StatusController.getPath, symbol.overrides=List(GenericController.getPath)
tree=override def save(entity: String): String = "child", symbol=StatusController.save, symbol.overrides=List(GenericController.save)
但如果你在jvm
阶段之后运行它,它会打印
tree=def getPath(): String, symbol=GenericController.getPath, symbol.overrides=List()
tree=def save(entity: Object): String = "parent", symbol=GenericController.save, symbol.overrides=List()
tree=def <init>(): GenericController = {
GenericController.super.<init>();
()
}, symbol=GenericController.<init>, symbol.overrides=List()
tree=override def getPath(): String = "/statuses", symbol=StatusController.getPath, symbol.overrides=List(GenericController.getPath)
tree=override def save(entity: String): String = "child", symbol=StatusController.save, symbol.overrides=List()
tree=override <bridge> <artifact> def save(entity: Object): String = StatusController.this.save(entity.$asInstanceOf[String]()), symbol=StatusController.save, symbol.overrides=List(GenericController.save)
tree=def <init>(): StatusController = {
StatusController.super.<init>();
()
}, symbol=StatusController.<init>, symbol.overrides=List()
如您所见,在typer
阶段之后,方法符号StatusController.getPath
覆盖方法符号GenericController.getPath
,StatusController.save
覆盖GenericController.save
。在CCD_ 15之后,相位CCD_ 16再次覆盖CCD_ 17,但覆盖GenericController.save
的是桥CCD_ 18而不是普通的CCD_ 19。所以我猜你们把桥牌法的符号和普通法的符号混淆了。