Skip to content

Add initial CompilerCallback implementation for IntelliJ #989

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/dotty/tools/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import Symbols._
import Denotations._
import Phases._
import java.lang.AssertionError
import java.io.{ File => JFile }
import scala.tools.asm
import scala.tools.asm.tree._
import dotty.tools.dotc.util.{Positions, DotClass}
Expand All @@ -47,6 +48,8 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter

var tree: Tree = _

val sourceJFile: JFile = ctx.compilationUnit.source.file.file

final class PlainClassBuilder(cunit: CompilationUnit) extends SyncAndTryBuilder(cunit)


Expand Down Expand Up @@ -300,6 +303,9 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
bytecodeWriter.close()
// Statistics.stopTimer(BackendStats.bcodeTimer, bcodeStart)

if (ctx.compilerCallback != null)
ctx.compilerCallback.onSourceCompiled(sourceJFile)

/* TODO Bytecode can be verified (now that all classfiles have been written to disk)
*
* (1) asm.util.CheckAdapter.verify()
Expand Down Expand Up @@ -363,6 +369,11 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
if (outFolder == null) null
else getFileForClassfile(outFolder, jclassName, ".class")
bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, outFile)

val outJFile = outFile.file
val className = jclassName.replace('/', '.')
if (ctx.compilerCallback != null)
ctx.compilerCallback.onClassGenerated(sourceJFile, outJFile, className)
}
catch {
case e: FileConflictException =>
Expand Down
42 changes: 42 additions & 0 deletions src/dotty/tools/dotc/CompilerCallback.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package dotty.tools.dotc

import java.io.File

/** This trait contains methods that can be overriden to execute code during the
* compilation process.
*
* NOTE: This trait is experimental and may be subject to arbitrary changes.
*
* Example usage:
* {{{
* val args: Array[String] = ...
* val callback = new CompilerCallback {
* override def onClassGenerated(source: File, generatedClass: File, className: String) =
* println(s"onClassGenerated($source, $generatedClass, $className)")
* override def onSourceCompiled(source: File) =
* println(s"onSourceCompiled($source)")
* }
* dotty.tools.dotc.process(args, callback)
* // Or, if you have a custom root context `rootCtx`:
* dotty.tools.dotc.process(args, rootCtx.setCompilerCallback(callback))
* }}}
*/
trait CompilerCallback {
/** Called when a class has been generated.
*
* @param source The source file corresponding to this class.
* Example: ./src/library/scala/collection/Seq.scala
* @param generatedClass The generated classfile for this class.
* Example: ./scala/collection/Seq$.class
* @param className The name of this class.
* Example: scala.collection.Seq$
*/
def onClassGenerated(source: File, generatedClass: File, className: String): Unit = {}

/** Called when every class for this file has been generated.
*
* @param source The source file.
* Example: ./src/library/scala/collection/Seq.scala
*/
def onSourceCompiled(source: File): Unit = {}
}
9 changes: 8 additions & 1 deletion src/dotty/tools/dotc/Driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ abstract class Driver extends DotClass {

def setup(args: Array[String], rootCtx: Context): (List[String], Context) = {
val summary = CompilerCommand.distill(args)(rootCtx)
implicit val ctx: Context = initCtx.fresh.setSettings(summary.sstate)
// FIXME: We should reuse rootCtx instead of creating newCtx, but this
// makes some tests fail with "denotation module _root_ invalid in run 2."
val newCtx = initCtx.setCompilerCallback(rootCtx.compilerCallback)
implicit val ctx: Context = newCtx.fresh.setSettings(summary.sstate)
val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired)
(fileNames, ctx)
}
Expand All @@ -44,6 +47,10 @@ abstract class Driver extends DotClass {
doCompile(newCompiler(), fileNames)(ctx)
}

def process(args: Array[String], callback: CompilerCallback): Reporter = {
process(args, initCtx.setCompilerCallback(callback))
}

// We overload `process` instead of using a default argument so that we
// can easily call this method using reflection from `RawCompiler` in sbt.
def process(args: Array[String]): Reporter = {
Expand Down
15 changes: 15 additions & 0 deletions src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,23 @@ object Contexts {
def next = { val c = current; current = current.outer; c }
}

/** Set the compiler callback, shared by all contexts with the same `base` */
def setCompilerCallback(callback: CompilerCallback): this.type = {
base.compilerCallback = callback; this
}

/** The outer context */
private[this] var _outer: Context = _
protected def outer_=(outer: Context) = _outer = outer
def outer: Context = _outer

// protected def compilerCallback_=(callback: CompilerCallback) =
// _compilerCallback = callback
// def compilerCallback: CompilerCallback = _compilerCallback
// def setCompilerCallback(callback: CompilerCallback): this.type = {
// this.compilerCallback = callback; this
// }

/** The current context */
private[this] var _period: Period = _
protected def period_=(period: Period) = {
Expand Down Expand Up @@ -525,6 +537,9 @@ object Contexts {
/** The essential mutable state of a context base, collected into a common class */
class ContextState {

/** The compiler callback implementation, or null if unset */
var compilerCallback: CompilerCallback = _

// Symbols state

/** A counter for unique ids */
Expand Down