in scala/tasty-reader/src/TreePrinter.scala [864:1079]
private def parametersIn(sb: StringBuilder, node: Node, template: Option[Node] = None, definition: Option[Node] = None, target: Target = Target.Definition, modifiers: StringBuilder => Unit = _ => (), withSynthetic: Boolean = true, resultType: Option[String] = None): Unit = {
val tps = target match {
case Target.This => Seq.empty
case Target.Definition => node.children
case Target.Extension => node.children.takeWhile(!_.is(PARAM))
case Target.ExtensionMethod => node.children.dropWhile(!_.is(PARAM))
}
val templateTypeParams = template.map(_.children.filter(_.is(TYPEPARAM)).iterator)
val isPrivateConstructor = node.is(DEFDEF) && node.names == Seq("<init>") && node.contains(PRIVATE)
lazy val contextBounds = if (!privateMembers && isPrivateConstructor) Seq.empty else node.children.collect {
case param @ Node3(PARAM, Seq(name), Seq(tail, _*)) if (param.contains(IMPLICIT) || param.contains(GIVEN)) && hasSingleArgument(tail) && (name.startsWith("evidence$") || !name.contains("$") && param.position().zip(tail.firstChild.position()).exists(_ == _)) =>
val Seq(designator, argument) = tail.children
(simple(textOfType(argument)), simple(textOfType(designator)), if (name.startsWith("evidence$")) None else Some(name))
}
var open = false
var next = false
tps.foreach {
case node @ Node2(TYPEPARAM, Seq(name)) if withSynthetic || !name.startsWith("_$") =>
if (!open) {
sb ++= "["
open = true
next = false
}
if (next) {
sb ++= ", "
}
textOfAnnotationIn(sb, "", node, " ")
if (template.isEmpty) { // Deduplicate?
if (node.contains(COVARIANT)) {
sb ++= "+"
}
if (node.contains(CONTRAVARIANT)) {
sb ++= "-"
}
}
templateTypeParams.map(_.next()).foreach { typeParam =>
textOfAnnotationIn(sb, "", typeParam, " ")
if (typeParam.contains(COVARIANT)) {
sb ++= "+"
}
if (typeParam.contains(CONTRAVARIANT)) {
sb ++= "-"
}
}
val nameId = if (name.startsWith("_$")) "_" else id(name)
sb ++= nameId // Detect Unique name?
node.children match {
case Seq(lambda @ Node1(LAMBDAtpt), _*) =>
parametersIn(sb, lambda)
lambda.children.lastOption match { // Deduplicate somehow?
case Some(bounds @ Node1(TYPEBOUNDStpt)) =>
boundsIn(sb, bounds)
case _ =>
}
case Seq(bounds @ Node1(TYPEBOUNDStpt), _*) =>
boundsIn(sb, bounds)
case _ =>
}
contextBounds.foreach { case (id, tpe, symbol) =>
if (id == name) {
if (needsSpace(nameId)) {
sb ++= " "
}
sb ++= ": "
sb ++= tpe
symbol.foreach { s =>
sb ++= " as "
sb ++= s
}
}
}
next = true
case _ =>
}
if (open) {
sb ++= "]"
}
val previousLength = sb.length
modifiers(sb)
val hasModifiers = sb.length > previousLength
val ps = target match {
case Target.This | Target.Definition => node.children
case Target.Extension =>
popExtensionParams(mutable.Stack[Node](node.children*))
case Target.ExtensionMethod =>
val stack = mutable.Stack[Node](node.children*)
popExtensionParams(stack)
stack.toSeq.dropWhile(_.is(SPLITCLAUSE))
}
val templateValueParams = template.map(_.children.filter(_.is(PARAM)).iterator)
open = false
next = false
var isFirstClause = true
var isImplicitClause = false
var isGivenClause = false
val valueParameterStart = sb.length
var syntheticParameterNames = List.empty[(String, Int)]
ps.foreach {
case Node1(EMPTYCLAUSE) =>
if (open) {
sb ++= ")"
open = false
isFirstClause = false
}
sb ++= "()"
case Node1(SPLITCLAUSE) =>
sb ++= ")"
open = false
isFirstClause = false
case node @ Node3(PARAM, Seq(name), Seq(tail, _*)) if !((node.contains(IMPLICIT) || node.contains(GIVEN)) && hasSingleArgument(tail) && (name.startsWith("evidence$") || !name.contains("$") && node.position().zip(tail.firstChild.position()).exists(_ == _))) =>
if (!open) {
sb ++= "("
open = true
next = false
if (node.contains(GIVEN)) {
sb ++= "using "
isGivenClause = true
} else {
if (node.contains(IMPLICIT)) {
sb ++= "implicit "
isImplicitClause = true
}
}
}
val templateValueParam = templateValueParams.map(_.next())
if (privateMembers || !isPrivateConstructor || templateValueParam.exists(!_.contains(PRIVATE))) { // private (), variables in { ... } ?
if (next) {
sb ++= ", "
}
textOfAnnotationIn(sb, "", node, " ")
val tpe = textOfType(tail)
if (node.contains(INLINE) || tpe.endsWith(" @_root_.scala.annotation.internal.InlineParam")) {
sb ++= "inline "
}
if (!definition.exists(isGivenClass0)) {
templateValueParam.foreach { valueParam =>
if (!valueParam.contains(LOCAL) || valueParam.contains(PROTECTED)) {
textOfAnnotationIn(sb, "", valueParam, " ")
val sb1 = new StringBuilder() // Reuse?
val isPrivate = valueParam.contains(PRIVATE)
modifiersIn(sb1, valueParam, (if (isImplicitClause) Set(IMPLICIT) else if (isGivenClause) Set(GIVEN) else Set.empty) ++ (if (privateMembers || !isPrivate) Set.empty else Set(ABSTRACT, OVERRIDE, PRIVATE, IMPLICIT, FINAL)))
sb ++= sb1
if (privateMembers || !isPrivate) {
if (valueParam.contains(MUTABLE)) {
sb ++= "var "
} else {
if (!(isFirstClause && definition.exists(_.contains(CASE)) && valueParam.modifierTags.forall(it => it == CASEaccessor || it == HASDEFAULT))) {
sb ++= "val "
}
}
}
}
}
}
val isSyntheticParam = node.contains(SYNTHETIC) || templateValueParam.exists(_.contains(SYNTHETIC))
if (!isSyntheticParam) {
val nameId = id(name, parameter = true)
sb ++= nameId
if (needsSpace(nameId)) {
sb ++= " "
}
sb ++= ": "
} else {
syntheticParameterNames ::= (name, sb.length)
}
sb ++= simple(tpe).stripSuffix(" @_root_.scala.annotation.internal.InlineParam")
if (node.contains(HASDEFAULT)) {
sb ++= " = "
sb ++= CompiledCode
}
next = true
}
case _ =>
}
if (open) {
if (!next) {
if (isImplicitClause) {
sb.setLength(sb.length - 9)
} else if (isGivenClause) {
sb.setLength(sb.length - 6)
}
}
sb ++= ")"
}
val valueParameterText = sb.substring(valueParameterStart) // Check nodes rather than text?
syntheticParameterNames.foreach { (name, index) =>
//example from `scala.annotation.MacroAnnotation#transform`
//original code : def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition]
//printed code : def transform(using _root_.scala.quoted.Quotes)(tree: x$1.reflect.Definition): List[x$1.reflect.Definition]
val syntheticParameterIsLikelyUsedInSignature =
valueParameterText.contains(name) || resultType.exists(_.contains(name))
val insertSyntheticParameterName = syntheticParameterIsLikelyUsedInSignature
if (insertSyntheticParameterName) {
val nameId = id(name)
val paramNamePrefix = name + (if (needsSpace(nameId)) " " else "") + ": "
sb.insert(index, paramNamePrefix)
}
}
if (template.isEmpty || hasModifiers || definition.exists(it => it.contains(CASE) && !it.contains(OBJECT))) {} else {
if (sb.length >= 2 && sb.substring(sb.length - 2, sb.length()) == "()" && !(sb.length > 2 && sb.charAt(sb.length - 3) == ')')) {
sb.delete(sb.length - 2, sb.length())
}
}
}