Methods for editing in JetValueArgumentList

This commit is contained in:
Valentin Kipyatkov
2015-05-16 16:58:43 +03:00
parent 1e60c24134
commit 25e323e960
12 changed files with 162 additions and 104 deletions
@@ -0,0 +1,83 @@
/*
* Copyright 2010-2015 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.kotlin.psi
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.psiUtil.siblings
private object EditCommaSeparatedListHelper {
public fun <TItem: JetElement> addItem(list: JetElement, allItems: List<TItem>, item: TItem): TItem {
return addItemBefore(list, allItems, item, null)
}
public fun <TItem: JetElement> addItemAfter(list: JetElement, allItems: List<TItem>, item: TItem, anchor: TItem?): TItem {
assert(anchor == null || anchor.getParent() == list)
if (allItems.isEmpty()) {
if (list.getFirstChild().getNode().getElementType() == JetTokens.LPAR) {
return list.addAfter(item, list.getFirstChild()) as TItem
}
else {
return list.add(item) as TItem
}
}
else {
var comma = JetPsiFactory(list).createComma()
if (anchor != null) {
comma = list.addAfter(comma, anchor)
return list.addAfter(item, comma) as TItem
}
else {
comma = list.addBefore(comma, allItems.first())
return list.addBefore(item, comma) as TItem
}
}
}
public fun <TItem: JetElement> addItemBefore(list: JetElement, allItems: List<TItem>, item: TItem, anchor: TItem?): TItem {
val anchorAfter: TItem?
if (allItems.isEmpty()) {
assert(anchor == null)
anchorAfter = null
}
else {
if (anchor != null) {
val index = allItems.indexOf(anchor)
assert(index >= 0)
anchorAfter = if (index > 0) allItems.get(index - 1) else null
}
else {
anchorAfter = allItems.get(allItems.size() - 1)
}
}
return addItemAfter(list, allItems, item, anchorAfter)
}
public fun <TItem: JetElement> removeItem(item: TItem) {
var comma = item.siblings(withItself = false).firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
if (comma?.getNode()?.getElementType() != JetTokens.COMMA) {
comma = item.siblings(forward = false, withItself = false).firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
if (comma?.getNode()?.getElementType() != JetTokens.COMMA) {
comma = null
}
}
item.delete()
comma?.delete()
}
}
@@ -47,53 +47,21 @@ public class JetParameterList extends JetElementImplStub<KotlinPlaceHolderStub<J
@NotNull @NotNull
public JetParameter addParameter(@NotNull JetParameter parameter) { public JetParameter addParameter(@NotNull JetParameter parameter) {
return addParameterBefore(parameter, null); return EditCommaSeparatedListHelper.INSTANCE$.addItem(this, getParameters(), parameter);
} }
@NotNull @NotNull
public JetParameter addParameterAfter(@NotNull JetParameter parameter, @Nullable JetParameter anchor) { public JetParameter addParameterAfter(@NotNull JetParameter parameter, @Nullable JetParameter anchor) {
assert anchor == null || anchor.getParent() == this; return EditCommaSeparatedListHelper.INSTANCE$.addItemAfter(this, getParameters(), parameter, anchor);
List<JetParameter> parameters = getParameters();
if (parameters.isEmpty()) {
if (getFirstChild().getNode().getElementType() == JetTokens.LPAR) {
return (JetParameter) addAfter(parameter, getFirstChild());
}
else {
return (JetParameter) add(parameter);
}
}
else {
PsiElement comma = new JetPsiFactory(getProject()).createComma();
if (anchor != null) {
comma = addAfter(comma, anchor);
return (JetParameter) addAfter(parameter, comma);
}
else {
comma = addBefore(comma, parameters.get(0));
return (JetParameter) addBefore(parameter, comma);
}
}
} }
@NotNull @NotNull
public JetParameter addParameterBefore(@NotNull JetParameter parameter, @Nullable JetParameter anchor) { public JetParameter addParameterBefore(@NotNull JetParameter parameter, @Nullable JetParameter anchor) {
List<JetParameter> parameters = getParameters(); return EditCommaSeparatedListHelper.INSTANCE$.addItemBefore(this, getParameters(), parameter, anchor);
JetParameter anchorAfter; }
if (parameters.isEmpty()) {
assert anchor == null; public void removeParameter(@NotNull JetParameter parameter) {
anchorAfter = null; EditCommaSeparatedListHelper.INSTANCE$.removeItem(parameter);
}
else {
if (anchor != null) {
int index = parameters.indexOf(anchor);
assert index >= 0;
anchorAfter = index > 0 ? parameters.get(index - 1) : null;
}
else {
anchorAfter = parameters.get(parameters.size() - 1);
}
}
return addParameterAfter(parameter, anchorAfter);
} }
// this method needed only for migrate lambda syntax // this method needed only for migrate lambda syntax
@@ -24,8 +24,6 @@ import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.impl.CheckUtil;
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.codeInsight.CommentUtilCore; import com.intellij.util.codeInsight.CommentUtilCore;
@@ -36,7 +34,6 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.JetNodeTypes; import org.jetbrains.kotlin.JetNodeTypes;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.kdoc.psi.api.KDocElement; import org.jetbrains.kotlin.kdoc.psi.api.KDocElement;
import org.jetbrains.kotlin.lexer.JetKeywordToken;
import org.jetbrains.kotlin.lexer.JetToken; import org.jetbrains.kotlin.lexer.JetToken;
import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
@@ -715,35 +712,6 @@ public class JetPsiUtil {
return null; return null;
} }
// Delete given element and all the elements separating it from the neighboring elements of the same class
public static void deleteElementWithDelimiters(@NotNull PsiElement element) {
PsiElement paramBefore = PsiTreeUtil.getPrevSiblingOfType(element, element.getClass());
PsiElement from;
PsiElement to;
if (paramBefore != null) {
from = paramBefore.getNextSibling();
to = element;
}
else {
PsiElement paramAfter = PsiTreeUtil.getNextSiblingOfType(element, element.getClass());
from = element;
to = paramAfter != null ? paramAfter.getPrevSibling() : element;
}
PsiElement parent = element.getParent();
parent.deleteChildRange(from, to);
}
// Delete element if it doesn't contain children of a given type
public static <T extends PsiElement> void deleteChildlessElement(PsiElement element, Class<T> childClass) {
if (PsiTreeUtil.getChildrenOfType(element, childClass) == null) {
element.delete();
}
}
public static PsiElement ascendIfPropertyAccessor(PsiElement element) { public static PsiElement ascendIfPropertyAccessor(PsiElement element) {
if (element instanceof JetPropertyAccessor) { if (element instanceof JetPropertyAccessor) {
return element.getParent(); return element.getParent();
@@ -49,4 +49,23 @@ public class JetValueArgumentList extends JetElementImpl {
public PsiElement getLeftParenthesis() { public PsiElement getLeftParenthesis() {
return findChildByType(JetTokens.LPAR); return findChildByType(JetTokens.LPAR);
} }
@NotNull
public JetValueArgument addArgument(@NotNull JetValueArgument argument) {
return EditCommaSeparatedListHelper.INSTANCE$.addItem(this, getArguments(), argument);
}
@NotNull
public JetValueArgument addArgumentAfter(@NotNull JetValueArgument argument, @Nullable JetValueArgument anchor) {
return EditCommaSeparatedListHelper.INSTANCE$.addItemAfter(this, getArguments(), argument, anchor);
}
@NotNull
public JetValueArgument addArgumentBefore(@NotNull JetValueArgument argument, @Nullable JetValueArgument anchor) {
return EditCommaSeparatedListHelper.INSTANCE$.addItemBefore(this, getArguments(), argument, anchor);
}
public void removeArgument(@NotNull JetValueArgument argument) {
EditCommaSeparatedListHelper.INSTANCE$.removeItem(argument);
}
} }
@@ -238,14 +238,44 @@ public fun PsiElement.isExtensionDeclaration(): Boolean {
public fun PsiElement.isObjectLiteral(): Boolean = this is JetObjectDeclaration && isObjectLiteral() public fun PsiElement.isObjectLiteral(): Boolean = this is JetObjectDeclaration && isObjectLiteral()
//TODO: git rid of this method
public fun PsiElement.deleteElementAndCleanParent() { public fun PsiElement.deleteElementAndCleanParent() {
val parent = getParent() val parent = getParent()
JetPsiUtil.deleteElementWithDelimiters(this) deleteElementWithDelimiters(this)
@suppress("UNCHECKED_CAST") deleteChildlessElement(parent, this.javaClass)
JetPsiUtil.deleteChildlessElement(parent, this.javaClass)
} }
// Delete element if it doesn't contain children of a given type
private fun <T : PsiElement> deleteChildlessElement(element: PsiElement, childClass: Class<T>) {
if (PsiTreeUtil.getChildrenOfType<T>(element, childClass) == null) {
element.delete()
}
}
// Delete given element and all the elements separating it from the neighboring elements of the same class
private fun deleteElementWithDelimiters(element: PsiElement) {
val paramBefore = PsiTreeUtil.getPrevSiblingOfType<PsiElement>(element, element.javaClass)
val from: PsiElement
val to: PsiElement
if (paramBefore != null) {
from = paramBefore.getNextSibling()
to = element
}
else {
val paramAfter = PsiTreeUtil.getNextSiblingOfType<PsiElement>(element, element.javaClass)
from = element
to = if (paramAfter != null) paramAfter.getPrevSibling() else element
}
val parent = element.getParent()
parent.deleteChildRange(from, to)
}
public fun PsiElement.parameterIndex(): Int { public fun PsiElement.parameterIndex(): Int {
val parent = getParent() val parent = getParent()
return when { return when {
@@ -122,10 +122,7 @@ public class KotlinSuppressIntentionAction(
args.replace(newArgList) args.replace(newArgList)
} }
else { else {
val rightParen = args.getRightParenthesis() args.addArgument(newArgList.getArguments()[0])
args.addBefore(psiFactory.createComma(), rightParen)
args.addBefore(psiFactory.createWhiteSpace(), rightParen)
args.addBefore(newArgList.getArguments()[0], rightParen)
} }
} }
@@ -375,10 +375,10 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
// TODO: process default arguments in the middle // TODO: process default arguments in the middle
else if (parameterInfo.getDefaultValueForCall() == null) { else if (parameterInfo.getDefaultValueForCall() == null) {
if (parameterInfo.getDefaultValueForParameter() != null) { if (parameterInfo.getDefaultValueForParameter() != null) {
JetPsiUtil.deleteElementWithDelimiters(newArgument); newArgumentList.removeArgument(newArgument);
} }
else { else {
newArgument.delete(); newArgument.delete(); // keep space between commas
} }
} }
else { else {
@@ -31,29 +31,20 @@ import com.intellij.openapi.editor.markup.MarkupModel
import com.intellij.openapi.editor.markup.TextAttributes import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.refactoring.rename.inplace.InplaceRefactoring
import com.intellij.ui.DottedBorder import com.intellij.ui.DottedBorder
import com.intellij.ui.JBColor import com.intellij.ui.JBColor
import com.intellij.ui.NonFocusableCheckBox import com.intellij.ui.NonFocusableCheckBox
import org.jetbrains.kotlin.idea.JetFileType import org.jetbrains.kotlin.idea.JetFileType
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinInplaceVariableIntroducer import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinInplaceVariableIntroducer
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.util.supertypes import org.jetbrains.kotlin.idea.util.supertypes
import org.jetbrains.kotlin.psi.JetExpression import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetParameter import org.jetbrains.kotlin.psi.JetParameter
import org.jetbrains.kotlin.psi.JetPsiFactory import org.jetbrains.kotlin.psi.JetParameterList
import org.jetbrains.kotlin.psi.JetPsiUtil
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.psi.psiUtil.getValueParameterList
import org.jetbrains.kotlin.psi.psiUtil.getValueParameters import org.jetbrains.kotlin.psi.psiUtil.getValueParameters
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.JetType
import java.awt.BorderLayout import java.awt.BorderLayout
import java.awt.Color import java.awt.Color
@@ -64,7 +55,6 @@ import javax.swing.BorderFactory
import javax.swing.JPanel import javax.swing.JPanel
import javax.swing.border.EmptyBorder import javax.swing.border.EmptyBorder
import javax.swing.border.LineBorder import javax.swing.border.LineBorder
import kotlin.properties.Delegates
public class KotlinInplaceParameterIntroducer( public class KotlinInplaceParameterIntroducer(
val originalDescriptor: IntroduceParameterDescriptor, val originalDescriptor: IntroduceParameterDescriptor,
@@ -285,7 +275,7 @@ public class KotlinInplaceParameterIntroducer(
} }
private fun removeAddedParameter() { private fun removeAddedParameter() {
runWriteAction { JetPsiUtil.deleteElementWithDelimiters(addedParameter) } runWriteAction { (addedParameter.getParent() as JetParameterList).removeParameter(addedParameter) }
} }
override fun performRefactoring(): Boolean { override fun performRefactoring(): Boolean {
@@ -298,7 +298,7 @@ public class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
element.deleteElementAndCleanParent() element.deleteElementAndCleanParent()
is JetParameter -> is JetParameter ->
JetPsiUtil.deleteElementWithDelimiters(element) (element.getParent() as JetParameterList).removeParameter(element)
} }
} }
@@ -18,13 +18,20 @@ package org.jetbrains.kotlin.idea.refactoring.safeDelete
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceSimpleDeleteUsageInfo import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceSimpleDeleteUsageInfo
import org.jetbrains.kotlin.psi.JetPsiUtil
import org.jetbrains.kotlin.psi.JetValueArgument import org.jetbrains.kotlin.psi.JetValueArgument
import org.jetbrains.kotlin.psi.JetValueArgumentList
public class SafeDeleteValueArgumentListUsageInfo( public class SafeDeleteValueArgumentListUsageInfo(
valueArgument: JetValueArgument, parameter: PsiElement valueArgument: JetValueArgument, parameter: PsiElement
) : SafeDeleteReferenceSimpleDeleteUsageInfo(valueArgument, parameter, true) { ) : SafeDeleteReferenceSimpleDeleteUsageInfo(valueArgument, parameter, true) {
public override fun deleteElement() { public override fun deleteElement() {
getElement()?.let { element -> JetPsiUtil.deleteElementWithDelimiters(element) } val element = getElement() as? JetValueArgument ?: return
val parent = element.getParent()
if (parent is JetValueArgumentList) {
parent.removeArgument(element)
}
else {
element.delete()
}
} }
} }
@@ -28,8 +28,9 @@ public fun PsiElement.canDeleteElement(): Boolean {
if (isObjectLiteral()) return false if (isObjectLiteral()) return false
if (this is JetParameter) { if (this is JetParameter) {
val declaration = getStrictParentOfType<JetDeclaration>() val parameterList = getParent() as? JetParameterList ?: return false
return declaration != null && !(declaration is JetPropertyAccessor && declaration.isSetter()) val declaration = parameterList.getParent() as? JetDeclaration ?: return false
return declaration !is JetPropertyAccessor
} }
return this is JetClassOrObject return this is JetClassOrObject
@@ -57,12 +57,7 @@ fun JetFunctionLiteralArgument.moveInsideParenthesesAndReplaceWith(
val functionLiteralArgument = newCallExpression.getFunctionLiteralArguments().head!! val functionLiteralArgument = newCallExpression.getFunctionLiteralArguments().head!!
val valueArgumentList = newCallExpression.getValueArgumentList() ?: psiFactory.createCallArguments("()") val valueArgumentList = newCallExpression.getValueArgumentList() ?: psiFactory.createCallArguments("()")
val closingParenthesis = valueArgumentList.getLastChild() valueArgumentList.addArgument(argument)
if (valueArgumentList.getArguments().isNotEmpty()) {
valueArgumentList.addBefore(psiFactory.createComma(), closingParenthesis)
valueArgumentList.addBefore(psiFactory.createWhiteSpace(), closingParenthesis)
}
valueArgumentList.addBefore(argument, closingParenthesis)
(functionLiteralArgument.getPrevSibling() as? PsiWhiteSpace)?.delete() (functionLiteralArgument.getPrevSibling() as? PsiWhiteSpace)?.delete()
if (newCallExpression.getValueArgumentList() != null) { if (newCallExpression.getValueArgumentList() != null) {