Function literal expression outside the parentheses wrapped into JetFunctionLiteralArgument

Extracted JetFunctionLiteralArgument.moveInsideParenthesesAndReplaceWith util function
This commit is contained in:
Svetlana Isakova
2014-07-12 20:03:38 +04:00
parent 4477a96ca7
commit 2ae87cae4a
59 changed files with 1040 additions and 912 deletions
@@ -45,7 +45,7 @@ public class KotlinFunctionLiteralSurrounder extends KotlinStatementsSurrounder
callExpression = (JetCallExpression) container.addAfter(callExpression, statements[statements.length - 1]);
container.addBefore(psiFactory.createWhiteSpace(), callExpression);
JetFunctionLiteralExpression bodyExpression = (JetFunctionLiteralExpression) callExpression.getFunctionLiteralArguments().get(0);
JetFunctionLiteralExpression bodyExpression = callExpression.getFunctionLiteralArguments().get(0).getFunctionLiteral();
assert bodyExpression != null : "Body expression should exists for " + callExpression.getText();
JetBlockExpression blockExpression = bodyExpression.getBodyExpression();
assert blockExpression != null : "JetBlockExpression should exists for " + callExpression.getText();
@@ -229,10 +229,10 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
(JetCallExpression) JetPsiUtil.getOutermostDescendantElement(element, down, IS_CALL_EXPRESSION);
if (callExpression == null) return null;
List<JetExpression> functionLiterals = callExpression.getFunctionLiteralArguments();
List<JetFunctionLiteralArgument> functionLiterals = callExpression.getFunctionLiteralArguments();
if (functionLiterals.isEmpty()) return null;
return ((JetFunctionLiteralExpression) functionLiterals.get(0)).getBodyExpression();
return functionLiterals.get(0).getFunctionLiteral().getBodyExpression();
}
@Nullable
@@ -57,6 +57,7 @@ import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace
import org.jetbrains.jet.lang.psi.JetPrefixExpression
import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall
import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument
enum class Tail {
COMMA
@@ -82,18 +83,18 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo
private fun calculateForArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val argument = expressionWithType.getParent() as? JetValueArgument ?: return null
if (argument.isNamed()) return null //TODO - support named arguments (also do not forget to check for presence of named arguments before)
val argumentList = argument.getParent() as JetValueArgumentList
val argumentList = argument.getParent() as? JetValueArgumentList ?: return null
val argumentIndex = argumentList.getArguments().indexOf(argument)
val callElement = argumentList.getParent() as? JetCallElement ?: return null
return calculateForArgument(callElement, argumentIndex, false)
}
private fun calculateForFunctionLiteralArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val callExpression = expressionWithType.getParent() as? JetCallExpression
val functionLiteralArgument = expressionWithType.getParent() as? JetFunctionLiteralArgument
val callExpression = functionLiteralArgument?.getParent() as? JetCallExpression
if (callExpression != null) {
val arguments = callExpression.getFunctionLiteralArguments()
if (arguments.firstOrNull() == expressionWithType) {
return calculateForArgument(callExpression, callExpression.getValueArguments().size, true)
if (callExpression.getFunctionLiteralArguments().head?.getArgumentExpression() == expressionWithType) {
return calculateForArgument(callExpression, callExpression.getValueArguments().size - 1, true)
}
}
return null
@@ -125,12 +125,12 @@ fun createSpacingBuilder(settings: CodeStyleSettings): KotlinSpacingBuilder {
beforeInside(COLON, EXTEND_COLON_ELEMENTS) { spaceIf(jetSettings.SPACE_BEFORE_EXTEND_COLON) }
afterInside(COLON, EXTEND_COLON_ELEMENTS) { spaceIf(jetSettings.SPACE_AFTER_EXTEND_COLON) }
between(VALUE_ARGUMENT_LIST, FUNCTION_LITERAL_EXPRESSION).spaces(1)
between(VALUE_ARGUMENT_LIST, FUNCTION_LITERAL_ARGUMENT).spaces(1)
beforeInside(ARROW, FUNCTION_LITERAL).spaceIf(jetSettings.SPACE_BEFORE_LAMBDA_ARROW)
aroundInside(ARROW, FUNCTION_TYPE).spaceIf(jetSettings.SPACE_AROUND_FUNCTION_TYPE_ARROW)
betweenInside(REFERENCE_EXPRESSION, FUNCTION_LITERAL_EXPRESSION, CALL_EXPRESSION).spaces(1)
betweenInside(REFERENCE_EXPRESSION, FUNCTION_LITERAL_ARGUMENT, CALL_EXPRESSION).spaces(1)
}
custom {
@@ -41,9 +41,9 @@ public class ConvertAssertToIfWithThrowIntention : JetSelfTargetingIntention<Jet
override fun isApplicableTo(element: JetCallExpression): Boolean {
if (element.getCalleeExpression()?.getText() != "assert") return false
val arguments = element.getValueArguments().size
val lambdas = element.getFunctionLiteralArguments().size
if (!(arguments == 1 && (lambdas == 1 || lambdas == 0)) && arguments != 2) return false
val argumentSize = element.getValueArguments().size
if (argumentSize !in 1..2) return false
if (element.getFunctionLiteralArguments().size == 1 && argumentSize == 1) return false
val context = AnalyzerFacadeWithCache.getContextForElement(element)
val resolvedCall = element.getResolvedCall(context)
@@ -49,10 +49,7 @@ public class ConvertToForEachLoopIntention : JetSelfTargetingIntention<JetExpres
else -> null
}
return when (argument) {
is JetFunctionLiteralExpression -> argument
else -> null
}
return argument as? JetFunctionLiteralExpression
}
override fun isApplicableTo(element: JetExpression): Boolean {
@@ -66,7 +63,7 @@ public class ConvertToForEachLoopIntention : JetSelfTargetingIntention<JetExpres
val selector = element.getSelectorExpression()
when (selector) {
is JetCallExpression -> (selector.getValueArguments().size() + selector.getFunctionLiteralArguments().size()) == 1
is JetCallExpression -> selector.getValueArguments().size() == 1
else -> false
}
}
@@ -17,38 +17,17 @@
package org.jetbrains.jet.plugin.intentions
import com.intellij.openapi.editor.Editor
import org.jetbrains.jet.lang.psi.JetCallExpression
import org.jetbrains.jet.lang.psi.JetPsiFactory
import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument
import org.jetbrains.jet.plugin.util.psiModificationUtil.moveInsideParentheses
import org.jetbrains.jet.plugin.caches.resolve.getBindingContext
import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall
public class MoveLambdaInsideParenthesesIntention : JetSelfTargetingIntention<JetCallExpression>(
public class MoveLambdaInsideParenthesesIntention : JetSelfTargetingIntention<JetFunctionLiteralArgument>(
"move.lambda.inside.parentheses", javaClass()) {
override fun isApplicableTo(element: JetCallExpression): Boolean = !element.getFunctionLiteralArguments().isEmpty()
override fun isApplicableTo(element: JetFunctionLiteralArgument): Boolean = true
override fun applyTo(element: JetCallExpression, editor: Editor) {
val typeArgs = element.getTypeArgumentList()?.getText()
val exprText = element.getCalleeExpression()?.getText()
if (exprText == null) return
val funName = if (!element.getTypeArguments().isEmpty() && typeArgs != null) "$exprText$typeArgs" else "$exprText"
val sb = StringBuilder()
sb.append("(")
for (value in element.getValueArguments()) {
if (value == null) continue
if (value.getArgumentName() != null) {
sb.append("${value.getArgumentName()?.getText()} = ${value.getArgumentExpression()?.getText()},")
} else {
sb.append("${value.getArgumentExpression()?.getText()},")
}
}
if (element.getValueArguments().any { it?.getArgumentName() != null}) {
val context = element.getBindingContext()
val resolvedCall = element.getResolvedCall(context)
val literalName = resolvedCall?.getResultingDescriptor()?.getValueParameters()?.last?.getName().toString()
sb.append("$literalName = ")
}
val newExpression = "$funName${sb.toString()}${element.getFunctionLiteralArguments()[0].getText()})"
element.replace(JetPsiFactory(element).createExpression(newExpression))
override fun applyTo(element: JetFunctionLiteralArgument, editor: Editor) {
element.moveInsideParentheses(element.getBindingContext())
}
}
}
@@ -22,6 +22,8 @@ import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression
import org.jetbrains.jet.lang.psi.JetPsiFactory
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.lang.psi.JetLabeledExpression
import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument
import org.jetbrains.jet.lang.resolve.calls.callUtil.getValueArgumentsInParentheses
public class MoveLambdaOutsideParenthesesIntention : JetSelfTargetingIntention<JetCallExpression>(
"move.lambda.outside.parentheses", javaClass()) {
@@ -31,17 +33,17 @@ public class MoveLambdaOutsideParenthesesIntention : JetSelfTargetingIntention<J
(expression is JetLabeledExpression && isLambdaOrLabeledLambda(expression.getBaseExpression()))
override fun isApplicableTo(element: JetCallExpression): Boolean {
val args = element.getValueArguments()
val args = element.getValueArgumentsInParentheses()
return args.size > 0 && isLambdaOrLabeledLambda(args.last?.getArgumentExpression())
}
override fun applyTo(element: JetCallExpression, editor: Editor) {
val args = element.getValueArguments()
val args = element.getValueArgumentsInParentheses()
val functionLiteral = args.last!!.getArgumentExpression()?.getText()
val calleeText = element.getCalleeExpression()?.getText()
if (calleeText == null || functionLiteral == null) return
val params = args.subList(0, args.size - 1).map { it?.asElement()?.getText() ?: "" }.makeString(", ", "(", ")")
val params = args.subList(0, args.size - 1).map { it.asElement().getText() ?: "" }.joinToString(", ", "(", ")")
val newCall =
if (params == "()") {
@@ -44,7 +44,7 @@ public class CallDescription internal (
get() = callElement.getCalleeExpression()?.getText()
public val argumentCount: Int
get() = callElement.getValueArguments().size + callElement.getFunctionLiteralArguments().size
get() = callElement.getValueArguments().size
public val hasTypeArguments: Boolean
get() = callElement.getTypeArgumentList() != null
@@ -23,20 +23,17 @@ import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.JetCallExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.plugin.JetBundle;
import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
public class AddSemicolonAfterFunctionCallFix extends JetIntentionAction<JetCallExpression> {
JetFunctionLiteralExpression literal;
private final JetFunctionLiteralArgument functionLiteralArgument;
public AddSemicolonAfterFunctionCallFix(@NotNull JetCallExpression element, @NotNull JetFunctionLiteralExpression literal) {
public AddSemicolonAfterFunctionCallFix(@NotNull JetCallExpression element, @NotNull JetFunctionLiteralArgument functionLiteralArgument) {
super(element);
this.literal = literal;
this.functionLiteralArgument = functionLiteralArgument;
}
@NotNull
@@ -59,8 +56,8 @@ public class AddSemicolonAfterFunctionCallFix extends JetIntentionAction<JetCall
assert argumentList != null;
PsiElement afterArgumentList = argumentList.getNextSibling();
int caretOffset = editor.getCaretModel().getOffset();
element.getParent().addRangeAfter(afterArgumentList, literal, element);
element.deleteChildRange(afterArgumentList, literal);
element.getParent().addRangeAfter(afterArgumentList, functionLiteralArgument, element);
element.deleteChildRange(afterArgumentList, functionLiteralArgument);
element.getParent().addAfter(JetPsiFactory(file).createSemicolon(), element);
editor.getCaretModel().moveToOffset(caretOffset + 1);
}
@@ -71,9 +68,10 @@ public class AddSemicolonAfterFunctionCallFix extends JetIntentionAction<JetCall
@Override
public JetIntentionAction createAction(Diagnostic diagnostic) {
JetCallExpression callExpression = QuickFixUtil.getParentElementOfType(diagnostic, JetCallExpression.class);
JetFunctionLiteralExpression literalExpression = QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralExpression.class);
if (callExpression == null || literalExpression == null) return null;
return new AddSemicolonAfterFunctionCallFix(callExpression, literalExpression);
JetFunctionLiteralArgument functionLiteralArgument =
QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralArgument.class);
if (callExpression == null || functionLiteralArgument == null) return null;
return new AddSemicolonAfterFunctionCallFix(callExpression, functionLiteralArgument);
}
};
}
@@ -105,8 +105,9 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF
// Change type of a function parameter in case TYPE_MISMATCH is reported on expression passed as value argument of call.
// 1) When an argument is a dangling function literal:
JetFunctionLiteralExpression functionLiteralExpression =
QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralExpression.class);
JetFunctionLiteralArgument functionLiteralArgument =
QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralArgument.class);
JetFunctionLiteralExpression functionLiteralExpression = functionLiteralArgument != null ? functionLiteralArgument.getFunctionLiteral() : null;
if (functionLiteralExpression != null && functionLiteralExpression.getBodyExpression() == expression) {
JetParameter correspondingParameter =
QuickFixUtil.getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(functionLiteralExpression);
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.sun.codemodel.internal.JVar;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
@@ -130,12 +131,15 @@ public class QuickFixUtil {
return null;
}
//todo remove, use value argument to parameter map
@Nullable
public static JetParameter getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(@NotNull JetFunctionLiteralExpression functionLiteralExpression) {
if (!(functionLiteralExpression.getParent() instanceof JetCallExpression)) {
JetFunctionLiteralArgument functionLiteralArgument = PsiTreeUtil.getParentOfType(functionLiteralExpression, JetFunctionLiteralArgument.class);
if (functionLiteralArgument == null || functionLiteralArgument.getFunctionLiteral() != functionLiteralExpression) return null;
if (!(functionLiteralArgument.getParent() instanceof JetCallExpression)) {
return null;
}
JetCallExpression callExpression = (JetCallExpression) functionLiteralExpression.getParent();
JetCallExpression callExpression = (JetCallExpression) functionLiteralArgument.getParent();
JetParameterList parameterList = getParameterListOfCallee(callExpression);
if (parameterList == null) return null;
return parameterList.getParameters().get(parameterList.getParameters().size() - 1);
@@ -68,6 +68,8 @@ import org.jetbrains.jet.lang.resolve.bindingContextUtil.isUsedAsStatement
import org.jetbrains.jet.lang.psi.psiUtil.isAncestor
import org.jetbrains.jet.plugin.intentions.declarations.DeclarationUtils
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
import org.jetbrains.jet.lang.psi.psiUtil.isFunctionLiteralOutsideParentheses
import org.jetbrains.jet.plugin.util.psiModificationUtil.moveInsideParenthesesAndReplaceWith
private val DEFAULT_FUNCTION_NAME = "myFun"
private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType()
@@ -915,23 +917,13 @@ fun ExtractionDescriptor.generateFunction(
}
val firstExpression = extractionData.getExpressions().firstOrNull()
val enclosingCall = firstExpression?.getParent() as? JetCallExpression
if (enclosingCall == null || firstExpression !in enclosingCall.getFunctionLiteralArguments()) {
anchor.replace(wrappedCall)
if (firstExpression?.isFunctionLiteralOutsideParentheses() ?: false) {
val functionLiteralArgument = PsiTreeUtil.getParentOfType(firstExpression, javaClass<JetFunctionLiteralArgument>())!!
//todo use the right binding context
functionLiteralArgument.moveInsideParenthesesAndReplaceWith(wrappedCall, BindingContext.EMPTY)
return
}
val argumentListExt = psiFactory.createCallArguments("(${wrappedCall.getText()})")
val argumentList = enclosingCall.getValueArgumentList()
if (argumentList == null) {
(anchor.getPrevSibling() as? PsiWhiteSpace)?.let { it.delete() }
anchor.replace(argumentListExt)
return
}
val newArgText = (argumentList.getArguments() + argumentListExt.getArguments()).map { it.getText() }.joinToString(", ", "(", ")")
argumentList.replace(psiFactory.createCallArguments(newArgText))
anchor.delete()
anchor.replace(wrappedCall)
}
fun makeCall(function: JetNamedFunction): JetNamedFunction {
@@ -31,10 +31,12 @@ import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzerPackage;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.ObservableBindingTrace;
@@ -57,6 +59,7 @@ import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl;
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle;
import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil;
import org.jetbrains.jet.plugin.refactoring.introduce.KotlinIntroduceHandlerBase;
import org.jetbrains.jet.plugin.util.psiModificationUtil.PsiModificationUtilPackage;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.*;
@@ -98,7 +101,6 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
}
final JetExpression expression = _expression;
boolean noTypeInference = false;
boolean needParentheses = false;
if (expression.getParent() instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression)expression.getParent();
if (qualifiedExpression.getReceiverExpression() != expression) {
@@ -109,13 +111,6 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
else if (expression instanceof JetStatementExpression) {
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression"));
return;
} else if (expression.getParent() instanceof JetCallElement) {
if (expression instanceof JetFunctionLiteralExpression) {
needParentheses = true;
} else {
showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.no.expression"));
return;
}
}
else if (expression.getParent() instanceof JetOperationExpression) {
JetOperationExpression operationExpression = (JetOperationExpression)expression.getParent();
@@ -126,7 +121,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
}
ResolveSessionForBodies resolveSession =
ResolvePackage.getLazyResolveSession(expression);
BindingContext bindingContext = resolveSession.resolveToElement(expression);
final BindingContext bindingContext = resolveSession.resolveToElement(expression);
final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); //can be null or error type
JetScope scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expression);
if (scope != null) {
@@ -176,7 +171,6 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
}
final boolean finalNoTypeInference = noTypeInference;
final boolean finalNeedParentheses = needParentheses;
Pass<OccurrencesChooser.ReplaceChoice> callback = new Pass<OccurrencesChooser.ReplaceChoice>() {
@Override
public void pass(OccurrencesChooser.ReplaceChoice replaceChoice) {
@@ -203,9 +197,10 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
final Ref<JetProperty> propertyRef = new Ref<JetProperty>();
final ArrayList<JetExpression> references = new ArrayList<JetExpression>();
final Ref<JetExpression> reference = new Ref<JetExpression>();
final Runnable introduceRunnable = introduceVariable(expression, suggestedNames, allReplaces, commonContainer,
commonParent, replaceOccurrence, propertyRef, references,
reference, finalNoTypeInference, finalNeedParentheses, expressionType);
final Runnable introduceRunnable = introduceVariable(
expression, suggestedNames, allReplaces, commonContainer,
commonParent, replaceOccurrence, propertyRef, references,
reference, finalNoTypeInference, expressionType, bindingContext);
final boolean finalReplaceOccurrence = replaceOccurrence;
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override
@@ -250,9 +245,10 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
final ArrayList<JetExpression> references,
final Ref<JetExpression> reference,
final boolean noTypeInference,
final boolean needParentheses,
final JetType expressionType
final JetType expressionType,
final BindingContext bindingContext
) {
final JetPsiFactory psiFactory = JetPsiFactory(expression);
return new Runnable() {
@Override
public void run() {
@@ -274,7 +270,6 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
else {
variableText += expression.getText();
}
JetPsiFactory psiFactory = JetPsiFactory(expression);
JetProperty property = psiFactory.createProperty(variableText);
PsiElement anchor = calculateAnchor(commonParent, commonContainer, allReplaces);
if (anchor == null) return;
@@ -291,15 +286,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
emptyBody.addAfter(psiFactory.createNewLine(), firstChild);
if (replaceOccurrence && commonContainer != null) {
for (JetExpression replace : allReplaces) {
boolean isActualExpression = expression == replace;
if (!needParentheses && !(replace.getParent() instanceof JetCallExpression)) {
JetExpression element = (JetExpression) replace.replace(psiFactory.createExpression(suggestedNames[0]));
if (isActualExpression) reference.set(element);
} else {
JetValueArgumentList argumentList = psiFactory.createCallArguments("(" + suggestedNames[0] + ")");
JetValueArgumentList element = (JetValueArgumentList) replace.replace(argumentList);
if (isActualExpression) reference.set(element.getArguments().get(0).getArgumentExpression());
}
replaceExpression(replace);
}
PsiElement oldElement = commonContainer;
if (commonContainer instanceof JetWhenEntry) {
@@ -390,22 +377,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
}
for (JetExpression replace : allReplaces) {
if (replaceOccurrence && !needBraces) {
boolean isActualExpression = expression == replace;
if (!needParentheses && !(replace.getParent() instanceof JetCallExpression)) {
JetExpression element =
(JetExpression)replace.replace(psiFactory.createExpression(suggestedNames[0]));
references.add(element);
if (isActualExpression) reference.set(element);
} else {
JetValueArgumentList argumentList = psiFactory.createCallArguments("(" + suggestedNames[0] + ")");
JetValueArgumentList element = (JetValueArgumentList) replace.replace(argumentList);
JetExpression argumentExpression = element.getArguments().get(0).getArgumentExpression();
references.add(argumentExpression);
if (isActualExpression) {
reference.set(argumentExpression);
}
}
replaceExpression(replace);
}
else if (!needBraces) {
replace.delete();
@@ -416,6 +388,25 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
ShortenReferences.INSTANCE$.process(property);
}
}
private void replaceExpression(JetExpression replace) {
boolean isActualExpression = expression == replace;
JetExpression replacement = psiFactory.createExpression(suggestedNames[0]);
JetExpression result;
if (PsiUtilPackage.isFunctionLiteralOutsideParentheses(replace)) {
JetFunctionLiteralArgument functionLiteralArgument =
PsiTreeUtil.getParentOfType(replace, JetFunctionLiteralArgument.class);
JetCallExpression newCallExpression = PsiModificationUtilPackage
.moveInsideParenthesesAndReplaceWith(functionLiteralArgument, replacement, bindingContext);
result = KotlinPackage.last(newCallExpression.getValueArguments()).getArgumentExpression();
}
else {
result = (JetExpression)replace.replace(replacement);
}
references.add(result);
if (isActualExpression) reference.set(result);
}
};
}
@@ -81,19 +81,13 @@ class JetInvokeFunctionReference extends JetSimpleReference<JetCallExpression> i
}
}
List<JetExpression> functionLiteralArguments = getExpression().getFunctionLiteralArguments();
for (JetExpression functionLiteralArgument : functionLiteralArguments) {
while (functionLiteralArgument instanceof JetLabeledExpression) {
functionLiteralArgument = ((JetLabeledExpression) functionLiteralArgument).getBaseExpression();
}
if (functionLiteralArgument instanceof JetFunctionLiteralExpression) {
JetFunctionLiteralExpression functionLiteralExpression = (JetFunctionLiteralExpression) functionLiteralArgument;
list.add(getRange(functionLiteralExpression.getLeftCurlyBrace()));
ASTNode rightCurlyBrace = functionLiteralExpression.getRightCurlyBrace();
if (rightCurlyBrace != null) {
list.add(getRange(rightCurlyBrace));
}
List<JetFunctionLiteralArgument> functionLiteralArguments = getExpression().getFunctionLiteralArguments();
for (JetFunctionLiteralArgument functionLiteralArgument : functionLiteralArguments) {
JetFunctionLiteralExpression functionLiteralExpression = functionLiteralArgument.getFunctionLiteral();
list.add(getRange(functionLiteralExpression.getLeftCurlyBrace()));
ASTNode rightCurlyBrace = functionLiteralExpression.getRightCurlyBrace();
if (rightCurlyBrace != null) {
list.add(getRange(rightCurlyBrace));
}
}
@@ -121,8 +121,7 @@ public class JetPsiMatcher {
if (!checkElementMatch(call1.getCalleeExpression(), call2.getCalleeExpression())) return false;
return checkListMatch(call1.getValueArguments(), call2.getValueArguments(), VALUE_ARGUMENT_CHECKER) &&
checkListMatch(call1.getFunctionLiteralArguments(), call2.getFunctionLiteralArguments());
return checkListMatch(call1.getValueArguments(), call2.getValueArguments(), VALUE_ARGUMENT_CHECKER);
}
@Override
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.util.psiModificationUtil
import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument
import org.jetbrains.jet.lang.psi.JetCallExpression
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.resolve.calls.callUtil.getValueArgumentsInParentheses
import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMatch
import org.jetbrains.jet.lang.psi.JetPsiFactory
import com.intellij.psi.PsiWhiteSpace
fun JetFunctionLiteralArgument.moveInsideParentheses(bindingContext: BindingContext): JetCallExpression {
return moveInsideParenthesesAndReplaceWith(this.getArgumentExpression(), bindingContext)
}
fun JetFunctionLiteralArgument.moveInsideParenthesesAndReplaceWith(
replacement: JetExpression,
bindingContext: BindingContext
): JetCallExpression {
val oldCallExpression = getParent() as JetCallExpression
val newCallExpression = oldCallExpression.copy() as JetCallExpression
val psiFactory = JetPsiFactory(getProject())
val argument = if (newCallExpression.getValueArgumentsInParentheses().any { it.getArgumentName() != null }) {
val resolvedCall = oldCallExpression.getResolvedCall(bindingContext)
val name = (resolvedCall?.getArgumentMapping(this) as? ArgumentMatch)?.valueParameter?.getName()?.toString()
psiFactory.createArgumentWithName(name, replacement)
}
else {
psiFactory.createArgument(replacement)
}
val functionLiteralArgument = newCallExpression.getFunctionLiteralArguments().head!!
val valueArgumentList = newCallExpression.getValueArgumentList() ?: psiFactory.createCallArguments("()")
val closingParenthesis = valueArgumentList.getLastChild()
if (valueArgumentList.getArguments().isNotEmpty()) {
valueArgumentList.addBefore(psiFactory.createComma(), closingParenthesis)
valueArgumentList.addBefore(psiFactory.createWhiteSpace(), closingParenthesis)
}
valueArgumentList.addBefore(argument, closingParenthesis)
(functionLiteralArgument.getPrevSibling() as? PsiWhiteSpace)?.delete()
if (newCallExpression.getValueArgumentList() != null) {
functionLiteralArgument.delete()
}
else {
functionLiteralArgument.replace(valueArgumentList)
}
return oldCallExpression.replace(newCallExpression) as JetCallExpression
}