scala.reflect.internal.Printers.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-reflect Show documentation
Show all versions of scala-reflect Show documentation
Reflection Library for the Scala Programming Language
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
// todo. we need to unify this prettyprinter with NodePrinters
package scala
package reflect
package internal
import java.io.{OutputStream, PrintWriter, Writer}
import Flags._
import java.lang.System.{lineSeparator => EOL}
import scala.annotation.{nowarn, tailrec}
trait Printers extends api.Printers { self: SymbolTable =>
//nsc import treeInfo.{ IsTrue, IsFalse }
/** Adds backticks if the name is a scala keyword. */
def quotedName(name: Name, decode: Boolean): String = {
val s = if (decode) name.decode else name.toString
val term = name.toTermName
if (nme.keywords(term) && term != nme.USCOREkw) "`%s`" format s
else s
}
def quotedName(name: Name): String = quotedName(name, decode = false)
def quotedName(name: String): String = quotedName(newTermName(name), decode = false)
private def symNameInternal(tree: Tree, name: Name, decoded: Boolean): String = {
val sym = tree.symbol
def qname = quotedName(name.dropLocal, decoded)
def qowner = quotedName(sym.owner.name.dropLocal, decoded)
def qsymbol = quotedName(sym.nameString)
if (sym == null || sym == NoSymbol)
qname
else if (sym.isErroneous)
s"<$qname: error>"
else if (sym.isMixinConstructor)
s"/*$qowner*/$qsymbol"
else
qsymbol
}
def decodedSymName(tree: Tree, name: Name) = symNameInternal(tree, name, decoded = true)
def symName(tree: Tree, name: Name) = symNameInternal(tree, name, decoded = false)
/** Turns a path into a String, introducing backquotes
* as necessary.
*/
def backquotedPath(t: Tree): String = {
t match {
case Select(qual, name) if name.isTermName => s"${backquotedPath(qual)}.${symName(t, name)}"
case Select(qual, name) if name.isTypeName => s"${backquotedPath(qual)}#${symName(t, name)}"
case Ident(name) => symName(t, name)
case _ => t.toString
}
}
@nowarn("""cat=deprecation&origin=scala\.reflect\.internal\.Printers\.TreePrinter""")
final type InternalTreePrinter = TreePrinter
@nowarn("msg=shadowing a nested class of a parent is deprecated")
@deprecated("use InternalTreePrinter instead", since = "2.13.4")
class TreePrinter(out: PrintWriter) extends super.TreePrinter {
protected var indentMargin = 0
protected val indentStep = 2
protected var indentString = " " // 40
printTypes = settings.printtypes.value
printIds = settings.uniqid.value
printOwners = settings.Yshowsymowners.value
printKinds = settings.Yshowsymkinds.value
printMirrors = false // typically there's no point to print mirrors inside the compiler, as there is only one mirror there
printPositions = settings.Xprintpos.value
def indent() = indentMargin += indentStep
def undent() = indentMargin -= indentStep
protected def checkForBlank(cond: Boolean) = if (cond) " " else ""
protected def blankForOperatorName(name: Name) = checkForBlank(name.isOperatorName)
protected def blankForName(name: Name) = checkForBlank(name.isOperatorName || name.endsWith("_"))
def printPosition(tree: Tree) =
if (printPositions) comment(print(tree.pos.show))
protected def printTypesInfo(tree: Tree) =
if (printTypes && tree.isTerm && tree.canHaveAttrs)
comment{
print("{", if (tree.tpe eq null) "" else tree.tpe.toString, "}")
}
def println() = {
out.println()
while (indentMargin > indentString.length())
indentString += indentString
if (indentMargin > 0)
out.write(indentString, 0, indentMargin)
}
@tailrec
final def printSeq[A](ls: List[A])(printelem: A => Unit)(printsep: => Unit): Unit =
ls match {
case List() =>
case List(x) => printelem(x)
case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep)
}
def printColumn(ts: List[Tree], start: String, sep: String, end: String) = {
print(start); indent(); println()
printSeq(ts){print(_)}{print(sep); println()}; undent(); println(); print(end)
}
def printRow(ts: List[Tree], start: String, sep: String, end: String): Unit = {
print(start); printSeq(ts){print(_)}{print(sep)}; print(end)
}
def printRow(ts: List[Tree], sep: String): Unit = printRow(ts, "", sep, "")
def printTypeParams(ts: List[TypeDef]): Unit =
if (ts.nonEmpty) {
print("["); printSeq(ts){ t =>
printAnnotations(t)
if (t.mods.hasFlag(CONTRAVARIANT)) {
print("-")
} else if (t.mods.hasFlag(COVARIANT)) {
print("+")
}
printTParam(t)
}{print(", ")}; print("]")
}
def printLabelParams(ps: List[Ident]) = {
print("(")
printSeq(ps){printLabelParam}{print(", ")}
print(")")
}
def printLabelParam(p: Ident) = {
print(symName(p, p.name)); printOpt(": ", TypeTree() setType p.tpe)
}
protected def parenthesize(condition: Boolean = true, open: String = "(", close: String = ")")(body: => Unit) = {
if (condition) print(open)
body
if (condition) print(close)
}
protected val commentsRequired = false
protected def comment(body: => Unit) =
parenthesize(commentsRequired, "/*", "*/")(body)
protected def printImplicitInParamsList(vds: List[ValDef]) =
if (vds.nonEmpty) printFlags(vds.head.mods.flags & IMPLICIT, "")
def printValueParams(ts: List[ValDef], inParentheses: Boolean = true): Unit =
parenthesize(inParentheses){
printImplicitInParamsList(ts)
printSeq(ts){printVParam}{print(", ")}
}
def printVParam(vd: ValDef) = {
printPosition(vd)
printAnnotations(vd)
print(symName(vd, vd.name)); printOpt(": ", vd.tpt); printOpt(" = ", vd.rhs)
}
def printTParam(td: TypeDef) = {
printPosition(td)
print(symName(td, td.name))
printTypeParams(td.tparams); print(td.rhs)
}
def printBlock(tree: Tree) =
tree match {
case Block(_, _) =>
print(tree)
case _ =>
printColumn(List(tree), "{", ";", "}")
}
private def symFn[T](tree: Tree, f: Symbol => T, orElse: => T): T = tree.symbol match {
case null | NoSymbol => orElse
case sym => f(sym)
}
private def ifSym(tree: Tree, p: Symbol => Boolean) = symFn(tree, p, false)
def printOpt(prefix: String, tree: Tree) = if (tree.nonEmpty) { print(prefix, tree) }
def printModifiers(tree: Tree, mods: Modifiers): Unit = printFlags(
if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + (
if (tree.symbol == NoSymbol) mods.privateWithin
else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name
else ""
)
)
def printFlags(flags: Long, privateWithin: String) = {
val mask: Long = if (settings.isDebug) -1L else PrintableFlags
val s = flagsToString(flags & mask, privateWithin)
if (s != "") print(s + " ")
}
def printAnnotations(tree: MemberDef) = {
// scala/bug#5885: by default this won't print annotations of not yet initialized symbols
val annots = tree.symbol.annotations match {
case Nil => tree.mods.annotations
case anns => anns
}
annots foreach (annot => print(s"@$annot "))
}
private[this] var currentOwner: Symbol = NoSymbol
private[this] var selectorType: Type = NoType
protected def printPackageDef(tree: PackageDef, separator: String) = {
val PackageDef(packaged, stats) = tree
printAnnotations(tree)
print("package ", packaged); printColumn(stats, " {", separator, "}")
}
protected def printValDef(tree: ValDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) = {
val ValDef(mods, _, _, _) = tree
printAnnotations(tree)
printModifiers(tree, mods)
print(if (mods.isMutable) "var " else "val ", resultName)
printTypeSignature
printRhs
}
protected def printDefDef(tree: DefDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) = {
val DefDef(mods, _, tparams, vparamss, _, _) = tree
printAnnotations(tree)
printModifiers(tree, mods)
print("def " + resultName)
printTypeParams(tparams)
vparamss foreach {printValueParams(_)}
printTypeSignature
printRhs
}
protected def printTypeDef(tree: TypeDef, resultName: => String) = {
val TypeDef(mods, _, tparams, rhs) = tree
if (mods hasFlag (PARAM | DEFERRED)) {
printAnnotations(tree)
printModifiers(tree, mods)
print("type ")
printTParam(tree)
} else {
printAnnotations(tree)
printModifiers(tree, mods)
print("type " + resultName)
printTypeParams(tparams)
printOpt(" = ", rhs)
}
}
protected def printImport(tree: Import, resSelect: => String) = {
val Import(_, selectors) = tree
def selectorToString(s: ImportSelector): String = {
def selectorName(n: Name): String = if (s.isWildcard) nme.WILDCARD.decoded else quotedName(n)
val from = selectorName(s.name)
if (s.isRename || s.isMask) from + "=>" + selectorName(s.rename)
else from
}
print("import ", resSelect, ".")
selectors match {
case List(s) =>
// If there is just one selector and it is not renaming or masking a name, no braces are needed
if (!s.isRename && !s.isMask) print(selectorToString(s))
else print("{", selectorToString(s), "}")
// If there is more than one selector braces are always needed
case many =>
print(many.map(selectorToString).mkString("{", ", ", "}"))
}
}
protected def printCaseDef(tree: CaseDef) = {
val CaseDef(pat, guard, body) = tree
print("case ")
print(pat)
printOpt(" if ", guard)
print(" => ", body)
}
protected def printFunction(tree: Function)(printValueParams: => Unit) = {
val Function(_, body) = tree
print("(")
printValueParams
print(" => ", body, ")")
if (printIds && tree.symbol != null)
comment{
print("#" + tree.symbol.id)
}
if (printOwners && tree.symbol != null)
comment{
print("@" + tree.symbol.owner.id)
}
}
protected def printSuper(tree: Super, resultName: => String, checkSymbol: Boolean = true) = {
val Super(This(qual), mix) = tree: @unchecked
if (qual.nonEmpty || (checkSymbol && tree.symbol != NoSymbol)) print(resultName + ".")
print("super")
if (mix.nonEmpty) print(s"[$mix]")
else if (settings.isDebug) tree.tpe match {
case st: SuperType => print(s"[${st.supertpe}]")
case tp: Type => print(s"[$tp]")
case _ =>
}
}
protected def printThis(tree: This, resultName: => String) = {
val This(qual) = tree
if (qual.nonEmpty) print(resultName + ".")
print("this")
}
protected def printBlock(stats: List[Tree], expr: Tree) =
printColumn(stats ::: List(expr), "{", ";", "}")
def printTree(tree: Tree) = {
tree match {
case EmptyTree =>
print("")
case cd @ ClassDef(mods, name, tparams, impl) =>
printAnnotations(cd)
printModifiers(tree, mods)
val word =
if (mods.isTrait) "trait"
else if (ifSym(tree, _.isModuleClass)) "object"
else "class"
print(word, " ", symName(tree, name))
printTypeParams(tparams)
print(if (mods.isDeferred) " <: " else " extends ", impl)
case pd @ PackageDef(packaged, stats) =>
printPackageDef(pd, ";")
case md @ ModuleDef(mods, name, impl) =>
printAnnotations(md)
printModifiers(tree, mods)
print("object " + symName(tree, name), " extends ", impl)
case vd @ ValDef(mods, name, tp, rhs) =>
printValDef(vd, symName(tree, name))(printOpt(": ", tp)) {
if (!mods.isDeferred) print(" = ", if (rhs.isEmpty) "_" else rhs)
}
case dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) =>
printDefDef(dd, symName(tree, name)) {
// place space after symbolic def name (def !: Unit does not compile)
if (tparams.isEmpty && vparamss.isEmpty) printOpt(blankForName(name.encodedName) + ": ", tp)
else printOpt(": ", tp)
} (printOpt(" = ", rhs))
case td @ TypeDef(mods, name, tparams, rhs) =>
printTypeDef(td, symName(tree, name))
case LabelDef(name, params, rhs) =>
print(symName(tree, name)); printLabelParams(params); printBlock(rhs)
case imp @ Import(expr, _) =>
printImport(imp, backquotedPath(expr))
case Template(parents, self, body) =>
val currentOwner1 = currentOwner
if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner
printRow(parents, " with ")
if (body.nonEmpty) {
if (self.name != nme.WILDCARD) {
print(" { ", self.name); printOpt(": ", self.tpt); print(" => ")
} else if (self.tpt.nonEmpty) {
print(" { _ : ", self.tpt, " => ")
} else {
print(" {")
}
printColumn(body, "", ";", "}")
}
currentOwner = currentOwner1
case Block(stats, expr) =>
printBlock(stats, expr)
case Match(selector, cases) =>
val selectorType1 = selectorType
selectorType = selector.tpe
print(selector); printColumn(cases, " match {", "", "}")
selectorType = selectorType1
case cd @ CaseDef(pat, guard, body) =>
printCaseDef(cd)
case Alternative(trees) =>
printRow(trees, "(", "| ", ")")
case Star(elem) =>
print("(", elem, ")*")
case Bind(name, t) =>
print("(", symName(tree, name), " @ ", t, ")")
case UnApply(fun, args) =>
print(fun, " "); printRow(args, "(", ", ", ")")
case ArrayValue(elemtpt, trees) =>
print("Array[", elemtpt); printRow(trees, "]{", ", ", "}")
case f @ Function(vparams, body) =>
printFunction(f)(printValueParams(vparams))
case Assign(lhs, rhs) =>
print(lhs, " = ", rhs)
case NamedArg(lhs, rhs) =>
print(lhs, " = ", rhs)
case If(cond, thenp, elsep) =>
print("if (", cond, ")"); indent(); println()
print(thenp); undent()
if (elsep.nonEmpty) {
println(); print("else"); indent(); println(); print(elsep); undent()
}
case Return(expr) =>
print("return ", expr)
case Try(block, catches, finalizer) =>
print("try "); printBlock(block)
if (catches.nonEmpty) printColumn(catches, " catch {", "", "}")
printOpt(" finally ", finalizer)
case Throw(expr) =>
print("throw ", expr)
case New(tpe) =>
print("new ", tpe)
case Typed(expr, tp) =>
print("(", expr, ": ", tp, ")")
case TypeApply(fun, targs) =>
print(fun); printRow(targs, "[", ", ", "]")
case Apply(fun, vargs) =>
print(fun); printRow(vargs, "(", ", ", ")")
case ApplyDynamic(qual, vargs) =>
print("(", qual, "#", tree.symbol.nameString)
printRow(vargs, ", (", ", ", "))")
case st @ Super(This(qual), mix) =>
printSuper(st, symName(tree, qual))
case Super(qual, mix) =>
print(qual, ".super")
if (mix.nonEmpty)
print("[" + mix + "]")
case th @ This(qual) =>
printThis(th, symName(tree, qual))
case Select(qual: New, name) if !settings.isDebug =>
print(qual)
case Select(qualifier, name) =>
print(backquotedPath(qualifier), ".", symName(tree, name))
case id @ Ident(name) =>
val str = symName(tree, name)
print( if (id.isBackquoted) "`" + str + "`" else str )
case Literal(x) =>
print(x.escapedStringValue)
case tt: TypeTree =>
if ((tree.tpe eq null) || (printPositions && tt.original != null)) {
if (tt.original != null) print("")
else print("")
} else if ((tree.tpe.typeSymbol ne null) && tree.tpe.typeSymbol.isAnonymousClass) {
print(tree.tpe.typeSymbol.toString)
} else {
print(tree.tpe.toString)
}
case an @ Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) =>
def printAnnot(): Unit = {
print("@", tpt)
if (args.nonEmpty)
printRow(args, "(", ",", ")")
}
print(tree, if (tree.isType) " " else ": ")
printAnnot()
case SingletonTypeTree(ref) =>
print(ref, ".type")
case SelectFromTypeTree(qualifier, selector) =>
print(qualifier, "#", symName(tree, selector))
case CompoundTypeTree(templ) =>
print(templ)
case AppliedTypeTree(tp, args) =>
print(tp); printRow(args, "[", ", ", "]")
case TypeBoundsTree(lo, hi) =>
// Avoid printing noisy empty typebounds everywhere
// Untyped empty bounds are not printed by printOpt,
// but after they are typed we have to exclude Nothing/Any.
if ((lo.tpe eq null) || !(lo.tpe =:= definitions.NothingTpe))
printOpt(" >: ", lo)
if ((hi.tpe eq null) || !(hi.tpe =:= definitions.AnyTpe))
printOpt(" <: ", hi)
case ExistentialTypeTree(tpt, whereClauses) =>
print(tpt)
printColumn(whereClauses, " forSome { ", ";", "}")
// SelectFromArray is no longer visible in scala.reflect.internal.
// eliminated until we figure out what we will do with both Printers and
// SelectFromArray.
// case SelectFromArray(qualifier, name, _) =>
// print(qualifier); print("."); print(symName(tree, name))
case tree =>
xprintTree(this, tree)
}
printTypesInfo(tree)
}
def print(args: Any*): Unit = args foreach {
case tree: Tree =>
printPosition(tree)
printTree(tree)
case name: Name =>
print(quotedName(name))
case arg =>
out.print(if (arg == null) "null" else arg.toString)
}
}
// it's the printer for AST-based code generation
class CodePrinter(out: PrintWriter, printRootPkg: Boolean) extends InternalTreePrinter(out) {
protected val parentsStack = scala.collection.mutable.Stack[Tree]()
protected def currentTree = if (parentsStack.nonEmpty) Some(parentsStack.top) else None
protected def currentParent = if (parentsStack.length > 1) Some(parentsStack(1)) else None
protected def printedName(name: Name, decoded: Boolean = true) = {
import Chars._
val decName = name.decoded
val bslash = '\\'
val isDot = (x: Char) => x == '.'
val brackets = List('[',']','(',')','{','}')
def addBackquotes(s: String) =
if (decoded && (decName.exists(ch => brackets.contains(ch) || isWhitespace(ch) || isDot(ch)) ||
((name.isOperatorName || decName.exists(isOperatorPart)) && decName.exists(isScalaLetter) && !decName.contains(bslash))))
s"`$s`" else s
if (name == nme.CONSTRUCTOR) "this"
else addBackquotes(quotedName(name, decoded))
}
protected def isIntLitWithDecodedOp(qual: Tree, name: Name) = {
val qualIsIntLit = qual match {
case Literal(Constant(x: Int)) => true
case _ => false
}
qualIsIntLit && name.isOperatorName
}
override protected val commentsRequired = true
protected def needsParentheses(parent: Tree)(insideIf: Boolean = true, insideMatch: Boolean = true, insideTry: Boolean = true,
insideAnnotated: Boolean = true, insideBlock: Boolean = true, insideLabelDef: Boolean = true, insideAssign: Boolean = true) = {
parent match {
case _: If => insideIf
case _: Match => insideMatch
case _: Try => insideTry
case _: Annotated => insideAnnotated
case _: Block => insideBlock
case _: LabelDef => insideLabelDef
case _: Assign => insideAssign
case _ => false
}
}
protected def resolveSelect(t: Tree): String = {
t match {
// case for: 1) (if (a) b else c).meth1.meth2 or 2) 1 + 5 should be represented as (1).+(5)
case Select(qual, name) if (name.isTermName && needsParentheses(qual)(insideLabelDef = false)) || isIntLitWithDecodedOp(qual, name) => s"(${resolveSelect(qual)}).${printedName(name)}"
case Select(qual, name) if name.isTermName => s"${resolveSelect(qual)}.${printedName(name)}"
case Select(qual, name) if name.isTypeName => s"${resolveSelect(qual)}#${blankForOperatorName(name)}%${printedName(name)}"
case Ident(name) => printedName(name)
case _ => render(t, new CodePrinter(_, printRootPkg))
}
}
object EmptyTypeTree {
def unapply(tt: TypeTree): Boolean = tt match {
case build.SyntacticEmptyTypeTree() if tt.wasEmpty || tt.isEmpty => true
case _ => false
}
}
protected def isEmptyTree(tree: Tree) =
tree match {
case EmptyTree | EmptyTypeTree() => true
case _ => false
}
protected def originalTypeTrees(trees: List[Tree]) =
trees.filter(!isEmptyTree(_)) map {
case tt: TypeTree if tt.original != null => tt.original
case tree => tree
}
val defaultClasses = List(tpnme.AnyRef, tpnme.Object)
val defaultTraitsForCase = List(tpnme.Product, tpnme.Serializable)
protected def removeDefaultTypesFromList(trees: List[Tree])(classesToRemove: List[Name] = defaultClasses)(traitsToRemove: List[Name]) = {
@tailrec
def removeDefaultTraitsFromList(trees: List[Tree], traitsToRemove: List[Name]): List[Tree] =
trees match {
case init :+ last => last match {
case Select(Select(Ident(nme.scala_), nme.PACKAGE), name) if traitsToRemove.contains(name) =>
removeDefaultTraitsFromList(init, traitsToRemove)
case Select(Ident(nme.scala_), name) if traitsToRemove.contains(name) =>
removeDefaultTraitsFromList(init, traitsToRemove)
case _ => trees
}
case _ => trees
}
removeDefaultTraitsFromList(removeDefaultClassesFromList(trees, classesToRemove), traitsToRemove)
}
protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) =
originalTypeTrees(trees) filter {
case Select(Ident(sc), name) => !(classesToRemove.contains(name) && sc == nme.scala_)
case tt: TypeTree if tt.tpe != null => !(classesToRemove contains(newTypeName(tt.tpe.toString())))
case _ => true
}
protected def syntheticToRemove(tree: Tree) =
tree match {
case _: ValDef | _: TypeDef => false // don't remove ValDef and TypeDef
case md: MemberDef if md.mods.isSynthetic => true
case _ => false
}
override def printOpt(prefix: String, tree: Tree) =
if (!isEmptyTree(tree)) super.printOpt(prefix, tree)
override def printColumn(ts: List[Tree], start: String, sep: String, end: String) = {
super.printColumn(ts.filter(!syntheticToRemove(_)), start, sep, end)
}
def printFlags(mods: Modifiers, primaryCtorParam: Boolean = false): Unit = {
val base = AccessFlags | OVERRIDE | ABSTRACT | FINAL | SEALED | LAZY
val mask = if (primaryCtorParam) base else base | IMPLICIT
val s = mods.flagString(mask)
if (s != "") print(s"$s ")
// case flag should be the last
if (mods.isCase) print(mods.flagBitsToString(CASE) + " ")
if (mods.isAbstractOverride) print("abstract override ")
}
override def printModifiers(tree: Tree, mods: Modifiers): Unit = printModifiers(mods, primaryCtorParam = false)
def printModifiers(mods: Modifiers, primaryCtorParam: Boolean): Unit = {
def modsAccepted = List(currentTree, currentParent) exists (_ map {
case _: ClassDef | _: ModuleDef | _: Template | _: PackageDef => true
case _ => false
} getOrElse false)
if (currentParent.isEmpty || modsAccepted)
printFlags(mods, primaryCtorParam)
else
List(IMPLICIT, CASE, LAZY, SEALED).foreach{flag => if (mods.hasFlag(flag)) print(s"${mods.flagBitsToString(flag)} ")}
}
def printVParam(vd: ValDef, primaryCtorParam: Boolean): Unit = {
printPosition(vd)
printAnnotations(vd)
val mutableOrOverride = vd.mods.isOverride || vd.mods.isMutable
val hideCtorMods = vd.mods.isParamAccessor && vd.mods.isPrivateLocal && !mutableOrOverride
val hideCaseCtorMods = vd.mods.isCaseAccessor && vd.mods.isPublic && !mutableOrOverride
if (primaryCtorParam && !(hideCtorMods || hideCaseCtorMods)) {
printModifiers(vd.mods, primaryCtorParam)
print(if (vd.mods.isMutable) "var " else "val ")
}
print(printedName(vd.name), blankForName(vd.name))
printOpt(": ", vd.tpt)
printOpt(" = ", vd.rhs)
}
def printTParam(td: TypeDef, primaryCtorParam: Boolean): Unit = {
printPosition(td)
print(printedName(td.name))
printTypeParams(td.tparams)
print(td.rhs)
}
override def printVParam(vd: ValDef): Unit = printVParam(vd, primaryCtorParam = false)
override def printTParam(td: TypeDef): Unit = printTParam(td, primaryCtorParam = false)
protected def printArgss(argss: List[List[Tree]]) =
argss foreach {x: List[Tree] => if (!(x.isEmpty && argss.size == 1)) printRow(x, "(", ", ", ")")}
override def printAnnotations(tree: MemberDef) = {
val annots = tree.mods.annotations
annots foreach {annot => printAnnot(annot); print(" ")}
}
protected def printAnnot(tree: Tree) = {
tree match {
case treeInfo.Applied(core, _, argss) =>
print("@")
core match {
case Select(New(ann), _) => print(ann)
case _ =>
}
printArgss(argss)
case _ => super.printTree(tree)
}
}
override def printTree(tree: Tree): Unit = {
parentsStack.push(tree)
try {
processTreePrinting(tree)
printTypesInfo(tree)
} finally parentsStack.pop()
}
def processTreePrinting(tree: Tree): Unit = {
tree match {
// don't remove synthetic ValDef/TypeDef
case _ if syntheticToRemove(tree) =>
case cl @ ClassDef(mods, name, tparams, impl) =>
if (mods.isJavaDefined) super.printTree(cl)
printAnnotations(cl)
// traits
val clParents: List[Tree] = if (mods.isTrait) {
// avoid abstract modifier for traits
printModifiers(tree, mods &~ ABSTRACT)
print("trait ", printedName(name))
printTypeParams(tparams)
val build.SyntacticTraitDef(_, _, _, _, parents, _, _) = tree: @unchecked
parents
// classes
} else {
printModifiers(tree, mods)
print("class ", printedName(name))
printTypeParams(tparams)
cl match {
case build.SyntacticClassDef(_, _, _, ctorMods, vparamss, earlyDefs, parents, selfType, body) =>
// constructor's modifier
if (ctorMods.hasFlag(AccessFlags) || ctorMods.hasAccessBoundary) {
print(" ")
printModifiers(ctorMods, primaryCtorParam = false)
}
def printConstrParams(ts: List[ValDef]): Unit = {
parenthesize() {
printImplicitInParamsList(ts)
printSeq(ts)(printVParam(_, primaryCtorParam = true))(print(", "))
}
}
// constructor's params processing (don't print single empty constructor param list)
vparamss match {
case Nil | List(Nil) if !mods.isCase && !ctorMods.hasFlag(AccessFlags) =>
case _ => vparamss foreach printConstrParams
}
parents
case _ =>
// Can get here with erroneous code, like `{@deprecatedName `
Nil
}
}
// get trees without default classes and traits (when they are last)
val printedParents = removeDefaultTypesFromList(clParents)()(if (mods.hasFlag(CASE)) defaultTraitsForCase else Nil)
print(if (mods.isDeferred) "<: " else if (printedParents.nonEmpty) " extends " else "", impl)
case pd @ PackageDef(packaged, stats) =>
packaged match {
case Ident(name) if name == nme.EMPTY_PACKAGE_NAME =>
printSeq(stats) {
print(_)
} {
println()
println()
};
case _ =>
printPackageDef(pd, scala.util.Properties.lineSeparator)
}
case md @ ModuleDef(mods, name, impl) =>
printAnnotations(md)
printModifiers(tree, mods)
val Template(parents, _, _) = impl
val parWithoutAnyRef = removeDefaultClassesFromList(parents)
print("object " + printedName(name), if (parWithoutAnyRef.nonEmpty) " extends " else "", impl)
case vd @ ValDef(mods, name, tp, rhs) =>
printValDef(vd, printedName(name)) {
// place space after symbolic def name (val *: Unit does not compile)
printOpt(s"${blankForName(name)}: ", tp)
} {
if (!mods.isDeferred) print(" = ", if (rhs.isEmpty) "_" else rhs)
}
case dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) =>
printDefDef(dd, printedName(name)) {
if (tparams.isEmpty && (vparamss.isEmpty || vparamss(0).isEmpty)) print(blankForName(name))
printOpt(": ", tp)
} {
printOpt(" = " + (if (mods.isMacro) "macro " else ""), rhs)
}
case td @ TypeDef(mods, name, tparams, rhs) =>
printTypeDef(td, printedName(name))
case LabelDef(name, params, rhs) =>
if (name.startsWith(nme.WHILE_PREFIX)) {
val If(cond, thenp, _) = rhs: @unchecked
print("while (", cond, ") ")
val Block(list, wh) = thenp: @unchecked
printColumn(list, "", ";", "")
} else if (name.startsWith(nme.DO_WHILE_PREFIX)) {
val Block(bodyList, If(cond, _, _)) = rhs: @unchecked
print("do ")
printColumn(bodyList, "", ";", "")
print(" while (", cond, ") ")
} else {
print(printedName(name)); printLabelParams(params)
printBlock(rhs)
}
case imp @ Import(expr, _) =>
printImport(imp, resolveSelect(expr))
case t @ Template(parents, self, tbody) =>
val body = treeInfo.untypecheckedTemplBody(t)
val printedParents =
currentParent map {
case _: CompoundTypeTree => parents
case ClassDef(mods, name, _, _) if mods.isCase => removeDefaultTypesFromList(parents)()(defaultTraitsForCase)
case _ => removeDefaultClassesFromList(parents)
} getOrElse (parents)
val primaryCtr = treeInfo.firstConstructor(body)
val ap: Option[Apply] = primaryCtr match {
case DefDef(_, _, _, _, _, Block(ctBody, _)) =>
val earlyDefs = treeInfo.preSuperFields(ctBody) ::: body.filter {
case td: TypeDef => treeInfo.isEarlyDef(td)
case _ => false
}
if (earlyDefs.nonEmpty) {
print("{")
printColumn(earlyDefs, "", ";", "")
print("} " + (if (printedParents.nonEmpty) "with " else ""))
}
ctBody collectFirst {
case apply: Apply => apply
}
case _ => None
}
if (printedParents.nonEmpty) {
val (clParent :: traits) = printedParents: @unchecked
print(clParent)
val constrArgss = ap match {
case Some(treeInfo.Applied(_, _, argss)) => argss
case _ => Nil
}
printArgss(constrArgss)
if (traits.nonEmpty) {
printRow(traits, " with ", " with ", "")
}
}
/* Remove primary constr def and constr val and var defs
* right contains all constructors
*/
val (left, right) = body.filter {
// remove valdefs defined in constructor and presuper vals
case vd: ValDef => !vd.mods.isParamAccessor && !treeInfo.isEarlyValDef(vd)
// remove $this$ from traits
case dd: DefDef => dd.name != nme.MIXIN_CONSTRUCTOR
case td: TypeDef => !treeInfo.isEarlyDef(td)
case EmptyTree => false
case _ => true
} span {
case dd: DefDef => dd.name != nme.CONSTRUCTOR
case _ => true
}
val modBody = (left ::: right.drop(1))
val showBody = !(modBody.isEmpty && (self == noSelfType || self.isEmpty))
if (showBody) {
if (self.name != nme.WILDCARD) {
print(" { ", self.name)
printOpt(": ", self.tpt)
print(" =>")
} else if (self.tpt.nonEmpty) {
print(" { _ : ", self.tpt, " =>")
} else {
print(" {")
}
printColumn(modBody, "", ";", "}")
}
case bl @ Block(stats, expr) =>
printBlock(treeInfo.untypecheckedBlockBody(bl), expr)
case Match(selector, cases) =>
/* Insert braces if match is inner
* make this function available for other cases
* passing required type for checking
*/
def insertBraces(body: => Unit): Unit =
if (parentsStack.nonEmpty && parentsStack.tail.exists(_.isInstanceOf[Match])) {
print("(")
body
print(")")
} else body
val printParentheses = needsParentheses(selector)(insideLabelDef = false)
tree match {
case Match(EmptyTree, cs) =>
printColumn(cases, "{", "", "}")
case _ =>
insertBraces {
parenthesize(printParentheses)(print(selector))
printColumn(cases, " match {", "", "}")
}
}
case cd @ CaseDef(pat, guard, body) =>
printCaseDef(cd)
case Star(elem) =>
print(elem, "*")
case Bind(name, t) =>
if (t == EmptyTree) print("(", printedName(name), ")")
else if (t.exists(_.isInstanceOf[Star])) print(printedName(name), " @ ", t)
else print("(", printedName(name), " @ ", t, ")")
case f @ Function(vparams, body) =>
// parentheses are not allowed for val a: Int => Int = implicit x => x
val printParentheses = vparams match {
case head :: _ => !head.mods.isImplicit
case _ => true
}
printFunction(f)(printValueParams(vparams, inParentheses = printParentheses))
case Typed(expr, tp) =>
def printTp() = print("(", tp, ")")
tp match {
case EmptyTree | EmptyTypeTree() => printTp()
// case for untypechecked trees
case Annotated(annot, arg) if (expr ne null) && (arg ne null) && expr.equalsStructure(arg) => printTp() // remove double arg - 5: 5: @unchecked
case tt: TypeTree if tt.original.isInstanceOf[Annotated] => printTp()
case Function(List(), EmptyTree) => print("(", expr, " _)") //func _
// parentheses required when (a match {}) : Type
case _ => print("((", expr, "): ", tp, ")")
}
// print only fun when targs are TypeTrees with empty original
case TypeApply(fun, targs) =>
if (targs.exists(isEmptyTree(_))) {
print(fun)
} else super.printTree(tree)
case Apply(fun, vargs) =>
tree match {
// processing methods ending on colons (x \: list)
case Apply(Block(l1 @ List(sVD: ValDef), a1 @ Apply(Select(_, methodName), l2 @ List(Ident(iVDName)))), l3)
if sVD.mods.isSynthetic && nme.isLeftAssoc(methodName) && sVD.name == iVDName =>
val printBlock = Block(l1, Apply(a1, l3))
print(printBlock)
case Apply(tree1, _) if (needsParentheses(tree1)(insideAnnotated = false)) =>
parenthesize()(print(fun)); printRow(vargs, "(", ", ", ")")
case _ => super.printTree(tree)
}
case UnApply(fun, args) =>
fun match {
case treeInfo.Unapplied(body) =>
body match {
case Select(qual, name) if name == nme.unapply => print(qual)
case TypeApply(Select(qual, name), _) if name == nme.unapply || name == nme.unapplySeq =>
print(qual)
case _ => print(body)
}
case _ => print(fun)
}
printRow(args, "(", ", ", ")")
case st @ Super(This(qual), mix) =>
printSuper(st, printedName(qual), checkSymbol = false)
case th @ This(qual) =>
if (tree.hasExistingSymbol && tree.symbol.hasPackageFlag) print(tree.symbol.fullName)
else printThis(th, printedName(qual))
// remove this prefix from constructor invocation in typechecked trees: this.this -> this
case Select(This(_), name @ nme.CONSTRUCTOR) => print(printedName(name))
case Select(qual: New, name) =>
print(qual)
case Select(qual, name) =>
@tailrec
def checkRootPackage(tr: Tree): Boolean =
(currentParent match { //check that Select is not for package def name
case Some(_: PackageDef) => false
case _ => true
}) && (tr match { // check that Select contains package
case Select(q, _) => checkRootPackage(q)
case _: Ident | _: This => val sym = tr.symbol
tr.hasExistingSymbol && sym.hasPackageFlag && sym.name != nme.ROOTPKG
case _ => false
})
if (printRootPkg && checkRootPackage(tree)) print(s"${printedName(nme.ROOTPKG)}.")
val printParentheses = needsParentheses(qual)(insideAnnotated = false) || isIntLitWithDecodedOp(qual, name)
if (printParentheses) print("(", resolveSelect(qual), ").", printedName(name))
else print(resolveSelect(qual), ".", printedName(name))
case id @ Ident(name) =>
if (name.nonEmpty) {
if (name == nme.dollarScope) {
print(s"scala.xml.${nme.TopScope}")
} else {
val str = printedName(name)
val strIsBackquoted = str.startsWith("`") && str.endsWith("`")
print(if (id.isBackquoted && !strIsBackquoted) "`" + str + "`" else str)
}
} else {
print("")
}
case Literal(k @ Constant(s: String)) if s.contains(Chars.LF) =>
val tq = "\"" * 3
val lines = s.linesIterator.toList
if (lines.lengthCompare(1) <= 0) print(k.escapedStringValue)
else {
val tqp = """["]{3}""".r
val tqq = """""\\"""" // ""\" is triple-quote quoted
print(tq)
printSeq(lines.map(x => tqp.replaceAllIn(x, tqq)))(print(_))(print(Chars.LF))
print(tq)
}
case Literal(x) =>
// processing Float constants
val suffix = x.value match { case _: Float => "F" case _ => "" }
print(s"${x.escapedStringValue}${suffix}")
case an @ Annotated(ap, tree) =>
val printParentheses = needsParentheses(tree)()
parenthesize(printParentheses) { print(tree) }; print(if (tree.isType) " " else ": ")
printAnnot(ap)
case SelectFromTypeTree(qualifier, selector) =>
print("(", qualifier, ")#", blankForOperatorName(selector), printedName(selector))
case tt: TypeTree =>
if (!isEmptyTree(tt)) {
val original = tt.original
if (original != null) print(original)
else super.printTree(tree)
}
case AppliedTypeTree(tp, args) =>
// it's possible to have (=> String) => String type but Function1[=> String, String] is not correct
val containsByNameTypeParam = args exists treeInfo.isByNameParamType
if (containsByNameTypeParam) {
print("(")
printRow(args.init, "(", ", ", ")")
print(" => ", args.last, ")")
} else {
if (treeInfo.isRepeatedParamType(tree) && args.nonEmpty) {
print(args(0), "*")
} else if (treeInfo.isByNameParamType(tree)) {
print("=> ", if (args.isEmpty) "()" else args(0))
} else
super.printTree(tree)
}
case ExistentialTypeTree(tpt, whereClauses) =>
print("(", tpt)
printColumn(whereClauses, " forSome { ", ";", "})")
case EmptyTree =>
case tree => super.printTree(tree)
}
}
}
/** Hook for extensions */
def xprintTree(treePrinter: InternalTreePrinter, tree: Tree) =
treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")"))
def newCodePrinter(writer: PrintWriter, tree: Tree, printRootPkg: Boolean): InternalTreePrinter =
new CodePrinter(writer, printRootPkg)
def newTreePrinter(writer: PrintWriter): InternalTreePrinter = new InternalTreePrinter(writer)
def newTreePrinter(stream: OutputStream): InternalTreePrinter = newTreePrinter(new PrintWriter(stream))
def newTreePrinter(): InternalTreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter))
/** A writer that writes to the current Console and
* is sensitive to replacement of the Console's
* output stream.
*/
object ConsoleWriter extends Writer {
override def write(str: String): Unit = { Console.print(str) }
def write(cbuf: Array[Char], off: Int, len: Int): Unit = {
write(new String(cbuf, off, len))
}
def close = { /* do nothing */ }
def flush = { /* do nothing */ }
}
def newRawTreePrinter(writer: PrintWriter): RawTreePrinter = new RawTreePrinter(writer)
// provides footnotes for types and mirrors
private class Footnotes {
import scala.collection.mutable.{Map, WeakHashMap, SortedSet}
private[this] val index = Map[Class[_], WeakHashMap[Any, Int]]()
private def classIndex[T: ClassTag] = index.getOrElseUpdate(classTag[T].runtimeClass, WeakHashMap[Any, Int]())
private[this] val counters = Map[Class[_], Int]()
private def nextCounter[T: ClassTag] = {
val clazz = classTag[T].runtimeClass
counters.getOrElseUpdate(clazz, 0)
counters(clazz) = counters(clazz) + 1
counters(clazz)
}
private[this] val footnotes = Map[Class[_], SortedSet[Int]]()
private def classFootnotes[T: ClassTag] = footnotes.getOrElseUpdate(classTag[T].runtimeClass, SortedSet[Int]())
def put[T: ClassTag](any: T): Int = {
val index = classIndex[T].getOrElseUpdate(any, nextCounter[T])
classFootnotes[T] += index
index
}
def get[T: ClassTag]: List[(Int, Any)] =
classFootnotes[T].toList map (fi => (fi, classIndex[T].find{ case (any, ii) => ii == fi }.get._1))
def print[T: ClassTag](printer: Printers.super.TreePrinter): Unit = {
val footnotes = get[T]
if (footnotes.nonEmpty) {
printer.print(EOL)
footnotes.zipWithIndex foreach {
case ((fi, any), ii) =>
printer.print("[", fi, "] ", any)
if (ii < footnotes.length - 1) printer.print(EOL)
}
}
}
}
// emits more or less verbatim representation of the provided tree
class RawTreePrinter(out: PrintWriter) extends super.TreePrinter {
private[this] var depth = 0
private[this] var printTypesInFootnotes = true
private[this] var printingFootnotes = false
private[this] val footnotes = new Footnotes()
def print(args: Any*): Unit = {
// don't print type footnotes if the argument is a mere type
if (depth == 0 && args.length == 1 && args(0) != null && args(0).isInstanceOf[Type])
printTypesInFootnotes = false
depth += 1
args foreach {
case expr: Expr[_] =>
print("Expr")
if (printTypes) print(expr.staticType)
print("(")
print(expr.tree)
print(")")
case EmptyTree =>
print("EmptyTree")
case self.noSelfType =>
print("noSelfType")
case self.pendingSuperCall =>
print("pendingSuperCall")
case tree: Tree =>
def hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol
val isError = hasSymbolField && (tree.symbol.name string_== nme.ERROR)
printProduct(
tree,
preamble = _ => {
if (printPositions) print(tree.pos.show)
print(tree.productPrefix)
if (printTypes && tree.tpe != null) print(tree.tpe)
},
body = {
case name: Name =>
if (isError) {
if (isError) print("<")
print(name)
if (isError) print(": error>")
} else if (hasSymbolField) {
tree match {
case refTree: RefTree =>
if (tree.symbol.name != refTree.name) print("[", tree.symbol, " aka ", refTree.name, "]")
else print(tree.symbol)
case defTree: DefTree =>
print(tree.symbol)
case _ =>
print(tree.symbol.name)
}
} else {
print(name)
}
case Constant(s: String) =>
print("Constant(\"" + s + "\")")
case Constant(null) =>
print("Constant(null)")
case Constant(value) =>
print("Constant(" + value + ")")
case arg =>
print(arg)
},
postamble = {
case tree @ TypeTree() if tree.original != null => print(".setOriginal(", tree.original, ")")
case _ => // do nothing
})
case sym: Symbol =>
if (sym == NoSymbol) print("NoSymbol")
else if (sym.isStatic && (sym.isClass || sym.isModule)) print(sym.fullName)
else print(sym.name)
if (printIds) print("#", sym.id)
if (printOwners) print("@", sym.owner.id)
if (printKinds) print("#", sym.abbreviatedKindString)
if (printMirrors) print("%M", footnotes.put[scala.reflect.api.Mirror[_]](mirrorThatLoaded(sym)))
case tag: TypeTag[_] =>
print("TypeTag(", tag.tpe, ")")
case tag: WeakTypeTag[_] =>
print("WeakTypeTag(", tag.tpe, ")")
case tpe: Type =>
val defer = printTypesInFootnotes && !printingFootnotes
if (defer) print("[", footnotes.put(tpe), "]")
else tpe match {
case NoType => print("NoType")
case NoPrefix => print("NoPrefix")
case _ => printProduct(tpe.asInstanceOf[Product])
}
case mods: Modifiers =>
print("Modifiers(")
if (mods.flags != NoFlags || mods.privateWithin != tpnme.EMPTY || mods.annotations.nonEmpty) print(show(mods.flags))
if (mods.privateWithin != tpnme.EMPTY || mods.annotations.nonEmpty) { print(", "); print(mods.privateWithin) }
if (mods.annotations.nonEmpty) { print(", "); print(mods.annotations); }
print(")")
case name: Name =>
print(show(name))
case scope: Scope =>
print("Scope")
printIterable(scope.toList)
case list: List[_] =>
print("List")
printIterable(list)
case product: Product =>
printProduct(product)
case arg =>
out.print(arg)
}
depth -= 1
if (depth == 0 && !printingFootnotes) {
printingFootnotes = true
footnotes.print[Type](this)
footnotes.print[scala.reflect.api.Mirror[_]](this)
printingFootnotes = false
}
}
def printProduct(
p: Product,
preamble: Product => Unit = p => print(p.productPrefix),
body: Any => Unit = print(_),
postamble: Product => Unit = p => print("")): Unit =
{
preamble(p)
printIterable(p.productIterator.toList, body = body)
postamble(p)
}
def printIterable(
iterable: List[_],
preamble: => Unit = print(""),
body: Any => Unit = print(_),
postamble: => Unit = print("")): Unit =
{
preamble
print("(")
val it = iterable.iterator
while (it.hasNext) {
body(it.next())
print(if (it.hasNext) ", " else "")
}
print(")")
postamble
}
}
def show(name: Name): String = name match {
case tpnme.WILDCARD => "typeNames.WILDCARD"
case tpnme.EMPTY => "typeNames.EMPTY"
case tpnme.ERROR => "typeNames.ERROR"
case tpnme.PACKAGE => "typeNames.PACKAGE"
case tpnme.WILDCARD_STAR => "typeNames.WILDCARD_STAR"
case nme.WILDCARD => "termNames.WILDCARD"
case nme.EMPTY => "termNames.EMPTY"
case nme.ERROR => "termNames.ERROR"
case nme.PACKAGE => "termNames.PACKAGE"
case nme.CONSTRUCTOR => "termNames.CONSTRUCTOR"
case nme.ROOTPKG => "termNames.ROOTPKG"
case _ =>
val prefix = if (name.isTermName) "TermName(\"" else "TypeName(\""
prefix + name.toString + "\")"
}
def show(flags: FlagSet): String = {
if (flags == NoFlags) nme.NoFlags.toString
else {
val s_flags = new scala.collection.mutable.ListBuffer[String]
def hasFlag(left: Long, right: Long): Boolean = (left & right) != 0
for (i <- 0 to 63 if hasFlag(flags, 1L << i))
s_flags += flagToString(1L << i).replace("<", "").replace(">", "").toUpperCase
s_flags mkString " | "
}
}
def show(position: Position): String = {
position.show
}
def showDecl(sym: Symbol): String = {
if (!isCompilerUniverse) definitions.fullyInitializeSymbol(sym)
sym.defString
}
}