Move TrailingComma* to separate module

This commit is contained in:
Dmitry Gridin
2020-05-22 13:01:33 +07:00
parent 64bcd32661
commit bb329c0415
11 changed files with 124 additions and 112 deletions
@@ -19,6 +19,8 @@ import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.idea.formatter.NodeIndentStrategy.Companion.strategy
import org.jetbrains.kotlin.idea.formatter.trailingComma.addTrailingCommaIsAllowedFor
import org.jetbrains.kotlin.idea.formatter.trailingComma.needTrailingComma
import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.kdoc.lexer.KDocTokens
import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes
@@ -3,13 +3,14 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
package org.jetbrains.kotlin.idea.formatter.trailingComma
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.tree.TokenSet
import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -3,10 +3,9 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
package org.jetbrains.kotlin.idea.formatter.trailingComma
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.util.canAddTrailingComma
import org.jetbrains.kotlin.idea.util.containsLineBreakInThis
import org.jetbrains.kotlin.idea.util.isMultiline
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
@@ -0,0 +1,110 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter.trailingComma
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.UserDataHolder
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiElement
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import com.intellij.psi.util.PsiUtilCore
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.idea.util.containsLineBreakInThis
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.utils.addToStdlib.cast
fun KtFunctionLiteral.needTrailingComma(settings: CodeStyleSettings?, checkExistingTrailingComma: Boolean = true): Boolean =
needTrailingComma(
settings = settings,
trailingComma = { if (checkExistingTrailingComma) valueParameterList?.trailingComma else null },
globalStartOffset = { valueParameterList?.startOffset },
globalEndOffset = { arrow?.endOffset },
)
fun KtWhenEntry.needTrailingComma(settings: CodeStyleSettings?, checkExistingTrailingComma: Boolean = true): Boolean = needTrailingComma(
settings = settings,
trailingComma = { if (checkExistingTrailingComma) trailingComma else null },
additionalCheck = { !isElse && parent.cast<KtWhenExpression>().leftParenthesis != null },
globalEndOffset = { arrow?.endOffset },
)
fun KtDestructuringDeclaration.needTrailingComma(settings: CodeStyleSettings?, checkExistingTrailingComma: Boolean = true): Boolean =
needTrailingComma(
settings = settings,
trailingComma = { if (checkExistingTrailingComma) trailingComma else null },
globalStartOffset = { lPar?.startOffset },
globalEndOffset = { rPar?.endOffset },
)
private fun <T : PsiElement> T.needTrailingComma(
settings: CodeStyleSettings?,
trailingComma: T.() -> PsiElement?,
additionalCheck: () -> Boolean = { true },
globalStartOffset: T.() -> Int? = PsiElement::startOffset,
globalEndOffset: T.() -> Int? = PsiElement::endOffset,
): Boolean {
if (trailingComma() == null && settings?.kotlinCustomSettings?.addTrailingCommaIsAllowedFor(this) == false) return false
if (!additionalCheck()) return false
val startOffset = globalStartOffset() ?: return false
val endOffset = globalEndOffset() ?: return false
return containsLineBreakInThis(startOffset, endOffset)
}
fun trailingCommaIsAllowedOnCallSite(): Boolean = Registry.`is`("kotlin.formatter.allowTrailingCommaOnCallSite")
private val TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE = TokenSet.create(
KtNodeTypes.TYPE_PARAMETER_LIST,
KtNodeTypes.DESTRUCTURING_DECLARATION,
KtNodeTypes.WHEN_ENTRY,
KtNodeTypes.FUNCTION_LITERAL,
KtNodeTypes.VALUE_PARAMETER_LIST,
)
private val TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE = TokenSet.create(
KtNodeTypes.COLLECTION_LITERAL_EXPRESSION,
KtNodeTypes.TYPE_ARGUMENT_LIST,
KtNodeTypes.INDICES,
KtNodeTypes.VALUE_ARGUMENT_LIST,
)
private val TYPES_WITH_TRAILING_COMMA = TokenSet.orSet(
TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE,
TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE,
)
fun UserDataHolder.addTrailingCommaIsAllowedForThis(): Boolean {
val type = elementType(this) ?: return false
return type in TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE ||
trailingCommaIsAllowedOnCallSite() && type in TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE
}
fun KotlinCodeStyleSettings.addTrailingCommaIsAllowedFor(element: UserDataHolder): Boolean =
ALLOW_TRAILING_COMMA && element.addTrailingCommaIsAllowedForThis()
private fun elementType(userDataHolder: UserDataHolder): IElementType? = when (userDataHolder) {
is ASTNode -> PsiUtilCore.getElementType(userDataHolder)
is PsiElement -> PsiUtilCore.getElementType(userDataHolder)
else -> null
}
fun ASTNode.canAddTrailingComma(): Boolean = psi?.canAddTrailingComma() == true
fun PsiElement.canAddTrailingComma(): Boolean =
if (this is KtWhenEntry && (isElse || parent.cast<KtWhenExpression>().leftParenthesis == null))
false
else
canAddTrailingComma(this)
private fun canAddTrailingComma(userDataHolder: UserDataHolder): Boolean = elementType(userDataHolder) in TYPES_WITH_TRAILING_COMMA
@@ -6,33 +6,18 @@
package org.jetbrains.kotlin.idea.util
import com.intellij.formatting.ASTBlock
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.UserDataHolder
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import com.intellij.psi.util.PsiUtil
import com.intellij.psi.util.PsiUtilCore
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.nextLeaf
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.utils.addToStdlib.cast
/*
* ASTBlock.node is nullable, this extension was introduced to minimize changes
@@ -76,92 +61,7 @@ fun PsiElement.leaf(forward: Boolean = true, filter: (PsiElement) -> Boolean): P
val PsiElement.isComma: Boolean get() = PsiUtil.getElementType(this) == KtTokens.COMMA
fun KtFunctionLiteral.needTrailingComma(settings: CodeStyleSettings?, checkExistingTrailingComma: Boolean = true): Boolean =
needTrailingComma(
settings = settings,
trailingComma = { if (checkExistingTrailingComma) valueParameterList?.trailingComma else null },
globalStartOffset = { valueParameterList?.startOffset },
globalEndOffset = { arrow?.endOffset },
)
fun KtWhenEntry.needTrailingComma(settings: CodeStyleSettings?, checkExistingTrailingComma: Boolean = true): Boolean = needTrailingComma(
settings = settings,
trailingComma = { if (checkExistingTrailingComma) trailingComma else null },
additionalCheck = { !isElse && parent.cast<KtWhenExpression>().leftParenthesis != null },
globalEndOffset = { arrow?.endOffset },
)
fun KtDestructuringDeclaration.needTrailingComma(settings: CodeStyleSettings?, checkExistingTrailingComma: Boolean = true): Boolean =
needTrailingComma(
settings = settings,
trailingComma = { if (checkExistingTrailingComma) trailingComma else null },
globalStartOffset = { lPar?.startOffset },
globalEndOffset = { rPar?.endOffset },
)
private fun <T : PsiElement> T.needTrailingComma(
settings: CodeStyleSettings?,
trailingComma: T.() -> PsiElement?,
additionalCheck: () -> Boolean = { true },
globalStartOffset: T.() -> Int? = PsiElement::startOffset,
globalEndOffset: T.() -> Int? = PsiElement::endOffset,
): Boolean {
if (trailingComma() == null && settings?.kotlinCustomSettings?.addTrailingCommaIsAllowedFor(this) == false) return false
if (!additionalCheck()) return false
val startOffset = globalStartOffset() ?: return false
val endOffset = globalEndOffset() ?: return false
return containsLineBreakInThis(startOffset, endOffset)
}
fun PsiElement.containsLineBreakInThis(globalStartOffset: Int, globalEndOffset: Int): Boolean {
val textRange = TextRange.create(globalStartOffset, globalEndOffset).shiftLeft(startOffset)
return StringUtil.containsLineBreak(textRange.subSequence(text))
}
fun trailingCommaIsAllowedOnCallSite(): Boolean = Registry.`is`("kotlin.formatter.allowTrailingCommaOnCallSite")
private val TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE = TokenSet.create(
KtNodeTypes.TYPE_PARAMETER_LIST,
KtNodeTypes.DESTRUCTURING_DECLARATION,
KtNodeTypes.WHEN_ENTRY,
KtNodeTypes.FUNCTION_LITERAL,
KtNodeTypes.VALUE_PARAMETER_LIST,
)
private val TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE = TokenSet.create(
KtNodeTypes.COLLECTION_LITERAL_EXPRESSION,
KtNodeTypes.TYPE_ARGUMENT_LIST,
KtNodeTypes.INDICES,
KtNodeTypes.VALUE_ARGUMENT_LIST,
)
private val TYPES_WITH_TRAILING_COMMA = TokenSet.orSet(
TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE,
TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE,
)
fun UserDataHolder.addTrailingCommaIsAllowedForThis(): Boolean {
val type = elementType(this) ?: return false
return type in TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE ||
trailingCommaIsAllowedOnCallSite() && type in TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE
}
fun KotlinCodeStyleSettings.addTrailingCommaIsAllowedFor(element: UserDataHolder): Boolean =
ALLOW_TRAILING_COMMA && element.addTrailingCommaIsAllowedForThis()
private fun elementType(userDataHolder: UserDataHolder): IElementType? = when (userDataHolder) {
is ASTNode -> PsiUtilCore.getElementType(userDataHolder)
is PsiElement -> PsiUtilCore.getElementType(userDataHolder)
else -> null
}
fun ASTNode.canAddTrailingComma(): Boolean = psi?.canAddTrailingComma() == true
fun PsiElement.canAddTrailingComma(): Boolean =
if (this is KtWhenEntry && (isElse || parent.cast<KtWhenExpression>().leftParenthesis == null))
false
else
canAddTrailingComma(this)
private fun canAddTrailingComma(userDataHolder: UserDataHolder): Boolean = elementType(userDataHolder) in TYPES_WITH_TRAILING_COMMA
@@ -11,7 +11,7 @@ import com.intellij.openapi.editor.Editor
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.core.util.isMultiLine
import org.jetbrains.kotlin.idea.formatter.TrailingCommaHelper
import org.jetbrains.kotlin.idea.formatter.trailingComma.TrailingCommaHelper
import org.jetbrains.kotlin.idea.util.isComma
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -17,9 +17,9 @@ import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.impl.source.codeStyle.PostFormatProcessor
import com.intellij.psi.impl.source.codeStyle.PostFormatProcessorHelper
import com.intellij.psi.util.PsiUtil.getElementType
import org.jetbrains.kotlin.idea.formatter.TrailingCommaHelper.findInvalidCommas
import org.jetbrains.kotlin.idea.formatter.TrailingCommaHelper.needComma
import org.jetbrains.kotlin.idea.formatter.TrailingCommaHelper.trailingCommaOrLastElement
import org.jetbrains.kotlin.idea.formatter.trailingComma.TrailingCommaHelper.findInvalidCommas
import org.jetbrains.kotlin.idea.formatter.trailingComma.TrailingCommaHelper.needComma
import org.jetbrains.kotlin.idea.formatter.trailingComma.TrailingCommaHelper.trailingCommaOrLastElement
import org.jetbrains.kotlin.idea.util.leafIgnoringWhitespace
import org.jetbrains.kotlin.idea.util.leafIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.lexer.KtTokens
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.formatter
import com.intellij.openapi.progress.ProgressIndicatorProvider
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.util.addTrailingCommaIsAllowedForThis
import org.jetbrains.kotlin.idea.formatter.trailingComma.addTrailingCommaIsAllowedForThis
import org.jetbrains.kotlin.psi.*
abstract class TrailingCommaVisitor : KtTreeVisitorVoid() {
@@ -18,7 +18,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.formatter.TrailingCommaHelper
import org.jetbrains.kotlin.idea.formatter.trailingComma.TrailingCommaHelper
import org.jetbrains.kotlin.idea.formatter.TrailingCommaVisitor
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.idea.formatter.trailingCommaAllowedInModule
@@ -10,7 +10,7 @@ import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.idea.util.addTrailingCommaIsAllowedForThis
import org.jetbrains.kotlin.idea.formatter.trailingComma.addTrailingCommaIsAllowedForThis
import org.jetbrains.kotlin.psi.KtElement
class TrailingCommaIntention : SelfTargetingIntention<KtElement>(
@@ -11,8 +11,8 @@ import com.intellij.openapi.editor.Document
import com.intellij.psi.PsiFile
import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.idea.core.util.containsLineBreakInRange
import org.jetbrains.kotlin.idea.formatter.TrailingCommaHelper
import org.jetbrains.kotlin.idea.util.addTrailingCommaIsAllowedForThis
import org.jetbrains.kotlin.idea.formatter.trailingComma.TrailingCommaHelper
import org.jetbrains.kotlin.idea.formatter.trailingComma.addTrailingCommaIsAllowedForThis
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf