Skip to content

Commit

Permalink
WIP - Adding trailing comma handling for enums
Browse files Browse the repository at this point in the history
Having issues with PSI not containing the semicolon element
  • Loading branch information
Kantis committed Jul 21, 2022
1 parent 951fbc5 commit 7e755a8
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassBody
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtValueArgumentList
Expand Down Expand Up @@ -91,9 +94,7 @@ public class TrailingCommaRule :
ElementType.TYPE_PARAMETER_LIST -> visitTypeList(node, emit, autoCorrect)
ElementType.VALUE_PARAMETER_LIST -> visitValueList(node, emit, autoCorrect)
ElementType.WHEN_ENTRY -> visitWhenEntry(node, emit, autoCorrect)
else -> Unit
}
when (node.elementType) {
ElementType.CLASS -> visitClassEntry(node, emit, autoCorrect)
ElementType.COLLECTION_LITERAL_EXPRESSION -> visitCollectionLiteralExpression(node, emit, autoCorrect)
ElementType.INDICES -> visitIndices(node, emit, autoCorrect)
ElementType.TYPE_ARGUMENT_LIST -> visitTypeList(node, emit, autoCorrect)
Expand Down Expand Up @@ -192,6 +193,34 @@ public class TrailingCommaRule :
node.reportAndCorrectTrailingCommaNodeBefore(inspectNode, emit, autoCorrect)
}

private fun visitClassEntry(
node: ASTNode,
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit,
autoCorrect: Boolean
) {
val psi = node.psi
require(psi is KtClass)

if (psi.isEnum()) {
val classBody = node.children().singleOrNull { it.psi is KtClassBody }
?: return // Nothing to do for empty enum class

val lastRelevantChild = classBody.psi.children.toList().asReversed()
.first()

val fullAST = psi
val fullPsi = classBody.psi

if (lastRelevantChild !is KtEnumEntry) {
// Aborting processing since Enum contains more than just constants.
return
}

val inspectNode = classBody.lastChildNode
node.reportAndCorrectTrailingCommaNodeBefore(inspectNode, emit, autoCorrect)
}
}

private fun ASTNode.reportAndCorrectTrailingCommaNodeBefore(
inspectNode: ASTNode,
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit,
Expand Down Expand Up @@ -325,7 +354,8 @@ public class TrailingCommaRule :
ElementType.FUNCTION_TYPE,
ElementType.TYPE_PARAMETER_LIST,
ElementType.VALUE_PARAMETER_LIST,
ElementType.WHEN_ENTRY
ElementType.WHEN_ENTRY,
ElementType.CLASS
)

private val TYPES_ON_CALL_SITE = TokenSet.create(
Expand All @@ -335,6 +365,11 @@ public class TrailingCommaRule :
ElementType.VALUE_ARGUMENT_LIST
)

private val ENUM_IGNORED_TYPES = TokenSet.create(
ElementType.WHITE_SPACE,
ElementType.RBRACE
)

internal const val ALLOW_TRAILING_COMMA_NAME = "ij_kotlin_allow_trailing_comma"
private const val ALLOW_TRAILING_COMMA_DESCRIPTION = "Defines whether a trailing comma (or no trailing comma)" +
"should be enforced on the defining side," +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1041,9 +1041,8 @@ class TrailingCommaRuleTest {

trailingCommaRuleAssertThat(code)
.withEditorConfigOverride(allowTrailingCommaProperty to true)
.hasLintViolations(
LintViolation(3, 12, "Missing trailing comma before \"}\"") // TODO
).isFormattedAs(formattedCode)
.hasLintViolation(3, 13, "Missing trailing comma before \"}\"")
.isFormattedAs(formattedCode)
}

@Test
Expand All @@ -1063,10 +1062,116 @@ class TrailingCommaRuleTest {
}
""".trimIndent()

trailingCommaRuleAssertThat(code)
.withEditorConfigOverride(allowTrailingCommaProperty to false)
.hasLintViolation(3, 13, "Unnecessary trailing comma before \"}\"")
.isFormattedAs(formattedCode)
}

@Test
fun `Given that a trailing comma is not allowed then nothing happens for enums terminated with semicolon`() {
val code =
"""
enum class Shape {
SQUARE,
TRIANGLE;
fun print() = name()
}
""".trimIndent()

trailingCommaRuleAssertThat(code)
.withEditorConfigOverride(allowTrailingCommaProperty to false)
.hasNoLintViolations()
}

@Test
fun `Given that a trailing comma is allowed then nothing happens for enums terminated with semicolon`() {
val code =
"""
enum class Shape {
SQUARE,
TRIANGLE;
fun print() = name()
}
""".trimIndent()

trailingCommaRuleAssertThat(code)
.withEditorConfigOverride(allowTrailingCommaProperty to true)
.hasLintViolations(
LintViolation(3, 12, "Unnecessary trailing comma before \"}\"") // TODO
).isFormattedAs(formattedCode)
.hasNoLintViolations()
}

@Test
fun `Given that a trailing comma is allowed then it is added for complicated enums`() {
val code =
"""
interface Printable {
fun print(): String
}
enum class Shape : Printable {
/*
* Block comment is OK!
*/
Square {
override fun print() = "■" // EOL Comment should be OK
},
Triangle {
override fun print() = "▲"
}
}
""".trimIndent()

val formattedCode =
"""
interface Printable {
fun print(): String
}
enum class Shape : Printable {
/*
* Block comment is OK!
*/
Square {
override fun print() = "■" // EOL Comment should be OK
},
Triangle {
override fun print() = "▲"
},
}
""".trimIndent()

trailingCommaRuleAssertThat(code)
.withEditorConfigOverride(allowTrailingCommaProperty to true)
.hasLintViolation(15, 6, "Missing trailing comma before \"}\"")
.isFormattedAs(formattedCode)
}

@Test
fun `Given that a trailing comma is allowed then it is added if enum is already terminated with semi-colon`() {
val code =
"""
enum class Shape {
SQUARE,
TRIANGLE;
}
""".trimIndent()

val formattedCode =
"""
enum class Shape {
SQUARE,
TRIANGLE,
;
}
""".trimIndent()

trailingCommaRuleAssertThat(code)
.withEditorConfigOverride(allowTrailingCommaProperty to true)
.hasLintViolation(3, 14, "Missing trailing comma before \"}\"")
.isFormattedAs(formattedCode)
}
}

0 comments on commit 7e755a8

Please sign in to comment.