"Put/Join arguments/parameters" intention: don't suggest on nested argument list

#KT-31020 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-12-24 14:31:16 +09:00
committed by Yan Zhulanow
parent be194c3460
commit 4a328981c6
17 changed files with 237 additions and 11 deletions
@@ -8,31 +8,33 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.application.options.CodeStyle import com.intellij.application.options.CodeStyle
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.CommonCodeStyleSettings import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.inspections.findExistingEditor
import org.jetbrains.kotlin.idea.formatter.kotlinCommonSettings import org.jetbrains.kotlin.idea.formatter.kotlinCommonSettings
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.allChildren import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.psi.psiUtil.startOffset
abstract class AbstractChopListIntention<TList : KtElement, TElement : KtElement>( abstract class AbstractChopListIntention<TList : KtElement, TElement : KtElement>(
listClass: Class<TList>, listClass: Class<TList>,
private val elementClass: Class<TElement>, private val elementClass: Class<TElement>,
textGetter: () -> String textGetter: () -> String
) : SelfTargetingOffsetIndependentIntention<TList>(listClass, textGetter) { ) : SelfTargetingIntention<TList>(listClass, textGetter) {
override fun allowCaretInsideElement(element: PsiElement) =
element !is KtValueArgument && super.allowCaretInsideElement(element)
open fun leftParOnNewLine(commonCodeStyleSettings: CommonCodeStyleSettings): Boolean = false open fun leftParOnNewLine(commonCodeStyleSettings: CommonCodeStyleSettings): Boolean = false
open fun rightParOnNewLine(commonCodeStyleSettings: CommonCodeStyleSettings): Boolean = false open fun rightParOnNewLine(commonCodeStyleSettings: CommonCodeStyleSettings): Boolean = false
override fun isApplicableTo(element: TList): Boolean { override fun isApplicableTo(element: TList, caretOffset: Int): Boolean {
val elements = element.elements() val elements = element.elements()
if (elements.size <= 1) return false if (elements.size <= 1) return false
if (!isApplicableCaretOffset(caretOffset, element)) return false
if (elements.dropLast(1).all { hasLineBreakAfter(it) }) return false if (elements.dropLast(1).all { hasLineBreakAfter(it) }) return false
return true return true
} }
@@ -82,6 +84,12 @@ abstract class AbstractChopListIntention<TList : KtElement, TElement : KtElement
it as TElement it as TElement
} }
.toList() .toList()
protected fun isApplicableCaretOffset(caretOffset: Int, element: TList): Boolean {
val elementBeforeCaret = element.containingFile.findElementAt(caretOffset - 1) ?: return true
if (elementBeforeCaret.node.elementType != KtTokens.RPAR) return true
return elementBeforeCaret.parent == element
}
} }
class ChopParameterListIntention : AbstractChopListIntention<KtParameterList, KtParameter>( class ChopParameterListIntention : AbstractChopListIntention<KtParameterList, KtParameter>(
@@ -89,9 +97,9 @@ class ChopParameterListIntention : AbstractChopListIntention<KtParameterList, Kt
KtParameter::class.java, KtParameter::class.java,
KotlinBundle.lazyMessage("put.parameters.on.separate.lines") KotlinBundle.lazyMessage("put.parameters.on.separate.lines")
) { ) {
override fun isApplicableTo(element: KtParameterList): Boolean { override fun isApplicableTo(element: KtParameterList, caretOffset: Int): Boolean {
if (element.parent is KtFunctionLiteral) return false if (element.parent is KtFunctionLiteral) return false
return super.isApplicableTo(element) return super.isApplicableTo(element, caretOffset)
} }
override fun leftParOnNewLine(commonCodeStyleSettings: CommonCodeStyleSettings): Boolean { override fun leftParOnNewLine(commonCodeStyleSettings: CommonCodeStyleSettings): Boolean {
@@ -22,9 +22,10 @@ abstract class AbstractJoinListIntention<TList : KtElement, TElement : KtElement
elementClass: Class<TElement>, elementClass: Class<TElement>,
textGetter: () -> String textGetter: () -> String
) : AbstractChopListIntention<TList, TElement>(listClass, elementClass, textGetter) { ) : AbstractChopListIntention<TList, TElement>(listClass, elementClass, textGetter) {
override fun isApplicableTo(element: TList): Boolean { override fun isApplicableTo(element: TList, caretOffset: Int): Boolean {
val elements = element.elements() val elements = element.elements()
if (elements.isEmpty()) return false if (elements.isEmpty()) return false
if (!isApplicableCaretOffset(caretOffset, element)) return false
return (hasLineBreakBefore(elements.first()) || elements.any { hasLineBreakAfter(it) }) return (hasLineBreakBefore(elements.first()) || elements.any { hasLineBreakAfter(it) })
&& element.allChildren.none { it is PsiComment && it.node.elementType == KtTokens.EOL_COMMENT } && element.allChildren.none { it is PsiComment && it.node.elementType == KtTokens.EOL_COMMENT }
} }
@@ -53,9 +54,9 @@ class JoinParameterListIntention : AbstractJoinListIntention<KtParameterList, Kt
KtParameter::class.java, KtParameter::class.java,
KotlinBundle.lazyMessage("put.parameters.on.one.line") KotlinBundle.lazyMessage("put.parameters.on.one.line")
) { ) {
override fun isApplicableTo(element: KtParameterList): Boolean { override fun isApplicableTo(element: KtParameterList, caretOffset: Int): Boolean {
if (element.parent is KtFunctionLiteral) return false if (element.parent is KtFunctionLiteral) return false
return super.isApplicableTo(element) return super.isApplicableTo(element, caretOffset)
} }
} }
@@ -0,0 +1,12 @@
// IS_APPLICABLE: false
fun foo() {
f(1, 2, g(<caret>
3,
4,
5
), 3)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,12 @@
// IS_APPLICABLE: false
fun foo() {
f(1, 2, g<caret>(
3,
4,
5
), 3)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,12 @@
// IS_APPLICABLE: false
fun foo() {
f(1, 2, g(
3,
4,
5
)<caret>, 3)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,12 @@
fun foo() {
f(
1,
2,
g(3, 4, 5)<caret>,
3
)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,16 @@
fun foo() {
f(
1,
2,
g(
3,
4,
5
),
3
)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,11 @@
fun foo() {
f(1, 2, g(
3,
4,
5
), 3)<caret>
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,16 @@
fun foo() {
f(
1,
2,
g(
3,
4,
5
),
3
)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,13 @@
// IS_APPLICABLE: false
fun foo() {
f(
1,
2,
g(<caret>3, 4, 5),
3
)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,13 @@
// IS_APPLICABLE: false
fun foo() {
f(
1,
2,
g<caret>(3, 4, 5),
3
)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,13 @@
// IS_APPLICABLE: false
fun foo() {
f(
1,
2,
g(3, 4, 5)<caret>,
3
)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,11 @@
fun foo() {
f(1, 2, g(
3,
4,
5
)<caret>, 3)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,7 @@
fun foo() {
f(1, 2, g(3, 4, 5), 3)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,12 @@
fun foo() {
f(
1,
2,
g(3, 4, 5),
3
)<caret>
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -0,0 +1,7 @@
fun foo() {
f(1, 2, g(3, 4, 5), 3)
}
fun f(a: Int, b: Int, c: Int, d: Int): Int = 0
fun g(a: Int, b: Int, c: Int): Int = 0
@@ -3763,6 +3763,31 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/chop/argumentList"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/chop/argumentList"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
} }
@TestMetadata("onNestedArgumentList.kt")
public void testOnNestedArgumentList() throws Exception {
runTest("idea/testData/intentions/chop/argumentList/onNestedArgumentList.kt");
}
@TestMetadata("onNestedArgumentList2.kt")
public void testOnNestedArgumentList2() throws Exception {
runTest("idea/testData/intentions/chop/argumentList/onNestedArgumentList2.kt");
}
@TestMetadata("onNestedArgumentList3.kt")
public void testOnNestedArgumentList3() throws Exception {
runTest("idea/testData/intentions/chop/argumentList/onNestedArgumentList3.kt");
}
@TestMetadata("onNestedArgumentList4.kt")
public void testOnNestedArgumentList4() throws Exception {
runTest("idea/testData/intentions/chop/argumentList/onNestedArgumentList4.kt");
}
@TestMetadata("onRightParenthesis.kt")
public void testOnRightParenthesis() throws Exception {
runTest("idea/testData/intentions/chop/argumentList/onRightParenthesis.kt");
}
@TestMetadata("leftParOnSameLine.kt") @TestMetadata("leftParOnSameLine.kt")
public void testLeftParOnSameLine() throws Exception { public void testLeftParOnSameLine() throws Exception {
runTest("idea/testData/intentions/chop/argumentList/leftParOnSameLine.kt"); runTest("idea/testData/intentions/chop/argumentList/leftParOnSameLine.kt");
@@ -10668,6 +10693,31 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/joinArgumentList/noLineBreak.kt"); runTest("idea/testData/intentions/joinArgumentList/noLineBreak.kt");
} }
@TestMetadata("onNestedArgumentList.kt")
public void testOnNestedArgumentList() throws Exception {
runTest("idea/testData/intentions/joinArgumentList/onNestedArgumentList.kt");
}
@TestMetadata("onNestedArgumentList2.kt")
public void testOnNestedArgumentList2() throws Exception {
runTest("idea/testData/intentions/joinArgumentList/onNestedArgumentList2.kt");
}
@TestMetadata("onNestedArgumentList3.kt")
public void testOnNestedArgumentList3() throws Exception {
runTest("idea/testData/intentions/joinArgumentList/onNestedArgumentList3.kt");
}
@TestMetadata("onNestedArgumentList4.kt")
public void testOnNestedArgumentList4() throws Exception {
runTest("idea/testData/intentions/joinArgumentList/onNestedArgumentList4.kt");
}
@TestMetadata("onRightParenthesis.kt")
public void testOnRightParenthesis() throws Exception {
runTest("idea/testData/intentions/joinArgumentList/onRightParenthesis.kt");
}
@TestMetadata("oneArg.kt") @TestMetadata("oneArg.kt")
public void testOneArg() throws Exception { public void testOneArg() throws Exception {
runTest("idea/testData/intentions/joinArgumentList/oneArg.kt"); runTest("idea/testData/intentions/joinArgumentList/oneArg.kt");