diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/EditCommaSeparatedListHelper.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/EditCommaSeparatedListHelper.kt new file mode 100644 index 00000000000..9f0dfaeb51e --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/EditCommaSeparatedListHelper.kt @@ -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 addItem(list: JetElement, allItems: List, item: TItem): TItem { + return addItemBefore(list, allItems, item, null) + } + + public fun addItemAfter(list: JetElement, allItems: List, 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 addItemBefore(list: JetElement, allItems: List, 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 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() + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetParameterList.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetParameterList.java index 59763231799..4fbcec169c2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetParameterList.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetParameterList.java @@ -47,53 +47,21 @@ public class JetParameterList extends JetElementImplStub 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); - } - } + return EditCommaSeparatedListHelper.INSTANCE$.addItemAfter(this, getParameters(), parameter, anchor); } @NotNull public JetParameter addParameterBefore(@NotNull JetParameter parameter, @Nullable JetParameter anchor) { - List parameters = getParameters(); - JetParameter anchorAfter; - if (parameters.isEmpty()) { - assert anchor == null; - anchorAfter = null; - } - 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); + return EditCommaSeparatedListHelper.INSTANCE$.addItemBefore(this, getParameters(), parameter, anchor); + } + + public void removeParameter(@NotNull JetParameter parameter) { + EditCommaSeparatedListHelper.INSTANCE$.removeItem(parameter); } // this method needed only for migrate lambda syntax diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java index c1d474f9e10..d2801255653 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiUtil.java @@ -24,8 +24,6 @@ import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; 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.util.PsiTreeUtil; import com.intellij.util.codeInsight.CommentUtilCore; @@ -36,7 +34,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.JetNodeTypes; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 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.JetTokens; import org.jetbrains.kotlin.name.FqName; @@ -715,35 +712,6 @@ public class JetPsiUtil { 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 void deleteChildlessElement(PsiElement element, Class childClass) { - if (PsiTreeUtil.getChildrenOfType(element, childClass) == null) { - element.delete(); - } - } - public static PsiElement ascendIfPropertyAccessor(PsiElement element) { if (element instanceof JetPropertyAccessor) { return element.getParent(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetValueArgumentList.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetValueArgumentList.java index cc968000984..f5b9c0bacd3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetValueArgumentList.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetValueArgumentList.java @@ -49,4 +49,23 @@ public class JetValueArgumentList extends JetElementImpl { public PsiElement getLeftParenthesis() { 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); + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt index 30db995ef39..b2b0aa2a3c9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt @@ -238,14 +238,44 @@ public fun PsiElement.isExtensionDeclaration(): Boolean { public fun PsiElement.isObjectLiteral(): Boolean = this is JetObjectDeclaration && isObjectLiteral() +//TODO: git rid of this method public fun PsiElement.deleteElementAndCleanParent() { val parent = getParent() - JetPsiUtil.deleteElementWithDelimiters(this) - @suppress("UNCHECKED_CAST") - JetPsiUtil.deleteChildlessElement(parent, this.javaClass) + deleteElementWithDelimiters(this) + deleteChildlessElement(parent, this.javaClass) } +// Delete element if it doesn't contain children of a given type +private fun deleteChildlessElement(element: PsiElement, childClass: Class) { + if (PsiTreeUtil.getChildrenOfType(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(element, element.javaClass) + + val from: PsiElement + val to: PsiElement + if (paramBefore != null) { + from = paramBefore.getNextSibling() + to = element + } + else { + val paramAfter = PsiTreeUtil.getNextSiblingOfType(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 { val parent = getParent() return when { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/KotlinSuppressIntentionAction.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/KotlinSuppressIntentionAction.kt index 2b999530eb6..91491f09064 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/KotlinSuppressIntentionAction.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/KotlinSuppressIntentionAction.kt @@ -122,10 +122,7 @@ public class KotlinSuppressIntentionAction( args.replace(newArgList) } else { - val rightParen = args.getRightParenthesis() - args.addBefore(psiFactory.createComma(), rightParen) - args.addBefore(psiFactory.createWhiteSpace(), rightParen) - args.addBefore(newArgList.getArguments()[0], rightParen) + args.addArgument(newArgList.getArguments()[0]) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionCallUsage.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionCallUsage.java index 51fc59cee27..2ebaf301ac3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionCallUsage.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/usages/JetFunctionCallUsage.java @@ -375,10 +375,10 @@ public class JetFunctionCallUsage extends JetUsageInfo { // TODO: process default arguments in the middle else if (parameterInfo.getDefaultValueForCall() == null) { if (parameterInfo.getDefaultValueForParameter() != null) { - JetPsiUtil.deleteElementWithDelimiters(newArgument); + newArgumentList.removeArgument(newArgument); } else { - newArgument.delete(); + newArgument.delete(); // keep space between commas } } else { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinInplaceParameterIntroducer.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinInplaceParameterIntroducer.kt index e894eb94c7a..1dfb331af2f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinInplaceParameterIntroducer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinInplaceParameterIntroducer.kt @@ -31,29 +31,20 @@ import com.intellij.openapi.editor.markup.MarkupModel import com.intellij.openapi.editor.markup.TextAttributes import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement -import com.intellij.refactoring.rename.inplace.InplaceRefactoring import com.intellij.ui.DottedBorder import com.intellij.ui.JBColor import com.intellij.ui.NonFocusableCheckBox import org.jetbrains.kotlin.idea.JetFileType -import org.jetbrains.kotlin.idea.caches.resolve.analyze -import org.jetbrains.kotlin.idea.refactoring.changeSignature.* +import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar 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.supertypes import org.jetbrains.kotlin.psi.JetExpression import org.jetbrains.kotlin.psi.JetParameter -import org.jetbrains.kotlin.psi.JetPsiFactory -import org.jetbrains.kotlin.psi.JetPsiUtil +import org.jetbrains.kotlin.psi.JetParameterList 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.isAncestor -import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.types.JetType import java.awt.BorderLayout import java.awt.Color @@ -64,7 +55,6 @@ import javax.swing.BorderFactory import javax.swing.JPanel import javax.swing.border.EmptyBorder import javax.swing.border.LineBorder -import kotlin.properties.Delegates public class KotlinInplaceParameterIntroducer( val originalDescriptor: IntroduceParameterDescriptor, @@ -285,7 +275,7 @@ public class KotlinInplaceParameterIntroducer( } private fun removeAddedParameter() { - runWriteAction { JetPsiUtil.deleteElementWithDelimiters(addedParameter) } + runWriteAction { (addedParameter.getParent() as JetParameterList).removeParameter(addedParameter) } } override fun performRefactoring(): Boolean { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt index 4aa85be6583..c8c590bad0b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt @@ -298,7 +298,7 @@ public class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() { element.deleteElementAndCleanParent() is JetParameter -> - JetPsiUtil.deleteElementWithDelimiters(element) + (element.getParent() as JetParameterList).removeParameter(element) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteValueArgumentListUsageInfo.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteValueArgumentListUsageInfo.kt index 947294a83ba..37ab09c5c5e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteValueArgumentListUsageInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteValueArgumentListUsageInfo.kt @@ -18,13 +18,20 @@ package org.jetbrains.kotlin.idea.refactoring.safeDelete import com.intellij.psi.PsiElement import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceSimpleDeleteUsageInfo -import org.jetbrains.kotlin.psi.JetPsiUtil import org.jetbrains.kotlin.psi.JetValueArgument +import org.jetbrains.kotlin.psi.JetValueArgumentList public class SafeDeleteValueArgumentListUsageInfo( valueArgument: JetValueArgument, parameter: PsiElement ) : SafeDeleteReferenceSimpleDeleteUsageInfo(valueArgument, parameter, true) { 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() + } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/utils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/utils.kt index a78d181c8db..c281983b18d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/utils.kt @@ -28,8 +28,9 @@ public fun PsiElement.canDeleteElement(): Boolean { if (isObjectLiteral()) return false if (this is JetParameter) { - val declaration = getStrictParentOfType() - return declaration != null && !(declaration is JetPropertyAccessor && declaration.isSetter()) + val parameterList = getParent() as? JetParameterList ?: return false + val declaration = parameterList.getParent() as? JetDeclaration ?: return false + return declaration !is JetPropertyAccessor } return this is JetClassOrObject diff --git a/idea/src/org/jetbrains/kotlin/idea/util/psiModificationUtil.kt b/idea/src/org/jetbrains/kotlin/idea/util/psiModificationUtil.kt index 99d8e6e4f17..ad320366ef0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/util/psiModificationUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/util/psiModificationUtil.kt @@ -57,12 +57,7 @@ fun JetFunctionLiteralArgument.moveInsideParenthesesAndReplaceWith( 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) + valueArgumentList.addArgument(argument) (functionLiteralArgument.getPrevSibling() as? PsiWhiteSpace)?.delete() if (newCallExpression.getValueArgumentList() != null) {