28048e468f/org.scala-refactoring.library/src/main/scala/scala/tools/refactoring/transformation/TreeFactory.scala
Commiter: Mirko Stocker
Author: Mirko Stocker
Revision: 28048e468f
File Size: 7.44 KB
(08 Jan 00:29 UTC) 5 months ago
First implementation of Move Class. Adapts the package declaration, adds imports where necessary and changes references to the moved class.
/*
* Copyright 2005-2010 LAMP/EPFL
*/
package scala.tools.refactoring
package transformation
import tools.nsc.symtab.Flags
import common.PimpedTrees
trait TreeFactory {
this: PimpedTrees with common.CompilerAccess with TreeTransformations =>
import global._
object Invisible extends Position
def mkRenamedSymTree(t: SymTree, name: String): SymTree = (t match {
case i: Ident => i.copy(name = name)
case v: ValDef => v.copy(name = name)
case d: DefDef => d.copy(name = name)
case b: Bind => b.copy(name = name)
case s: Select => s.copy(name = name)
case c: ClassDef => c.copy(name = name.toTypeName)
case t: This => t.copy(qual = name.toTypeName)
case m: ModuleDef => m.copy(name = name)
case t: TypeDef => t.copy(name = name.toTypeName)
case t: PackageDef => t.copy(pid = Ident(name) setPos t.pid.pos)
case t => throw new Exception("Found " + t.getClass.getName)
}) setPos t.pos
def mkRenamedTypeTree(t: TypeTree, name: String, originalSymbol: Symbol) = {
val newType = t.tpe map {
case TypeRef(pre, `originalSymbol`, args) =>
new Type {
override def safeToString: String = name
}
case t => t
}
val typeTree = t match {
case att: AppliedTypeTree => att.copy()
case _ => new TypeTree
}
typeTree setType newType
typeTree setPos t.pos
}
def mkImportFromStrings(qualifier: String, name: String) = {
def mapPackageNames(qualifier: String) = {
qualifier.split("\\.").map(s => escapeScalaKeywordsForImport(s.toTermName)).mkString(".")
}
new Import(Ident(mapPackageNames(qualifier)), new ImportSelector(name, -1, name, -1) :: Nil)
}
def mkRenamedImportTree(t: ImportSelectorTree, name: String) =
ImportSelectorTree(NameTree(name) setPos t.name.pos, t.rename) setPos t.pos
def mkReturn(s: List[Symbol]): Tree = s match {
case Nil => EmptyTree
case x :: Nil => Ident(x) setType x.tpe
case xs =>
typer.typed(gen.mkTuple(xs map (s => Ident(s) setType s.tpe))) match {
case t: Apply => t.fun setPos Invisible; t //don't show the TupleX..
case t => t
}
}
def mkValDef(name: String, rhs: Tree): ValDef = {
val valDef = ValDef(NoMods, name, new TypeTree, rhs)
def valDefForFunction = ValDef(NoMods, name, new TypeTree, Apply(rhs, Ident(nme.USCOREkw) :: Nil))
rhs match {
case rhs: Select if rhs.symbol.isMethod =>
rhs.symbol.tpe match {
case _: NullaryMethodType => valDef
case _ => valDefForFunction
}
case _ => valDef
}
}
def mkCallDefDef(name: String, arguments: List[List[Symbol]] = Nil :: Nil, returns: List[Symbol] = Nil): Tree = {
// currying not yet supported
val args = arguments.head map (s => Ident(s))
val call = if (args.isEmpty)
Select(This(nme.EMPTY.toTypeName) setPos Invisible, name)
else
Apply(Select(This(nme.EMPTY.toTypeName) setPos Invisible, name), args)
returns match {
case Nil => call
case returns =>
// 'val (a, b) =' is represented by various trees, so we cheat and create the assignment in the name of the value:
val valName = returns match {
case x :: Nil => x.name.toString
case xs => "(" + (xs map (_.name) mkString ", ") + ")"
}
ValDef(NoMods, valName, new TypeTree(), call)
}
}
def mkDefDef(mods: Modifiers = NoMods, name: String, parameters: List[List[Symbol]] = Nil :: Nil, body: List[Tree]): DefDef = {
val formalParameters = {
if (parameters.isEmpty)
Nil
else
parameters map (_ map (s => new ValDef(Modifiers(Flags.PARAM), s.nameString, TypeTree(s.tpe), EmptyTree)))
}
DefDef(mods withPosition (Flags.METHOD, NoPosition), name, Nil /*type parameters*/ , formalParameters, TypeTree(body.last.tpe), mkBlock(body))
}
def mkBlock(trees: List[Tree]): Block = trees match {
case Nil => throw new Exception("can't make block from 0 trees")
case x :: Nil => Block(x :: Nil, EmptyTree)
case xs => Block(xs.init, xs.last)
}
def mkClass(
mods: Modifiers = NoMods,
name: String,
tparams: List[TypeDef] = Nil,
argss: List[List[(Modifiers, String, Tree)]] = Nil,
body: List[Tree] = Nil,
parents: List[Tree] = Nil,
superArgs: List[Tree] = Nil) = {
val constructorArguments = argss map (_ map {
case (mods, name, tpe) =>
ValDef(mods | Flags.PARAMACCESSOR, name, tpe, EmptyTree)
})
val constructor = {
val body = List(superArgs) map {
case Nil =>
EmptyTree
case args =>
Apply(EmptyTree, args)
}
DefDef(mods withPosition (Flags.METHOD, NoPosition), nme.CONSTRUCTOR.toString, Nil, constructorArguments, TypeTree(NoType), mkBlock(body))
}
ClassDef(
mods,
name.toTypeName,
tparams,
Template(
parents,
emptyValDef,
constructor :: constructorArguments.flatten ::: body))
}
def mkCaseClass(
mods: Modifiers = NoMods,
name: String,
tparams: List[TypeDef] = Nil,
argss: List[List[(Modifiers, String, Tree)]] = Nil,
body: List[Tree] = Nil,
parents: List[Tree] = Nil,
superArgs: List[Tree] = Nil) = {
mkClass(mods withPosition (Flags.CASE, NoPosition), name, tparams, argss, body, parents, superArgs)
}
class CopyTypeFromOtherTree(t1: Tree) {
def typeFrom(t2: Tree) = {
t1.tpe = t2.tpe
t1
}
}
implicit def typeFromTree(t1: Tree) = new CopyTypeFromOtherTree(t1)
/**
* Creates a function call `fun` on the selector and passes a function with
* a single parameter `param` and the body `body`.
*
* Example:
*
* someExpr becomes someExpr fun (param => body)
*
*/
def mkFunctionCallWithFunctionArgument(selector: Tree, fun: String, param: Name, body: Tree) = {
Apply(
Select(selector, newTermName(fun)),
List(Function(List(ValDef(Modifiers(Flags.PARAM), param, EmptyTree, EmptyTree)), body))
) typeFrom body
}
/**
* Creates a function call `fun` on the selector and passes a function with
* no parameter and the body `body`.
*
* Example:
*
* someExpr becomes someExpr fun (body)
*/
def mkFunctionCallWithZeroArgFunctionArgument(selector: Tree, fun: String, body: Tree) = {
Apply(
Select(selector, newTermName(fun)),
List(Function(Nil, body))
) typeFrom body
}
def mkImportTrees(trees: List[Select], enclosingPackage: String) = {
def importsFromSamePackage(t: Tree) = {
asSelectorString(t) == enclosingPackage
}
trees flatMap {
// warning if binding is never used! and quickfix to replace with `_`!
case Select(selector, _) if importsFromSamePackage(selector) =>
None
case select @ Select(expr, name) =>
// we don't want to see imports like "java.this.lang..."
val removeThisTrees = {
matchingChildren {
transform {
case t: This =>
// expand to the full package name
val parents = ancestorSymbols(t)
Ident(parents map (_.nameString) mkString ".")
}
}
}
// copy the tree and delete all positions so the full path will be written
val newExpr = topdown(setNoPosition &> removeThisTrees) apply duplicateTree(expr) getOrElse expr
val typeName = select.symbol.nameString
Some(Import(newExpr, List(new ImportSelector(if(typeName == name.toString) name else typeName, -1, name, -1))))
}
}
} |