def buildReplacement()

in scala/structural-search/src/org/jetbrains/plugins/scala/structuralSearch/replace/ScalaReplacementBuilder.scala [188:432]


  def buildReplacement(element: PsiElement, scopeRes: MatchResult, result: StringBuilder): Unit =
    buildReplacement(element, Some(scopeRes), result)
  def buildReplacement(element: PsiElement, scopeRes: Option[MatchResult], result: StringBuilder, insertBefore: InsertBeAf = Map(), insertAfter: InsertBeAf = Map()): Unit = {
    element match {
      case replacePattern: ScExtendsBlock if replacePattern.getParent.is[ScClass | ScTrait | ScObject | ScGivenDefinition] =>
        val skipBlocks: Skippers = mutable.Map()
        replacePattern.templateParents match {
          case None =>
          case Some(par) => skipBlocks.put(replacePattern.getFirstChild, (if (par.getNextSibling.is[PsiWhiteSpace]) par.getNextSibling else par, par, 0))
        }
        buildChildren(element, scopeRes, result, insertAfter = insertAfter, skipBlock = skipBlocks)
      case replacePattern: ScTemplateBody if replacePattern.getParent.getParent.is[ScClass | ScTrait | ScObject | ScGivenDefinition] =>
        buildChildren(element, scopeRes, result, insertAfter = insertAfter)
      // Build class likes
      case replacePattern: ScTypeDefinition if replacePattern.is[ScClass | ScTrait | ScObject | ScGivenDefinition] =>
        def buildClass(subRes: Option[MatchResult], insertBefore: InsertBeAf = Map(), insertAfter: InsertBeAf = Map()): Unit = {
          val skipBlocks: Skippers = mutable.Map()
          createAnnotationSkipper(replacePattern, replacePattern.getModifierList, skipBlocks)
          createTypeParametersSkippers(replacePattern, skipBlocks)
          replacePattern.asOptionOf[ScConstructorOwner].flatMap(_.constructor) match {
            case None =>
            case Some(constr) => skipBlocks.put(constr, (constr, constr, 2))
          }

          buildChildren(replacePattern, subRes, result, insertBefore = insertBefore, insertAfter = insertAfter, skipBlock = skipBlocks)
        }
        handleScope(replacePattern, Option(replacePattern.nameId), scopeRes, result, Some("\n\n"), (ident, subRes) => {
          val parameterMatch = subRes.getMatch
          val searchPattern = findMatchResult(subRes, PATTERN_CONTEXT).getOrElse(throw new Exception("Expected pattern context")).getMatch

          val annotationCopy = createAnnotationCopy(searchPattern, replacePattern, replacePattern.getModifierList, parameterMatch)
          val modifierCopy = createModifierCopy(searchPattern, replacePattern, parameterMatch)
          val typeParaCopy = createTypeParaCopy(searchPattern, replacePattern, ident, parameterMatch)
          val primConstrCopy = ifNotMentioned(searchPattern.asOptionOf[ScConstructorOwner].flatMap(_.constructor.filter(_.getTextLength > 0)),
            replacePattern.asOptionOf[ScConstructorOwner].flatMap(_.constructor.filter(_.getTextLength > 0)),
            replacePattern.typeParametersClause.getOrElse(ident), parameterMatch.asOptionOf[ScConstructorOwner].flatMap(_.constructor.map(_.getText))
          )
          val parentsCopy = ifNotMentioned(searchPattern.asOptionOf[ScTemplateDefinition].flatMap(_.extendsBlock.templateParents),
            replacePattern.extendsBlock.templateParents,
            replacePattern.asOptionOf[ScConstructorOwner].flatMap(_.constructor)
              .orElse(replacePattern.typeParametersClause)
              .getOrElse(ident),
            parameterMatch.asOptionOf[ScTemplateDefinition].flatMap(_.extendsBlock.templateParents.map(par => if (par.getTextLength > 0) " extends " + par.getText else "")))

          val noBody = replacePattern.extendsBlock.templateBody.isEmpty
          val (bodyStart, enclStartAdd: InsertBeAf) = {
            if (noBody)
              (replacePattern.extendsBlock, Map(replacePattern.extendsBlock.asInstanceOf[PsiElement] -> " {"))
            else
              (replacePattern.extendsBlock.templateBody.get.getEnclosingStartElement.getOrElse(throw Exception("Body needs to have start element")), Map[PsiElement, String]())
          }

          val propCopy = ifNotMentioned(searchPattern.asOptionOf[ScTemplateDefinition].flatMap(_.properties.headOption),
            replacePattern.properties.headOption, bodyStart,
            parameterMatch.asOptionOf[ScTemplateDefinition].map(_.properties.map("\n  " + _.getText).mkString))
          val functionCopy = ifNotMentioned(searchPattern.asOptionOf[ScTemplateDefinition].flatMap(_.functions.headOption),
            replacePattern.functions.headOption, bodyStart,
            parameterMatch.asOptionOf[ScTemplateDefinition].map(_.functions.map("\n  " + _.getText).mkString))
          val subClassCopy = ifNotMentioned(searchPattern.asOptionOf[ScTemplateDefinition].flatMap(_.typeDefinitions.headOption),
            replacePattern.typeDefinitions.headOption, bodyStart,
            parameterMatch.asOptionOf[ScTemplateDefinition].map(_.typeDefinitions.map("\n  " + _.getText).mkString))
          val insertBefore = mergeInserts(annotationCopy, modifierCopy)
          val insertAfter = mergeInserts(typeParaCopy, primConstrCopy, parentsCopy, enclStartAdd, propCopy, functionCopy, subClassCopy)
          buildClass(Some(subRes), insertBefore = insertBefore, insertAfter = insertAfter)
          if (noBody) result.append("\n}")
        }, Some(() => buildClass(scopeRes)))
      case g: ScGiven =>
        buildChildren(element, scopeRes, result)
      // Build function
      case replacePattern: ScFunction =>
        def buildFunc(subRes: Option[MatchResult], insertBefore: Map[PsiElement, String] = Map(), insertAfter: Map[PsiElement, String] = Map()): Unit = {
          val skipBlocks: Skippers = mutable.Map()
          createAnnotationSkipper(replacePattern, replacePattern.getModifierList, skipBlocks)
          createTypeParametersSkippers(replacePattern, skipBlocks)
          replacePattern.returnTypeElement match {
            case None =>
            case Some(ret) =>
              skipBlocks.put(replacePattern.paramClauses.getNextSibling, (ret, ret, 0))
          }
          replacePattern.asOptionOf[ScFunctionDefinition].flatMap(_.body) match {
            case None =>
            case Some(body) =>
              skipBlocks.put(replacePattern.returnTypeElement.getOrElse(replacePattern.paramClauses).getNextSibling, (body, body, 0))
          }
          buildChildren(replacePattern, subRes, result, insertBefore = insertBefore, insertAfter = insertAfter, skipBlock = skipBlocks)
        }
        handleScope(replacePattern, Option(replacePattern.nameId), scopeRes, result, Some("\n\n"), (ident, subRes) => {
          val parameterMatch = subRes.getMatch
          val searchPattern = findMatchResult(subRes, PATTERN_CONTEXT).getOrElse(throw new Exception("Expected pattern context")).getMatch

          val annotationsCopy = createAnnotationCopy(searchPattern, replacePattern, replacePattern.getModifierList, parameterMatch)
          val modifierCopy = createModifierCopy(searchPattern, replacePattern, parameterMatch)
          val typeParaCopy = createTypeParaCopy(searchPattern, replacePattern, ident, parameterMatch)
          val retParaCopy = createRetTypeEquivCopy(searchPattern, replacePattern, replacePattern.paramClauses, parameterMatch)
          val bodyCopy = createFuncBodyEquivCopy(searchPattern, replacePattern,
            replacePattern.returnTypeElement.getOrElse(replacePattern.paramClauses), parameterMatch)
          val insertBefore = mergeInserts(annotationsCopy, modifierCopy)
          val insertAfter = mergeInserts(typeParaCopy, retParaCopy, bodyCopy)

          buildFunc(Some(subRes), insertBefore = insertBefore, insertAfter = insertAfter)
        }, Some(() => buildFunc(scopeRes)))
      // Build parameter
      case replacePattern: ScParameter =>
        handleScope(replacePattern, Option(replacePattern.nameId), scopeRes, result, Some(", "), (ident, subRes) => {
          val parameterMatch = subRes.getMatch

          val searchPattern = findMatchResult(subRes, PATTERN_CONTEXT).getOrElse(throw new Exception("Expected pattern context")).getMatch

          {
            createAnnotationCopy(searchPattern, replacePattern, ident, parameterMatch, false).get(ident) match {
              case None =>
                replacePattern.annotations.foreach(anno => {
                  val prevSize = result.length()
                  buildReplacement(anno, subRes, result)
                  if (result.length() > prevSize)
                    result.append(" ")
                })
              case Some(cop) => result.append(cop)
            }
          }
          {
            val source = if replacePattern.isVal || replacePattern.isVar then replacePattern else parameterMatch
            if (source.asOptionOf[ScTypedDefinition].exists(_.isVal) || source.is[ScValue])
              result.append("val ")
            else if (source.asOptionOf[ScTypedDefinition].exists(_.isVar) || source.is[ScVariable])
              result.append("var ")
          }
          buildReplacement(ident, subRes, result)
          {
            replacePattern.typeElement match {
              case Some(typ) =>
                val sb = StringBuilder()
                buildReplacement(typ.getParent, subRes, sb)
                if (sb.nonEmpty) {
                  result.append(": ")
                  result.append(sb.result())
                }
              case None =>
                createRetTypeEquivCopy(searchPattern, replacePattern, ident, parameterMatch).get(ident) match {
                  case Some(cop) => result.append(cop)
                  case None =>
                }
            }
          }
          replacePattern.getDefaultExpression match {
            case Some(default) =>
              val sb = StringBuilder()
              buildReplacement(default, subRes, sb)
              if (sb.nonEmpty) {
                result.append(" = ")
                result.append(sb.result())
              }
            case None =>
              createFuncBodyEquivCopy(searchPattern, replacePattern, ident, parameterMatch).get(ident) match {
                case Some(cop) => result.append(cop)
                case None =>
              }
          }
        })
      case replacePattern: ScParameterClause =>
        result.append(replacePattern.getFirstChild.getText)
        var lastEl: Option[PsiElement] = None
        var foundFirst = false
        for (param <- replacePattern.parameters) {
          val sb = StringBuilder()
          buildReplacement(param, scopeRes, sb)
          if (sb.nonEmpty) {
            if (lastEl.nonEmpty && foundFirst) {
              var cur = lastEl.get.getNextSibling
              while (cur != param) {
                result.append(cur.getText)
                cur = cur.getNextSibling
              }
            }
            foundFirst = true
            result.append(sb.result)
          }
          lastEl = Some(param)
        }
        result.append(replacePattern.getLastChild.getText)
      // Value and Variable
      case replacePattern: ScValueOrVariable =>
        handleScope(replacePattern, Option.when(replacePattern.declaredNames.size == 1)(replacePattern.declaredElements.head.getParent), scopeRes, result, Some("\n"), (ident, subRes) => {
          val parameterMatch = subRes.getMatch
          val searchPattern = findMatchResult(subRes, PATTERN_CONTEXT).getOrElse(throw new Exception("Expected pattern context")).getMatch

          val annotationsCopy = createAnnotationCopy(searchPattern, replacePattern, replacePattern.getModifierList, parameterMatch)
          val modifierCopy = createModifierCopy(searchPattern, replacePattern, parameterMatch)
          val typeCopy = createRetTypeEquivCopy(searchPattern, replacePattern, ident, parameterMatch)
          val bodyCopy = createFuncBodyEquivCopy(searchPattern, replacePattern, replacePattern.typeElement.getOrElse(ident), parameterMatch)
          val insertBefore = mergeInserts(annotationsCopy, modifierCopy)
          val insertAfter = mergeInserts(typeCopy, bodyCopy)

          buildChildren(replacePattern, Some(subRes), result, insertBefore = insertBefore, insertAfter = insertAfter)
        })
      // Build annotation
      case annotation: ScAnnotation =>
        val text = annotation.constructorInvocation.reference.map(_.getText).getOrElse("")
        if (profile.isReplacementTypedVariable(text)) {
          findMatchResult(scopeRes, profile.stripReplacementTypedVariableDecorations(text)) match {
            case None =>
            case Some(subRes) =>
              if (subRes.isMultipleMatch)
                handleMultiple(subRes, result, mR => buildChildren(element, Some(mR), result), Some(" "))
              else
                buildChildren(element, scopeRes, result)
          }
        } else {
          buildChildren(element, scopeRes, result)
        }
      // Build case guard
      case guard: ScGuard =>
        buildChildren(guard, scopeRes, result, skipBlock = mutable.Map(guard.getFirstChild -> (guard.getLastChild, guard.expr.orNull, 0)))
      // Build case clause
      case replacePattern: ScCaseClause =>
        handleScope(replacePattern, replacePattern.pattern, scopeRes, result, Some("\n"), (ident, subRes) => {
          val ccMatch = subRes.getMatch match {
            case ccM: ScCaseClause => ccM
            case _ => throw Exception("Invalid element")
          }

          val searchPattern = findMatchResult(subRes, PATTERN_CONTEXT).getOrElse(throw new Exception("Expected pattern context")).getMatch.asInstanceOf[ScCaseClause]
          val insertAfter = ifNotMentioned(searchPattern.guard, replacePattern.guard, ident, ccMatch.guard.map(" " + _.getText))
          val skippers: Skippers = replacePattern.guard.map(guard => mutable.Map(guard.getPrevSibling -> (guard.asInstanceOf[PsiElement], guard.asInstanceOf[PsiElement], 0))).getOrElse(mutable.Map())
          buildChildren(replacePattern, Some(subRes), result, insertAfter = insertAfter, skipBlock = skippers)
        })
      // Default case for leaf elements
      case _ if element.getFirstChild == null =>
        val text = element.getText
        if (profile.isReplacementTypedVariable(text)) {
          findMatchResult(scopeRes, profile.stripReplacementTypedVariableDecorations(text)) match {
            case None =>
            case Some(res) =>
              if (res.isMultipleMatch)
                handleMultiple(res, result, subRes => insertImage(subRes, result))
              else
                insertImage(res, result)
          }
        } else {
          result.append(text)
        }
      // Default case non leaf elements
      case _ => buildChildren(element, scopeRes, result)
    }
  }