Skip to content

Commit

Permalink
Remove shared methods
Browse files Browse the repository at this point in the history
  • Loading branch information
chao2zhang committed Jul 24, 2022
1 parent fc3216a commit 4ad78f2
Show file tree
Hide file tree
Showing 4 changed files with 341 additions and 166 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,26 @@ import com.pinterest.ktlint.core.api.EditorConfigProperties
import com.pinterest.ktlint.core.api.UsesEditorConfigProperties
import com.pinterest.ktlint.core.ast.ElementType
import com.pinterest.ktlint.core.ast.children
import com.pinterest.ktlint.ruleset.standard.internal.trailingcomma.reportAndCorrectTrailingCommaNodeBefore
import com.pinterest.ktlint.core.ast.containsLineBreakInRange
import com.pinterest.ktlint.core.ast.prevCodeLeaf
import com.pinterest.ktlint.core.ast.prevLeaf
import kotlin.properties.Delegates
import org.ec4j.core.model.PropertyType
import org.ec4j.core.model.PropertyType.PropertyValueParser
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.KtCollectionLiteralExpression
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtValueArgumentList
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.nextLeaf
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf

/**
* Linting trailing comma for call site.
Expand Down Expand Up @@ -128,6 +142,150 @@ public class TrailingCommaOnCallSiteRule :
)
}

private fun ASTNode.reportAndCorrectTrailingCommaNodeBefore(
inspectNode: ASTNode,
isTrailingCommaAllowed: Boolean,
autoCorrect: Boolean,
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit
) {
val prevLeaf = inspectNode.prevLeaf()
val trailingCommaNode = prevLeaf.findPreviousTrailingCommaNodeOrNull()
val trailingCommaState = when {
isMultiline(psi) -> if (trailingCommaNode != null) TrailingCommaState.EXISTS else TrailingCommaState.MISSING
else -> if (trailingCommaNode != null) TrailingCommaState.REDUNDANT else TrailingCommaState.NOT_EXISTS
}
when (trailingCommaState) {
TrailingCommaState.EXISTS -> if (!isTrailingCommaAllowed) {
emit(
trailingCommaNode!!.startOffset,
"Unnecessary trailing comma before \"${inspectNode.text}\"",
true
)
if (autoCorrect) {
this.removeChild(trailingCommaNode)
}
}
TrailingCommaState.MISSING -> if (isTrailingCommaAllowed) {
val addNewLineBeforeArrowInWhenEntry = addNewLineBeforeArrowInWhen()
val prevNode = inspectNode.prevCodeLeaf()!!
if (addNewLineBeforeArrowInWhenEntry) {
emit(
prevNode.startOffset + prevNode.textLength,
"Missing trailing comma and newline before \"${inspectNode.text}\"",
true
)
} else {
emit(
prevNode.startOffset + prevNode.textLength,
"Missing trailing comma before \"${inspectNode.text}\"",
true
)
}
if (autoCorrect) {
if (addNewLineBeforeArrowInWhenEntry) {
val parentIndent = (prevNode.psi.parent.prevLeaf() as? PsiWhiteSpace)?.text ?: "\n"
val leafBeforeArrow = (psi as KtWhenEntry).arrow?.prevLeaf()
if (leafBeforeArrow != null && leafBeforeArrow is PsiWhiteSpace) {
val newLine = KtPsiFactory(prevNode.psi).createWhiteSpace(parentIndent)
leafBeforeArrow.replace(newLine)
} else {
val newLine = KtPsiFactory(prevNode.psi).createWhiteSpace(parentIndent)
prevNode.psi.parent.addAfter(newLine, prevNode.psi)
}
}
val comma = KtPsiFactory(prevNode.psi).createComma()
prevNode.psi.parent.addAfter(comma, prevNode.psi)
}
}
TrailingCommaState.REDUNDANT -> {
emit(
trailingCommaNode!!.startOffset,
"Unnecessary trailing comma before \"${inspectNode.text}\"",
true
)
if (autoCorrect) {
this.removeChild(trailingCommaNode)
}
}
TrailingCommaState.NOT_EXISTS -> Unit
}
}

private enum class TrailingCommaState {
/**
* The trailing comma is needed and exists
*/
EXISTS,

/**
* The trailing comma is needed and doesn't exist
*/
MISSING,

/**
* The trailing comma isn't needed and doesn't exist
*/
NOT_EXISTS,

/**
* The trailing comma isn't needed, but exists
*/
REDUNDANT,
;
}

private fun isMultiline(element: PsiElement): Boolean = when {
element.parent is KtFunctionLiteral -> isMultiline(element.parent)
element is KtFunctionLiteral -> containsLineBreakInRange(element.valueParameterList!!, element.arrow!!)
element is KtWhenEntry -> containsLineBreakInRange(element.firstChild, element.arrow!!)
element is KtDestructuringDeclaration -> containsLineBreakInRange(element.lPar!!, element.rPar!!)
element is KtValueArgumentList && element.children.size == 1 && element.anyDescendantOfType<KtCollectionLiteralExpression>() -> {
// special handling for collection literal
// @Annotation([
// "something",
// ])
val lastChild = element.collectDescendantsOfType<KtCollectionLiteralExpression>().last()
containsLineBreakInLeafsRange(lastChild.rightBracket!!, element.rightParenthesis!!)
}
else -> element.textContains('\n')
}

private fun ASTNode.addNewLineBeforeArrowInWhen() =
if (psi is KtWhenEntry) {
val leafBeforeArrow = (psi as KtWhenEntry).arrow?.prevLeaf()
!(leafBeforeArrow is PsiWhiteSpace && leafBeforeArrow.textContains('\n'))
} else {
false
}

private fun ASTNode?.findPreviousTrailingCommaNodeOrNull(): ASTNode? {
var node = this
while (node?.isIgnorable() == true) {
node = node.prevLeaf()
}
return if (node?.elementType == ElementType.COMMA) {
node
} else {
null
}
}

private fun containsLineBreakInLeafsRange(from: PsiElement, to: PsiElement): Boolean {
var leaf: PsiElement? = from
while (leaf != null && !leaf.isEquivalentTo(to)) {
if (leaf.textContains('\n')) {
return true
}
leaf = leaf.nextLeaf(skipEmptyElements = false)
}
return leaf?.textContains('\n') ?: false
}

private fun ASTNode.isIgnorable(): Boolean =
elementType == ElementType.WHITE_SPACE ||
elementType == ElementType.EOL_COMMENT ||
elementType == ElementType.BLOCK_COMMENT

public companion object {
internal const val ALLOW_TRAILING_COMMA_ON_CALL_SITE_NAME = "ij_kotlin_allow_trailing_comma_on_call_site"
private const val ALLOW_TRAILING_COMMA_ON_CALL_SITE_DESCRIPTION =
Expand Down Expand Up @@ -157,3 +315,4 @@ public class TrailingCommaOnCallSiteRule :
)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,27 @@ import com.pinterest.ktlint.core.api.EditorConfigProperties
import com.pinterest.ktlint.core.api.UsesEditorConfigProperties
import com.pinterest.ktlint.core.ast.ElementType
import com.pinterest.ktlint.core.ast.children
import com.pinterest.ktlint.ruleset.standard.internal.trailingcomma.reportAndCorrectTrailingCommaNodeBefore
import com.pinterest.ktlint.core.ast.containsLineBreakInRange
import com.pinterest.ktlint.core.ast.prevCodeLeaf
import com.pinterest.ktlint.core.ast.prevLeaf
import kotlin.properties.Delegates
import org.ec4j.core.model.PropertyType
import org.ec4j.core.model.PropertyType.PropertyValueParser
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.KtCollectionLiteralExpression
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtValueArgumentList
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.nextLeaf
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
import org.jetbrains.kotlin.utils.addToStdlib.cast

/**
Expand Down Expand Up @@ -157,6 +170,150 @@ public class TrailingCommaOnDeclarationSiteRule :
)
}

private fun ASTNode.reportAndCorrectTrailingCommaNodeBefore(
inspectNode: ASTNode,
isTrailingCommaAllowed: Boolean,
autoCorrect: Boolean,
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit
) {
val prevLeaf = inspectNode.prevLeaf()
val trailingCommaNode = prevLeaf.findPreviousTrailingCommaNodeOrNull()
val trailingCommaState = when {
isMultiline(psi) -> if (trailingCommaNode != null) TrailingCommaState.EXISTS else TrailingCommaState.MISSING
else -> if (trailingCommaNode != null) TrailingCommaState.REDUNDANT else TrailingCommaState.NOT_EXISTS
}
when (trailingCommaState) {
TrailingCommaState.EXISTS -> if (!isTrailingCommaAllowed) {
emit(
trailingCommaNode!!.startOffset,
"Unnecessary trailing comma before \"${inspectNode.text}\"",
true
)
if (autoCorrect) {
this.removeChild(trailingCommaNode)
}
}
TrailingCommaState.MISSING -> if (isTrailingCommaAllowed) {
val addNewLineBeforeArrowInWhenEntry = addNewLineBeforeArrowInWhen()
val prevNode = inspectNode.prevCodeLeaf()!!
if (addNewLineBeforeArrowInWhenEntry) {
emit(
prevNode.startOffset + prevNode.textLength,
"Missing trailing comma and newline before \"${inspectNode.text}\"",
true
)
} else {
emit(
prevNode.startOffset + prevNode.textLength,
"Missing trailing comma before \"${inspectNode.text}\"",
true
)
}
if (autoCorrect) {
if (addNewLineBeforeArrowInWhenEntry) {
val parentIndent = (prevNode.psi.parent.prevLeaf() as? PsiWhiteSpace)?.text ?: "\n"
val leafBeforeArrow = (psi as KtWhenEntry).arrow?.prevLeaf()
if (leafBeforeArrow != null && leafBeforeArrow is PsiWhiteSpace) {
val newLine = KtPsiFactory(prevNode.psi).createWhiteSpace(parentIndent)
leafBeforeArrow.replace(newLine)
} else {
val newLine = KtPsiFactory(prevNode.psi).createWhiteSpace(parentIndent)
prevNode.psi.parent.addAfter(newLine, prevNode.psi)
}
}
val comma = KtPsiFactory(prevNode.psi).createComma()
prevNode.psi.parent.addAfter(comma, prevNode.psi)
}
}
TrailingCommaState.REDUNDANT -> {
emit(
trailingCommaNode!!.startOffset,
"Unnecessary trailing comma before \"${inspectNode.text}\"",
true
)
if (autoCorrect) {
this.removeChild(trailingCommaNode)
}
}
TrailingCommaState.NOT_EXISTS -> Unit
}
}

private enum class TrailingCommaState {
/**
* The trailing comma is needed and exists
*/
EXISTS,

/**
* The trailing comma is needed and doesn't exist
*/
MISSING,

/**
* The trailing comma isn't needed and doesn't exist
*/
NOT_EXISTS,

/**
* The trailing comma isn't needed, but exists
*/
REDUNDANT,
;
}

private fun isMultiline(element: PsiElement): Boolean = when {
element.parent is KtFunctionLiteral -> isMultiline(element.parent)
element is KtFunctionLiteral -> containsLineBreakInRange(element.valueParameterList!!, element.arrow!!)
element is KtWhenEntry -> containsLineBreakInRange(element.firstChild, element.arrow!!)
element is KtDestructuringDeclaration -> containsLineBreakInRange(element.lPar!!, element.rPar!!)
element is KtValueArgumentList && element.children.size == 1 && element.anyDescendantOfType<KtCollectionLiteralExpression>() -> {
// special handling for collection literal
// @Annotation([
// "something",
// ])
val lastChild = element.collectDescendantsOfType<KtCollectionLiteralExpression>().last()
containsLineBreakInLeafsRange(lastChild.rightBracket!!, element.rightParenthesis!!)
}
else -> element.textContains('\n')
}

private fun ASTNode.addNewLineBeforeArrowInWhen() =
if (psi is KtWhenEntry) {
val leafBeforeArrow = (psi as KtWhenEntry).arrow?.prevLeaf()
!(leafBeforeArrow is PsiWhiteSpace && leafBeforeArrow.textContains('\n'))
} else {
false
}

private fun ASTNode?.findPreviousTrailingCommaNodeOrNull(): ASTNode? {
var node = this
while (node?.isIgnorable() == true) {
node = node.prevLeaf()
}
return if (node?.elementType == ElementType.COMMA) {
node
} else {
null
}
}

private fun containsLineBreakInLeafsRange(from: PsiElement, to: PsiElement): Boolean {
var leaf: PsiElement? = from
while (leaf != null && !leaf.isEquivalentTo(to)) {
if (leaf.textContains('\n')) {
return true
}
leaf = leaf.nextLeaf(skipEmptyElements = false)
}
return leaf?.textContains('\n') ?: false
}

private fun ASTNode.isIgnorable(): Boolean =
elementType == ElementType.WHITE_SPACE ||
elementType == ElementType.EOL_COMMENT ||
elementType == ElementType.BLOCK_COMMENT

public companion object {

internal const val ALLOW_TRAILING_COMMA_NAME = "ij_kotlin_allow_trailing_comma"
Expand Down Expand Up @@ -189,3 +346,26 @@ public class TrailingCommaOnDeclarationSiteRule :
)
}
}

private enum class TrailingCommaState {
/**
* The trailing comma is needed and exists
*/
EXISTS,

/**
* The trailing comma is needed and doesn't exist
*/
MISSING,

/**
* The trailing comma isn't needed and doesn't exist
*/
NOT_EXISTS,

/**
* The trailing comma isn't needed, but exists
*/
REDUNDANT,
;
}

0 comments on commit 4ad78f2

Please sign in to comment.