0

I'm working on a system to help me solve this problem getting annotations off of a specific method.

I have created a compiler plugin which will take a function name as an argument and prints out all the annotations. What I want is to make an SBT task which will call the compiler using this plugin, capture the output, and parse it. I've found several potential methods to do this, but all of them have issues.

The simplest, although least elegant, solution I found was to manually execute the compiler with all the correct arguments using sys.process like so:

private val typerPlugin = "pluginName"
private val scalac = s"scalac -Xplugin:lib/$typerPlugin.jar -Ystop-after:$typerPlugin ${(server / Compile / scalacOptions).value.mkString(" ")} -classpath ${(server / Compile / dependencyClasspath).value.map(_.data).mkString(":")} -P:$typerPlugin:methods:$pack.$controller.$fn ${(server / Compile / sources).value.mkString(" ")}\n"
scalac !!

Obviously this is clunky, but should theoretically work. The problem is that I seem to be missing some dependency or enviorment variable. This is evidenced by this error which I do not encounter when compiling through SBT:

/path/to/proj/server/app/name/tflucke/controllers/Controller.scala:23: error: exception during macro expansion:
java.lang.NoSuchMethodError: 'void scala.Product.$init$(scala.Product)'
        at io.getquill.quotation.Parsing$Parser.<init>(Parsing.scala:20)
        at io.getquill.quotation.Parsing.$init$(Parsing.scala:36)
        at io.getquill.dsl.QuotationMacro.<init>(QuotationDsl.scala:38)

  val pojo = quote(querySchema[Pojo]("Pojo"))

I've investigated this a little and it seems to be an error relating to my scala version based on these three similar issues.

I've also considered directly calling the (server / Compile / compile) task by wrapping it in another task which changes it's settings, but it does not seem to behave as a normal task and I can't find a way to wrap it. It seems to be some undocumented class called CompilationAnalysis.

Finally, the SBT documentation has something called Fork which sounds similar to the above sys.process but built into SBT and thus might maintain some of the enviorment information. Unfortunately, when I try to call Fork.scalac, I get this error for unknown reasons:

Error: Could not find or load main class scala.tools.nsc.Main
Caused by: java.lang.ClassNotFoundException: scala.tools.nsc.Main

I have not found any explanation for this error. The closest is this which seems to be a very specific use case on Windows, which seems unrelated to me and my Ubuntu system.

So at this point I have tried many possible solutions and come to many dead ends. Does anyone here have any suggestions to how I can run my compiler plugin and capture the output?

Thomas
  • 871
  • 2
  • 8
  • 21
  • What you are trying to do is a bit strange. Isn't it possible to do it by defining a Task in your plugin that parses the functions by names defined in some Setting in your plugin, and adds sourceGenerators for the compiler to use? – Kolmar May 17 '20 at 02:38
  • @Kolmar is there a way to have SBT parse my source code directly? I searched online and the only real answer I found was that there wasn't any good libraries for parsing source files and that my best bet was to use the compiler. I had even posted another question to a few weeks ago about exactly that and never got a reply. If there's a way to parse without using the compiler, I'd love to hear it. – Thomas May 17 '20 at 05:01
  • Actually, I did use that `CompileAnalysis` from `compile` task once in my SBT plugin. My problem was different: from SBT I was looking for classes in my source code that extend one from a list of known classes. It's undocumented as you've mentioned, but I've just experimented and looked at SBT source code to understand how to use it. In the end I had managed to find the classes and access them with Java reflection (load through a ClassLoader) inside an SBT plugin. Not sure how useful all that would be for your problem. Maybe I can make and self-answer a question with my experience? – Kolmar May 17 '20 at 06:19
  • @Kolmar At this point? It's worth a shot. I'm honestly just amazed this is as difficult as it seems to be right now. You'd think invoking the compiler would be trivially easy. I'm honestly on the verge of concluding this isn't possible. – Thomas May 23 '20 at 05:49
  • Please, see if this question helps you: https://stackoverflow.com/questions/62029478/ – Kolmar May 26 '20 at 19:06
  • @Kolmar I've tried the solution you posted. Unfortunately, I need to do my code analysis to generate a file that will be used at compile time. Therefore, I need a solution that works without being dependent on the compiled code. – Thomas Jun 12 '20 at 05:17
  • I've found another method which I don't like as much, but it works. I'm leaving this open incase anyone manages to find a solution to this problem because I'm genuinely curious and maybe it will help someone else. – Thomas Jun 13 '20 at 01:53

0 Answers0