Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly format expressions wrapped *before* a binary operator #1486

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class KdocMethods(configRules: List<RulesConfig>) : DiktatRule(
val isReferenceExpressionWithSameName = node.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION).map { it.text }.contains((node.psi as KtFunction).name)
val hasReturnKdoc = kdocTags != null && kdocTags.hasKnownKdocTag(KDocKnownTag.RETURN)
return (hasExplicitNotUnitReturnType || isFunWithExpressionBody && !hasExplicitUnitReturnType && hasNotExpressionBodyTypes)
&& !hasReturnKdoc && !isReferenceExpressionWithSameName
&& !hasReturnKdoc && !isReferenceExpressionWithSameName
}

private fun getExplicitlyThrownExceptions(node: ASTNode): Set<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class SmartCastRule(configRules: List<RulesConfig>) : DiktatRule(
val list: MutableList<KtNameReferenceExpression> = mutableListOf()
asExpr.forEach { asCall ->
if (asCall.node.findParentNodeWithSpecificType(IF)
== it.node.findParentNodeWithSpecificType(IF)) {
== it.node.findParentNodeWithSpecificType(IF)) {
list.add(asCall)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ private fun ASTNode.hasExplicitIt(): Boolean {
val parameterList = findChildByType(ElementType.FUNCTION_LITERAL)
?.findChildByType(ElementType.VALUE_PARAMETER_LIST)
?.psi
as KtParameterList?
as KtParameterList?
return parameterList?.parameters
?.any { it.name == "it" }
?: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.pinterest.ktlint.core.ast.ElementType.ARROW
import com.pinterest.ktlint.core.ast.ElementType.AS_KEYWORD
import com.pinterest.ktlint.core.ast.ElementType.AS_SAFE
import com.pinterest.ktlint.core.ast.ElementType.BINARY_EXPRESSION
import com.pinterest.ktlint.core.ast.ElementType.BINARY_WITH_TYPE
import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT
import com.pinterest.ktlint.core.ast.ElementType.BODY
import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION
Expand All @@ -39,6 +40,7 @@ import com.pinterest.ktlint.core.ast.ElementType.VALUE_ARGUMENT_LIST
import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER
import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER_LIST
import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE
import com.pinterest.ktlint.core.ast.children
import com.pinterest.ktlint.core.ast.nextCodeSibling
import com.pinterest.ktlint.core.ast.prevSibling
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
Expand Down Expand Up @@ -138,7 +140,17 @@ internal class ValueParameterListChecker(configuration: IndentationConfig) : Cus
internal class ExpressionIndentationChecker(configuration: IndentationConfig) : CustomIndentationChecker(configuration) {
override fun checkNode(whiteSpace: PsiWhiteSpace, indentError: IndentationError): CheckResult? =
when {
whiteSpace.parent.node.elementType == BINARY_EXPRESSION && whiteSpace.prevSibling.node.elementType == OPERATION_REFERENCE -> {
whiteSpace.parent.node.elementType in sequenceOf(BINARY_EXPRESSION, BINARY_WITH_TYPE) &&
whiteSpace.immediateSiblings().any { sibling ->
/*
* We're looking for an operation reference, including
* `as` and `as?` (`AS_SAFE`), but excluding `?:` (`ELVIS`),
* because there's a separate flag for Elvis expressions
* in IDEA (`CONTINUATION_INDENT_IN_ELVIS`).
*/
sibling.node.elementType == OPERATION_REFERENCE &&
sibling.node.children().firstOrNull()?.elementType != ELVIS
} -> {
val parentIndent = whiteSpace.parentIndent() ?: indentError.expected
val expectedIndent = parentIndent + IndentationAmount.valueOf(configuration.extendedIndentAfterOperators)
CheckResult.from(indentError.actual, expectedIndent, true)
Expand Down Expand Up @@ -308,3 +320,10 @@ internal fun PsiElement.parentIndent(): Int? = parentsWithSelf
.firstOrNull()
?.text
?.lastIndent()

/**
* @return the sequence of immediate siblings (the previous and the next one),
* excluding `null`'s.
*/
private fun PsiElement.immediateSiblings(): Sequence<PsiElement> =
sequenceOf(prevSibling, nextSibling).filterNotNull()
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestMixin.withCust
import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.dotQualifiedExpressions
import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.expressionBodyFunctions
import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.expressionsWrappedAfterOperator
import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.expressionsWrappedBeforeOperator
import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.parenthesesSurroundedInfixExpressions
import org.cqfn.diktat.ruleset.chapter3.spaces.IndentationRuleTestResources.whitespaceInStringLiterals
import org.cqfn.diktat.ruleset.constants.Warnings.WRONG_INDENTATION
Expand Down Expand Up @@ -225,6 +226,40 @@ class IndentationRuleFixTest : FixTestBase("test/paragraph3/indentation",
}
}

/**
* See [#1340](https://github.com/saveourtool/diktat/issues/1340).
*/
@Nested
@TestMethodOrder(DisplayName::class)
inner class `Expressions wrapped before operator` {
@ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}")
@ValueSource(booleans = [false, true])
@Tag(WarningNames.WRONG_INDENTATION)
fun `should be properly indented`(extendedIndentAfterOperators: Boolean, @TempDir tempDir: Path) {
val defaultConfig = IndentationConfig(NEWLINE_AT_END to false)
val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators)

lintMultipleMethods(
expressionsWrappedBeforeOperator[extendedIndentAfterOperators].assertNotNull(),
tempDir = tempDir,
rulesConfigList = customConfig.asRulesConfigList())
}

@ParameterizedTest(name = "$EXTENDED_INDENT_AFTER_OPERATORS = {0}")
@ValueSource(booleans = [false, true])
@Tag(WarningNames.WRONG_INDENTATION)
fun `should be reformatted if mis-indented`(extendedIndentAfterOperators: Boolean, @TempDir tempDir: Path) {
val defaultConfig = IndentationConfig(NEWLINE_AT_END to false)
val customConfig = defaultConfig.withCustomParameters(EXTENDED_INDENT_AFTER_OPERATORS to extendedIndentAfterOperators)

lintMultipleMethods(
actualContent = expressionsWrappedBeforeOperator[!extendedIndentAfterOperators].assertNotNull(),
expectedContent = expressionsWrappedBeforeOperator[extendedIndentAfterOperators].assertNotNull(),
tempDir = tempDir,
rulesConfigList = customConfig.asRulesConfigList())
}
}

/**
* See [#1409](https://github.com/saveourtool/diktat/issues/1409).
*/
Expand Down
Loading