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)
}
}