diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt index 4f93c00997f..ced34efd64d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/TrailingCommaInspection.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.inspections +import com.intellij.application.options.CodeStyle import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel @@ -73,23 +74,26 @@ class TrailingCommaInspection( highlightType: ProblemHighlightType = ProblemHighlightType.GENERIC_ERROR_OR_WARNING, ) { val commaOwner = commaOrElement.parent + // case for KtFunctionLiteral, where PsiWhiteSpace after KtTypeParameterList isn't included in this list + val problemOwner = commaOwner.parent holder.registerProblem( - commaOwner, + problemOwner, message, highlightType, - commaOrElement.textRangeOfLastSymbol.shiftLeft(commaOwner.startOffset), - ReformatQuickFix(fixMessage), + commaOrElement.textRangeOfCommaOrSymbolAfter.shiftLeft(problemOwner.startOffset), + ReformatQuickFix(fixMessage, commaOwner), ) } - private val PsiElement.textRangeOfLastSymbol: TextRange + private val PsiElement.textRangeOfCommaOrSymbolAfter: TextRange get() { val textRange = textRange if (textRange.length <= 1) return textRange - return nextLeaf()?.leafIgnoringWhitespaceAndComments(false)?.endOffset?.takeIf { it > 0 }?.let { - TextRange.create(it - 1, it).intersection(textRange) + val resultRange = nextLeaf()?.leafIgnoringWhitespaceAndComments(false)?.endOffset?.takeIf { it > 0 }?.let { + TextRange.create(it - 1, it).intersection(parent.textRange) } ?: TextRange.create(textRange.endOffset - 1, textRange.endOffset) + return resultRange.shiftRight(1) } } @@ -104,10 +108,13 @@ private enum class TrailingCommaAction { ADD, REFORMAT, REMOVE; companion object { - fun create(commaOwner: KtElement): TrailingCommaAction = when { - needComma(commaOwner, checkExistingTrailingComma = false) -> ADD - needComma(commaOwner, checkExistingTrailingComma = true) -> REFORMAT - else -> REMOVE + fun create(commaOwner: KtElement): TrailingCommaAction { + val settings = CodeStyle.getSettings(commaOwner.project) + return when { + needComma(commaOwner, settings, checkExistingTrailingComma = false) -> ADD + needComma(commaOwner, settings, checkExistingTrailingComma = true) -> REFORMAT + else -> REMOVE + } } } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ReformatQuickFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ReformatQuickFix.kt index 22ddfff0155..3eceed10805 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ReformatQuickFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ReformatQuickFix.kt @@ -8,15 +8,19 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.codeInspection.LocalQuickFix import com.intellij.codeInspection.ProblemDescriptor import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement import com.intellij.psi.codeStyle.CodeStyleManager +import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer + +class ReformatQuickFix(private val description: String, element: PsiElement? = null) : LocalQuickFix { + private val elementPoint = element?.createSmartPointer() -class ReformatQuickFix(val description: String) : LocalQuickFix { override fun getName(): String = description override fun getFamilyName(): String = name override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - descriptor.psiElement?.let { + (elementPoint?.element ?: descriptor.psiElement)?.let { CodeStyleManager.getInstance(project).reformat(it) } } diff --git a/idea/testData/inspectionsLocal/trailingComma/addComma2.kt b/idea/testData/inspectionsLocal/trailingComma/addComma2.kt new file mode 100644 index 00000000000..acef4bead07 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/addComma2.kt @@ -0,0 +1,5 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Add trailing comma + +fun a(i: Int, + b: Boolean) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/addComma2.kt.after b/idea/testData/inspectionsLocal/trailingComma/addComma2.kt.after new file mode 100644 index 00000000000..88c61d70292 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/addComma2.kt.after @@ -0,0 +1,7 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Add trailing comma + +fun a( + i: Int, + b: Boolean, +) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/addComma3.kt b/idea/testData/inspectionsLocal/trailingComma/addComma3.kt new file mode 100644 index 00000000000..11cd7bf6314 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/addComma3.kt @@ -0,0 +1,5 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// PROBLEM: none + +fun a(i: Int, + b: Boolean) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/addComma4.kt b/idea/testData/inspectionsLocal/trailingComma/addComma4.kt new file mode 100644 index 00000000000..7eb3d1304da --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/addComma4.kt @@ -0,0 +1,5 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// PROBLEM: none + +fun a(i: Int, + b: Boolean) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/addComma5.kt b/idea/testData/inspectionsLocal/trailingComma/addComma5.kt new file mode 100644 index 00000000000..e32dbdf6ea5 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/addComma5.kt @@ -0,0 +1,5 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Add trailing comma + +fun a(i: Int, + b: Boolean ) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/addComma5.kt.after b/idea/testData/inspectionsLocal/trailingComma/addComma5.kt.after new file mode 100644 index 00000000000..88c61d70292 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/addComma5.kt.after @@ -0,0 +1,7 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Add trailing comma + +fun a( + i: Int, + b: Boolean, +) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/addComma6.kt b/idea/testData/inspectionsLocal/trailingComma/addComma6.kt new file mode 100644 index 00000000000..61435887af7 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/addComma6.kt @@ -0,0 +1,8 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Add trailing comma + +val x = { + x: String, y + : String-> + val a = 2 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/addComma6.kt.after b/idea/testData/inspectionsLocal/trailingComma/addComma6.kt.after new file mode 100644 index 00000000000..bcf244fcdcc --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/addComma6.kt.after @@ -0,0 +1,10 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Add trailing comma + +val x = { + x: String, + y + : String, + -> + val a = 2 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition2.kt b/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition2.kt new file mode 100644 index 00000000000..4c5cf345603 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition2.kt @@ -0,0 +1,5 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Fix comma position + +fun a(i: Int /* +*/, b: Boolean) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition2.kt.after b/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition2.kt.after new file mode 100644 index 00000000000..cd0b3a1ec65 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition2.kt.after @@ -0,0 +1,8 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Fix comma position + +fun a( + i: Int, /* +*/ + b: Boolean, +) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition3.kt b/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition3.kt new file mode 100644 index 00000000000..12027e67fa5 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition3.kt @@ -0,0 +1,5 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// PROBLEM: none + +fun a(i: Int /* +*/, b: Boolean) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition4.kt b/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition4.kt new file mode 100644 index 00000000000..5c914acf756 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/changeCommaPosition4.kt @@ -0,0 +1,5 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// PROBLEM: none + +fun a(i: Int /* +*/, b: Boolean) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/removeComma2.kt b/idea/testData/inspectionsLocal/trailingComma/removeComma2.kt new file mode 100644 index 00000000000..de1666fff69 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/removeComma2.kt @@ -0,0 +1,4 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Remove trailing comma + +fun a(i: Int, b: Boolean,) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/removeComma2.kt.after b/idea/testData/inspectionsLocal/trailingComma/removeComma2.kt.after new file mode 100644 index 00000000000..3eff3145a52 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/removeComma2.kt.after @@ -0,0 +1,4 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// FIX: Remove trailing comma + +fun a(i: Int, b: Boolean) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/removeComma3.kt b/idea/testData/inspectionsLocal/trailingComma/removeComma3.kt new file mode 100644 index 00000000000..94b1d6599d8 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/removeComma3.kt @@ -0,0 +1,4 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// PROBLEM: none + +fun a(i: Int, b: Boolean,) = Unit \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/trailingComma/removeComma4.kt b/idea/testData/inspectionsLocal/trailingComma/removeComma4.kt new file mode 100644 index 00000000000..fa4d1881241 --- /dev/null +++ b/idea/testData/inspectionsLocal/trailingComma/removeComma4.kt @@ -0,0 +1,4 @@ +// COMPILER_ARGUMENTS: -XXLanguage:+TrailingCommas +// PROBLEM: none + +fun a(i: Int, b: Boolean,) = Unit \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 7ded403f2ce..de1f3ea9293 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -12271,6 +12271,31 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/trailingComma/addComma.kt"); } + @TestMetadata("addComma2.kt") + public void testAddComma2() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/addComma2.kt"); + } + + @TestMetadata("addComma3.kt") + public void testAddComma3() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/addComma3.kt"); + } + + @TestMetadata("addComma4.kt") + public void testAddComma4() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/addComma4.kt"); + } + + @TestMetadata("addComma5.kt") + public void testAddComma5() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/addComma5.kt"); + } + + @TestMetadata("addComma6.kt") + public void testAddComma6() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/addComma6.kt"); + } + public void testAllFilesPresentInTrailingComma() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/trailingComma"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); } @@ -12280,10 +12305,40 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/trailingComma/changeCommaPosition.kt"); } + @TestMetadata("changeCommaPosition2.kt") + public void testChangeCommaPosition2() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/changeCommaPosition2.kt"); + } + + @TestMetadata("changeCommaPosition3.kt") + public void testChangeCommaPosition3() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/changeCommaPosition3.kt"); + } + + @TestMetadata("changeCommaPosition4.kt") + public void testChangeCommaPosition4() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/changeCommaPosition4.kt"); + } + @TestMetadata("removeComma.kt") public void testRemoveComma() throws Exception { runTest("idea/testData/inspectionsLocal/trailingComma/removeComma.kt"); } + + @TestMetadata("removeComma2.kt") + public void testRemoveComma2() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/removeComma2.kt"); + } + + @TestMetadata("removeComma3.kt") + public void testRemoveComma3() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/removeComma3.kt"); + } + + @TestMetadata("removeComma4.kt") + public void testRemoveComma4() throws Exception { + runTest("idea/testData/inspectionsLocal/trailingComma/removeComma4.kt"); + } } @TestMetadata("idea/testData/inspectionsLocal/unlabeledReturnInsideLambda")