有没有办法测试scala编译器插件?

有没有办法测试scala编译器插件?,scala,plugins,compiler-construction,Scala,Plugins,Compiler Construction,我正在尝试为我正在开发的scala编译器插件设置测试 根据这种类似的方法,可以通过编程方式调用插件。然而,当我尝试这样做时,程序找不到我的插件 Error:(34, 25) not found: type GetFileFromAnnotation for (phase <- new GetFileFromAnnotation(this).components) 两个文件都在同一个包中 下面是试图测试从上述问题中提取的插件的代码,注释掉的代码是上面代码的替代代码,并抛出相同的

我正在尝试为我正在开发的scala编译器插件设置测试

根据这种类似的方法,可以通过编程方式调用插件。然而,当我尝试这样做时,程序找不到我的插件

Error:(34, 25) not found: type GetFileFromAnnotation
      for (phase <- new GetFileFromAnnotation(this).components)
两个文件都在同一个包中

下面是试图测试从上述问题中提取的插件的代码,注释掉的代码是上面代码的替代代码,并抛出相同的错误:

package compilerPlugin

import scala.reflect.internal.util.BatchSourceFile
import scala.tools.nsc.io.VirtualDirectory
import scala.tools.nsc.reporters.ConsoleReporter
import scala.tools.nsc.{Global, Settings}

object AnnotationFinderTest extends App {
  // prepare the code you want to compile
  val code =
"""
  |class Typestate(filename:String) extends scala.annotation.StaticAnnotation
  |
  |@Typestate(filename = "MyProtocol.txt")
  |class Cat{
  |  def comeAlive(): Unit = println("The cat is alive")
  |}
  |
  |object Main extends App {
  |  val cat = new Cat()
  |  cat.comeAlive()
  |}""".stripMargin

  val sources = List(new BatchSourceFile("<test>", code))
  println("sources "+sources)
  val settings = new Settings
  settings.usejavacp.value = true

  settings.outputDirs.setSingleOutput(new VirtualDirectory("(memory)", None))

  val compiler = new Global(settings, new ConsoleReporter(settings)) {
    override protected def computeInternalPhases () {
      super.computeInternalPhases
      for (phase <- new GetFileFromAnnotation(this).components)
        phasesSet += phase
    }
  }

    new compiler.Run() compileSources (sources)

}
GetFileFromAnnotation插件的代码为:

package compilerPlugin

import java.io.{FileNotFoundException, IOException}

import scala.tools.nsc
import nsc.Global
import nsc.Phase
import nsc.plugins.Plugin
import nsc.plugins.PluginComponent
import scala.io.BufferedSource
import scala.io.Source._

class GetFileFromAnnotation(val global: Global) extends Plugin {
  import global._

  val name = "GetFileFromAnnotation"
  val description = "gets file from typestate annotation"
  val components: List[PluginComponent] = List[PluginComponent](Component)

  private object Component extends PluginComponent {
    val global: GetFileFromAnnotation.this.global.type = GetFileFromAnnotation.this.global
    val runsAfter: List[String] = List[String]("parser")
    val phaseName: String = GetFileFromAnnotation.this.name
    def newPhase(_prev: Phase) = new GetFileFromAnnotationPhase(_prev)

    class GetFileFromAnnotationPhase(prev: Phase) extends StdPhase(prev) {
      override def name: String = GetFileFromAnnotation.this.name

      def printFile(filename: String): Unit ={
        val source = fromFile(filename)
        try {
          val it = source.getLines()
          while (it.hasNext)
            println(it.next())
        }
        catch{
          case e: IOException => println(s"Had an IOException trying to use file $filename")
        } finally {
          source.close
        }
      }

      def getFilenameFromAnnotation(annotation: Apply): Option[String] ={
        annotation match{
          case Apply(Select(New(Ident(TypeName("Typestate"))), con),List(NamedArg(Ident(TermName("filename")), Literal(Constant(filename))))) => Some(filename.toString)
          case Apply(Select(New(Ident(TypeName("Typestate"))), con),List(Literal(Constant(filename)))) => Some(filename.toString)
          case _ => None
        }
      }

      def apply(unit: CompilationUnit): Unit = {
        for (tree@q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" <- unit.body) {
          val annotations = mods.annotations
          for(annotation@Apply(arg1,arg2) <- annotations){
            getFilenameFromAnnotation(annotation) match{
              case Some(filename) => printFile(filename)
              case None => println("Not a Typestate annotation")
            }
          }
        }
      }
    }
  }
}
使用这种方法测试插件是否可行,或者使用模拟是唯一的方法?有没有其他方法可以完全做到这一点

更新: 感谢您的评论和github示例。 它最终与上面编辑的测试代码一起工作良好,并按预期打印出协议文件。我不知道为什么它以前不工作。

无法复制。如果我在IDE中运行AnnotationFinderTest,它的行为与预期的一样:它打印源列表aaa bbb aaa bbb是MyProtocol.txt中的行。如果我尝试在sbt shell中运行AnnotationFinderTest,则加载对象时出错,编译器镜像中缺少依赖项“类scala.native”,scala.reflect.internal.MissingRequirementError:未找到编译器镜像中的对象scala.annotation.StaticAnnotation。。。。。。但是对getClass.getClassLoader.asInstanceOf[URLClassLoader]from的修复对我不起作用:java.lang.ClassCastException:sbt.internal.LayeredClassLoader不能强制转换为scala.reflect.internal.util.ScalaClassLoader$URLClassLoader。无法复制。如果我在IDE中运行AnnotationFinderTest,它的行为与预期的一样:它打印源列表aaa bbb aaa bbb是MyProtocol.txt中的行。如果我尝试在sbt shell中运行AnnotationFinderTest,则加载对象时出错,编译器镜像中缺少依赖项“类scala.native”,scala.reflect.internal.MissingRequirementError:未找到编译器镜像中的对象scala.annotation.StaticAnnotation。。。。。。但是使用getClass.getClassLoader.asInstanceOf[URLClassLoader]from的修复对我不起作用:java.lang.ClassCastException:sbt.internal.LayeredClassLoader不能强制转换为scala.reflect.internal.util.ScalaClassLoader$URLClassLoader。