Skip to content

Instantly share code, notes, and snippets.

@lihaoyi
Created November 15, 2012 21:37
Show Gist options
  • Save lihaoyi/4081484 to your computer and use it in GitHub Desktop.
Save lihaoyi/4081484 to your computer and use it in GitHub Desktop.
import tools.nsc.plugins.{Plugin, PluginComponent}
import tools.nsc.Global
import tools.nsc.transform.{TypingTransformers, InfoTransform, Transform}
import tools.nsc.symtab.Flags
class MyPlugin(val global: Global) extends Plugin {
val name = "annotations-inject-implicit"
val description = "generates code which adds an implicit parameter of type BindingModule when an AutoInjectable trait is mixed in"
val components = List[PluginComponent](AnnotationsInjectComponent)
private object AnnotationsInjectComponent extends PluginComponent with Transform with TypingTransformers {
val global: MyPlugin.this.global.type = MyPlugin.this.global
import global._
val runsAfter = List[String]("parser")
override val runsBefore = List[String]("namer")
val phaseName = MyPlugin.this.name
def newTransformer(unit: CompilationUnit) = new AnnotationsInjectTransformer (unit)
val autoInjectable = "Serializable"
val bindingModule = "bindingModule"
val constructorMethod = "<init>"
val bindingModuleType = Select(Select(Ident(newTermName("_root_")),newTermName("app")),newTermName("Module"))
class AnnotationsInjectTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
def preTransform(tree: Tree): Tree = {
import Flags._
tree match {
case cd @ ClassDef(modifiers, name, tparams, classBody)
if !classBody.parents.map(_.toString).contains(autoInjectable) => {
log("AutoInjecting class %s".format(name))
val newParents = classBody.parents
val body = classBody.body.map {
case item @ DefDef(modifiers, termname, tparams, vparamss, tpt, rhs)
if termname.toString != constructorMethod =>
val newMods = Modifiers(IMPLICIT | PARAM | PARAMACCESSOR)
val newImplicit = new ValDef(newMods, bindingModule, bindingModuleType, EmptyTree)
val newParams = vparamss ::: List(List(newImplicit))
val newTree = treeCopy.DefDef(item, modifiers, termname, tparams, newParams, tpt, rhs)
newTree
case t => t
}
val newImpVal = ValDef(Modifiers(IMPLICIT | PARAMACCESSOR), bindingModule, bindingModuleType, EmptyTree)
treeCopy.ClassDef(cd, modifiers, name, tparams, Template(newParents, classBody.self, newImpVal :: body))
}
case t => t
}
}
override def transform (tree:Tree):Tree = {
val t = preTransform(tree)
super.transform(t)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment