JetPsiFactory: refactored method for creating argument + introduced ability to create arbitrary constructs by pattern
This commit is contained in:
@@ -23,13 +23,14 @@ import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFileFactory
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.LocalTimeCounter
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.idea.JetFileType
|
||||
import org.jetbrains.kotlin.lexer.JetKeywordToken
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.renderName
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory.CallableBuilder.Target
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import java.io.PrintWriter
|
||||
@@ -187,12 +188,12 @@ public class JetPsiFactory(private val project: Project) {
|
||||
return createDeclaration(text)
|
||||
}
|
||||
|
||||
public fun <T> createDeclaration(text: String): T {
|
||||
public fun <TDeclaration : JetDeclaration> createDeclaration(text: String): TDeclaration {
|
||||
val file = createFile(text)
|
||||
val dcls = file.getDeclarations()
|
||||
assert(dcls.size() == 1) { "${dcls.size()} declarations in $text" }
|
||||
[suppress("UNCHECKED_CAST")]
|
||||
val result = dcls.first() as T
|
||||
val declarations = file.getDeclarations()
|
||||
assert(declarations.size() == 1) { "${declarations.size()} declarations in $text" }
|
||||
@suppress("UNCHECKED_CAST")
|
||||
val result = declarations.first() as TDeclaration
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -361,13 +362,24 @@ public class JetPsiFactory(private val project: Project) {
|
||||
createExpressionByPattern("if ($0) $1", condition, thenExpr)) as JetIfExpression
|
||||
}
|
||||
|
||||
public fun createArgumentWithName(name: String?, argumentExpression: JetExpression): JetValueArgument {
|
||||
val argumentText = (if (name != null) "$name = " else "") + argumentExpression.getText()
|
||||
return createCallArguments("($argumentText)").getArguments().first()
|
||||
}
|
||||
public fun createArgument(expression: JetExpression, name: String? = null, isSpread: Boolean = false): JetValueArgument {
|
||||
val argumentList = buildByPattern({ pattern, args -> createByPattern(pattern, *args) { createCallArguments(it) } }) {
|
||||
appendFixedText("(")
|
||||
|
||||
public fun createArgument(argumentExpression: JetExpression): JetValueArgument {
|
||||
return createArgumentWithName(null, argumentExpression)
|
||||
if (name != null) {
|
||||
appendFixedText(Name.identifier(name).renderName())
|
||||
appendFixedText("=")
|
||||
}
|
||||
|
||||
if (isSpread) {
|
||||
appendFixedText("*")
|
||||
}
|
||||
|
||||
appendExpression(expression)
|
||||
|
||||
appendFixedText(")")
|
||||
}
|
||||
return argumentList.getArguments().single()
|
||||
}
|
||||
|
||||
public fun createDelegatorToSuperCall(text: String): JetDelegatorToSuperCall {
|
||||
|
||||
@@ -30,13 +30,19 @@ import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
import java.util.LinkedHashMap
|
||||
|
||||
public fun JetPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any): JetExpression {
|
||||
public fun JetPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any): JetExpression
|
||||
= createByPattern(pattern, *args) { createExpression(it) }
|
||||
|
||||
public fun <TDeclaration : JetDeclaration> JetPsiFactory.createDeclarationByPattern(pattern: String, vararg args: Any): TDeclaration
|
||||
= createByPattern(pattern, *args) { createDeclaration<TDeclaration>(it) }
|
||||
|
||||
public fun <TElement : JetElement> createByPattern(pattern: String, vararg args: Any, factory: (String) -> TElement): TElement {
|
||||
val (processedText, allPlaceholders) = processPattern(pattern, args)
|
||||
|
||||
var expression = createExpression(processedText.trim())
|
||||
val project = expression.getProject()
|
||||
var resultElement = factory(processedText.trim())
|
||||
val project = resultElement.getProject()
|
||||
|
||||
val start = expression.startOffset
|
||||
val start = resultElement.startOffset
|
||||
|
||||
val pointerManager = SmartPointerManager.getInstance(project)
|
||||
|
||||
@@ -52,7 +58,7 @@ public fun JetPsiFactory.createExpressionByPattern(pattern: String, vararg args:
|
||||
}
|
||||
|
||||
for ((range, text) in placeholders) {
|
||||
val token = expression.findElementAt(range.getStartOffset())!!
|
||||
val token = resultElement.findElementAt(range.getStartOffset())!!
|
||||
for (element in token.parents()) {
|
||||
val elementRange = element.getTextRange().shiftRight(-start)
|
||||
if (elementRange == range && expectedElementType.isInstance(element)) {
|
||||
@@ -79,20 +85,20 @@ public fun JetPsiFactory.createExpressionByPattern(pattern: String, vararg args:
|
||||
|
||||
// reformat whole text except for String arguments (as they can contain user's formatting to be preserved)
|
||||
if (stringPlaceholderRanges.none()) {
|
||||
expression = codeStyleManager.reformat(expression, true) as JetExpression
|
||||
resultElement = codeStyleManager.reformat(resultElement, true) as TElement
|
||||
}
|
||||
else {
|
||||
var bound = expression.endOffset - 1
|
||||
var bound = resultElement.endOffset - 1
|
||||
for (range in stringPlaceholderRanges) {
|
||||
// we extend reformatting range by 1 to the right because otherwise some of spaces are not reformatted
|
||||
expression = codeStyleManager.reformatRange(expression, range.getEndOffset() + start, bound + 1, true) as JetExpression
|
||||
resultElement = codeStyleManager.reformatRange(resultElement, range.getEndOffset() + start, bound + 1, true) as TElement
|
||||
bound = range.getStartOffset() + start
|
||||
}
|
||||
expression = codeStyleManager.reformatRange(expression, start, bound + 1, true) as JetExpression
|
||||
resultElement = codeStyleManager.reformatRange(resultElement, start, bound + 1, true) as TElement
|
||||
}
|
||||
|
||||
// do not reformat the whole expression in PostprocessReformattingAspect
|
||||
CodeEditUtil.setNodeGeneratedRecursively(expression.getNode(), false)
|
||||
CodeEditUtil.setNodeGeneratedRecursively(resultElement.getNode(), false)
|
||||
|
||||
for ((pointer, n) in pointers) {
|
||||
var element = pointer.getElement()!!
|
||||
@@ -102,9 +108,9 @@ public fun JetPsiFactory.createExpressionByPattern(pattern: String, vararg args:
|
||||
element.replace(args[n] as PsiElement)
|
||||
}
|
||||
|
||||
codeStyleManager.adjustLineIndent(expression.getContainingFile(), expression.getTextRange())
|
||||
codeStyleManager.adjustLineIndent(resultElement.getContainingFile(), resultElement.getTextRange())
|
||||
|
||||
return expression
|
||||
return resultElement
|
||||
}
|
||||
|
||||
private data class Placeholder(val range: TextRange, val text: String)
|
||||
@@ -182,22 +188,22 @@ private fun processPattern(pattern: String, args: Array<out Any>): PatternData {
|
||||
return PatternData(text, ranges)
|
||||
}
|
||||
|
||||
public class ExpressionBuilder {
|
||||
public class BuilderByPattern<TElement> {
|
||||
private val patternBuilder = StringBuilder()
|
||||
private val arguments = ArrayList<Any>()
|
||||
|
||||
public fun appendFixedText(text: String): ExpressionBuilder {
|
||||
public fun appendFixedText(text: String): BuilderByPattern<TElement> {
|
||||
patternBuilder.append(text)
|
||||
return this
|
||||
}
|
||||
|
||||
public fun appendNonFormattedText(text: String): ExpressionBuilder {
|
||||
public fun appendNonFormattedText(text: String): BuilderByPattern<TElement> {
|
||||
patternBuilder.append("$" + arguments.size())
|
||||
arguments.add(text)
|
||||
return this
|
||||
}
|
||||
|
||||
public fun appendExpression(expression: JetExpression?): ExpressionBuilder {
|
||||
public fun appendExpression(expression: JetExpression?): BuilderByPattern<TElement> {
|
||||
if (expression != null) {
|
||||
patternBuilder.append("$" + arguments.size())
|
||||
arguments.add(expression)
|
||||
@@ -205,7 +211,7 @@ public class ExpressionBuilder {
|
||||
return this
|
||||
}
|
||||
|
||||
public fun appendTypeReference(typeRef: JetTypeReference?): ExpressionBuilder {
|
||||
public fun appendTypeReference(typeRef: JetTypeReference?): BuilderByPattern<TElement> {
|
||||
if (typeRef != null) {
|
||||
patternBuilder.append("$" + arguments.size())
|
||||
arguments.add(typeRef)
|
||||
@@ -213,13 +219,17 @@ public class ExpressionBuilder {
|
||||
return this
|
||||
}
|
||||
|
||||
public fun createExpression(factory: JetPsiFactory): JetExpression {
|
||||
return factory.createExpressionByPattern(patternBuilder.toString(), *arguments.toArray())
|
||||
public fun create(factory: (String, Array<out Any>) -> TElement): TElement {
|
||||
return factory(patternBuilder.toString(), arguments.toArray())
|
||||
}
|
||||
}
|
||||
|
||||
public fun JetPsiFactory.buildExpression(build: ExpressionBuilder.() -> Unit): JetExpression {
|
||||
val builder = ExpressionBuilder()
|
||||
builder.build()
|
||||
return builder.createExpression(this)
|
||||
public fun JetPsiFactory.buildExpression(build: BuilderByPattern<JetExpression>.() -> Unit): JetExpression {
|
||||
return buildByPattern({ pattern, args -> this.createExpressionByPattern(pattern, *args) }, build)
|
||||
}
|
||||
|
||||
public fun <TElement> buildByPattern(factory: (String, Array<out Any>) -> TElement, build: BuilderByPattern<TElement>.() -> Unit): TElement {
|
||||
val builder = BuilderByPattern<TElement>()
|
||||
builder.build()
|
||||
return builder.create(factory)
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public class AddNameToArgumentFix extends JetIntentionAction<JetValueArgument> {
|
||||
private static JetValueArgument getParsedArgumentWithName(@NotNull String name, @NotNull JetValueArgument argument) {
|
||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||
assert argumentExpression != null : "Argument should be already parsed.";
|
||||
return JetPsiFactory(argument).createArgumentWithName(name, argumentExpression);
|
||||
return JetPsiFactory(argument).createArgument(argumentExpression, name, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+1
-1
@@ -369,7 +369,7 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
||||
changeArgumentName(argumentNameExpression, parameterInfo);
|
||||
//noinspection ConstantConditions
|
||||
newArgument.replace(oldArgument instanceof JetFunctionLiteralArgument
|
||||
? psiFactory.createArgument(oldArgument.getArgumentExpression())
|
||||
? psiFactory.createArgument(oldArgument.getArgumentExpression(), null, false)
|
||||
: oldArgument.asElement());
|
||||
}
|
||||
// TODO: process default arguments in the middle
|
||||
|
||||
@@ -48,7 +48,7 @@ fun JetFunctionLiteralArgument.moveInsideParenthesesAndReplaceWith(
|
||||
|
||||
val psiFactory = JetPsiFactory(getProject())
|
||||
val argument = if (newCallExpression.getValueArgumentsInParentheses().any { it.getArgumentName() != null }) {
|
||||
psiFactory.createArgumentWithName(functionLiteralArgumentName, replacement)
|
||||
psiFactory.createArgument(replacement, functionLiteralArgumentName)
|
||||
}
|
||||
else {
|
||||
psiFactory.createArgument(replacement)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// IS_APPLICABLE: true
|
||||
fun foo() {
|
||||
bar(2, { it * 3 })
|
||||
bar(2, {it * 3})
|
||||
}
|
||||
|
||||
fun bar(a: Int, b: (Int) -> Int) {
|
||||
|
||||
Reference in New Issue
Block a user