From 4a13e39e5aa85728ca0e62bbe38203d578c5e58f Mon Sep 17 00:00:00 2001 From: Alexey Votintsev <79669665+Arrgentum@users.noreply.github.com> Date: Mon, 16 May 2022 16:32:11 +0300 Subject: [PATCH] Fix logic "BinaryExpression" in "LineLength" Rule (#1292) ### What's done: * Fixed logic and tests for binary expression in rule "LineLength" * Added tests for LineLength rule (#1292) Co-authored-by: Andrey Kuleshov --- .../ruleset/rules/chapter1/PackageNaming.kt | 1 + .../ruleset/rules/chapter3/LineLength.kt | 487 +++++++++--------- .../ruleset/chapter3/LineLengthFixTest.kt | 14 + .../long_line/LongBinaryExpressionExpected.kt | 43 +- .../long_line/LongBinaryExpressionTest.kt | 6 + .../LongConditionInSmallFunctionExpected.kt | 5 + .../LongConditionInSmallFunctionTest.kt | 4 + .../LongExpressionInConditionExpected.kt | 18 + .../LongExpressionInConditionTest.kt | 15 + .../long_line/LongLineCommentExpected2.kt | 11 +- .../long_line/LongLineExpressionExpected.kt | 5 +- .../long_line/LongLineExpressionTest.kt | 1 + .../long_line/LongLineRValueExpected.kt | 31 +- .../long_line/LongLineRValueTest.kt | 8 +- .../long_line/LongStringTemplateExpected.kt | 13 +- 15 files changed, 391 insertions(+), 271 deletions(-) create mode 100644 diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionExpected.kt create mode 100644 diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionTest.kt create mode 100644 diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionExpected.kt create mode 100644 diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionTest.kt diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt index 49c99c4288..874ccc08af 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/PackageNaming.kt @@ -10,6 +10,7 @@ import org.cqfn.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_PREFIX import org.cqfn.diktat.ruleset.constants.Warnings.PACKAGE_NAME_INCORRECT_SYMBOLS import org.cqfn.diktat.ruleset.constants.Warnings.PACKAGE_NAME_MISSING import org.cqfn.diktat.ruleset.rules.DiktatRule + import org.cqfn.diktat.ruleset.utils.* import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/LineLength.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/LineLength.kt index 5bfd51aaa5..04469c307e 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/LineLength.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/LineLength.kt @@ -5,54 +5,56 @@ import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.common.config.rules.getRuleConfig import org.cqfn.diktat.ruleset.constants.Warnings.LONG_LINE import org.cqfn.diktat.ruleset.rules.DiktatRule -import org.cqfn.diktat.ruleset.utils.KotlinParser -import org.cqfn.diktat.ruleset.utils.appendNewlineMergingWhiteSpace -import org.cqfn.diktat.ruleset.utils.calculateLineColByOffset -import org.cqfn.diktat.ruleset.utils.findAllNodesWithConditionOnLine -import org.cqfn.diktat.ruleset.utils.findParentNodeWithSpecificType -import org.cqfn.diktat.ruleset.utils.getLineNumber -import org.cqfn.diktat.ruleset.utils.hasChildOfType +import org.cqfn.diktat.ruleset.utils.* +import com.pinterest.ktlint.core.ast.ElementType.ANDAND import com.pinterest.ktlint.core.ast.ElementType.ANNOTATION_ENTRY import com.pinterest.ktlint.core.ast.ElementType.BINARY_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.BOOLEAN_CONSTANT -import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.CHARACTER_CONSTANT import com.pinterest.ktlint.core.ast.ElementType.CONDITION +import com.pinterest.ktlint.core.ast.ElementType.ELVIS import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT import com.pinterest.ktlint.core.ast.ElementType.EQ +import com.pinterest.ktlint.core.ast.ElementType.EQEQ +import com.pinterest.ktlint.core.ast.ElementType.EXCL +import com.pinterest.ktlint.core.ast.ElementType.EXCLEQ import com.pinterest.ktlint.core.ast.ElementType.FILE import com.pinterest.ktlint.core.ast.ElementType.FLOAT_CONSTANT import com.pinterest.ktlint.core.ast.ElementType.FUN +import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_LITERAL +import com.pinterest.ktlint.core.ast.ElementType.GT +import com.pinterest.ktlint.core.ast.ElementType.GTEQ import com.pinterest.ktlint.core.ast.ElementType.IF import com.pinterest.ktlint.core.ast.ElementType.IMPORT_LIST import com.pinterest.ktlint.core.ast.ElementType.INTEGER_CONSTANT import com.pinterest.ktlint.core.ast.ElementType.KDOC_MARKDOWN_INLINE_LINK import com.pinterest.ktlint.core.ast.ElementType.KDOC_TEXT +import com.pinterest.ktlint.core.ast.ElementType.LBRACE import com.pinterest.ktlint.core.ast.ElementType.LITERAL_STRING_TEMPLATE_ENTRY import com.pinterest.ktlint.core.ast.ElementType.LONG_STRING_TEMPLATE_ENTRY -import com.pinterest.ktlint.core.ast.ElementType.LPAR +import com.pinterest.ktlint.core.ast.ElementType.LT +import com.pinterest.ktlint.core.ast.ElementType.LTEQ import com.pinterest.ktlint.core.ast.ElementType.NULL import com.pinterest.ktlint.core.ast.ElementType.OPERATION_REFERENCE +import com.pinterest.ktlint.core.ast.ElementType.OROR import com.pinterest.ktlint.core.ast.ElementType.PACKAGE_DIRECTIVE import com.pinterest.ktlint.core.ast.ElementType.PARENTHESIZED import com.pinterest.ktlint.core.ast.ElementType.POSTFIX_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.PREFIX_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.PROPERTY +import com.pinterest.ktlint.core.ast.ElementType.RBRACE import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION -import com.pinterest.ktlint.core.ast.ElementType.RPAR import com.pinterest.ktlint.core.ast.ElementType.SHORT_STRING_TEMPLATE_ENTRY import com.pinterest.ktlint.core.ast.ElementType.STRING_TEMPLATE import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE import com.pinterest.ktlint.core.ast.isWhiteSpace import com.pinterest.ktlint.core.ast.isWhiteSpaceWithNewline -import com.pinterest.ktlint.core.ast.nextSibling -import com.pinterest.ktlint.core.ast.parent -import com.pinterest.ktlint.core.ast.prevSibling import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl +import org.jetbrains.kotlin.com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.psi.psiUtil.parents import java.net.MalformedURLException @@ -85,20 +87,21 @@ class LineLength(configRules: List) : DiktatRule( } } } - - @Suppress("UnsafeCallOnNullableType") + @Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION") private fun checkLength(node: ASTNode, configuration: LineLengthConfiguration) { var offset = 0 node.text.lines().forEach { line -> if (line.length > configuration.lineLength) { val newNode = node.psi.findElementAt(offset + configuration.lineLength.toInt() - 1)!!.node if ((newNode.elementType != KDOC_TEXT && newNode.elementType != KDOC_MARKDOWN_INLINE_LINK) || - !isKdocValid(newNode)) { + !isKdocValid(newNode) + ) { positionByOffset = node.treeParent.calculateLineColByOffset() val fixableType = isFixable(newNode, configuration) LONG_LINE.warnAndFix(configRules, emitWarn, isFixMode, "max line length ${configuration.lineLength}, but was ${line.length}", - offset + node.startOffset, node, fixableType != LongLineFixableCases.None) { + offset + node.startOffset, node, fixableType !is None + ) { // we should keep in mind, that in the course of fixing we change the offset val textLenBeforeFix = node.textLength fixError(fixableType) @@ -112,14 +115,29 @@ class LineLength(configRules: List) : DiktatRule( } } + @Suppress( + "TOO_LONG_FUNCTION", + "ComplexMethod", + ) private fun isFixable(wrongNode: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases { var parent = wrongNode do { when (parent.elementType) { - FUN -> return checkFun(parent) + BINARY_EXPRESSION, PARENTHESIZED -> { + val splitOffset = searchRightSplitInBinaryExpression(parent, configuration)?.second + splitOffset?.let { + if (isConditionToUpAnalysisBinExpression(parent, splitOffset)) { + parent = parent.treeParent + } else { + return checkBinaryExpression(parent, configuration) + } + } + ?: run { parent = parent.treeParent } + } + FUN, PROPERTY -> return checkFunAndProperty(parent) CONDITION -> return checkCondition(parent, configuration) - PROPERTY -> return checkProperty(parent, configuration) EOL_COMMENT -> return checkComment(parent, configuration) + FUNCTION_LITERAL -> return Lambda(parent) STRING_TEMPLATE -> { // as we are going from bottom to top we are excluding // 1. IF, because it seems that string template is in condition @@ -138,7 +156,30 @@ class LineLength(configRules: List) : DiktatRule( else -> parent = parent.treeParent } } while (parent.treeParent != null) - return LongLineFixableCases.None + return None() + } + + /** + * Analyzes the Binary expression and decides to go higher level with the analysis or analyze at this level + */ + private fun isConditionToUpAnalysisBinExpression(parent: ASTNode, offset: Int): Boolean { + val parentIsBiExprOrParenthesized = parent.treeParent.elementType in listOf(BINARY_EXPRESSION, PARENTHESIZED) + val parentIsFunctionLiteral = parent.treeParent.treeParent.elementType == FUNCTION_LITERAL + val parentIsFunOrProperty = parent.treeParent.elementType in listOf(FUN, PROPERTY) + return (parentIsBiExprOrParenthesized || parentIsFunctionLiteral || (parentIsFunOrProperty && offset >= configuration.lineLength)) + } + + /** + * Parses the existing binary expression and passes the necessary parameters to the fix function for splitting + */ + private fun checkBinaryExpression(node: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases { + val leftOffset = positionByOffset(node.firstChildNode.startOffset).second + val binList: MutableList = mutableListOf() + searchBinaryExpression(node, binList) + if (binList.size == 1) { + return BinaryExpression(node) + } + return LongBinaryExpression(node, configuration, leftOffset, binList) } /** @@ -148,7 +189,7 @@ class LineLength(configRules: List) : DiktatRule( * BinaryExpression - if there is two concatenated strings and new line should be inserted after `+` * None - if the string can't be split */ - @Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION") + @Suppress("TOO_LONG_FUNCTION", "UnsafeCallOnNullableType") private fun checkStringTemplate(node: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases { var multiLineOffset = 0 val leftOffset = if (node.text.lines().size > 1) { @@ -171,16 +212,16 @@ class LineLength(configRules: List) : DiktatRule( // we can't split this string, however may be we can move it entirely: // case when new line should be inserted after `+`. Example: "first" + "second" node.treeParent.findChildByType(OPERATION_REFERENCE)?.let { - return LongLineFixableCases.BinaryExpression(node.treeParent) + return BinaryExpression(node.treeParent) } // can't fix this case - return LongLineFixableCases.None + return None() } // check, that space to split is a part of text - not code // If the space split is part of the code, then there is a chance of breaking the code when fixing, that why we should ignore it val isSpaceIsWhiteSpace = node.psi.findElementAt(delimiterIndex)!!.node.isWhiteSpace() if (isSpaceIsWhiteSpace) { - return LongLineFixableCases.None + return None() } // minus 2 here as we are inserting ` +` and we don't want it to exceed line length val shouldAddTwoSpaces = (multiLineOffset == 0) && (leftOffset + delimiterIndex > configuration.lineLength.toInt() - 2) @@ -190,26 +231,26 @@ class LineLength(configRules: List) : DiktatRule( delimiterIndex } if (correcterDelimiter == -1) { - return LongLineFixableCases.None + return None() } - return LongLineFixableCases.StringTemplate(node, correcterDelimiter, multiLineOffset == 0) + return StringTemplate(node, correcterDelimiter, multiLineOffset == 0) } - private fun checkFun(wrongNode: ASTNode) = - if (wrongNode.hasChildOfType(EQ)) LongLineFixableCases.Fun(wrongNode) else LongLineFixableCases.None + private fun checkFunAndProperty(wrongNode: ASTNode) = + if (wrongNode.hasChildOfType(EQ)) FunAndProperty(wrongNode) else None() private fun checkComment(wrongNode: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases { val leftOffset = positionByOffset(wrongNode.startOffset).second val stringBeforeCommentContent = wrongNode.text.takeWhile { it == ' ' || it == '/' } if (stringBeforeCommentContent.length >= configuration.lineLength.toInt() - leftOffset) { - return LongLineFixableCases.None + return None() } val indexLastSpace = wrongNode.text.substring(stringBeforeCommentContent.length, configuration.lineLength.toInt() - leftOffset).lastIndexOf(' ') val isNewLine = wrongNode.treePrev?.isWhiteSpaceWithNewline() ?: wrongNode.treeParent?.treePrev?.isWhiteSpaceWithNewline() ?: false if (isNewLine && indexLastSpace == -1) { - return LongLineFixableCases.None + return None() } - return LongLineFixableCases.Comment(wrongNode, isNewLine, indexLastSpace + stringBeforeCommentContent.length) + return Comment(wrongNode, isNewLine, indexLastSpace + stringBeforeCommentContent.length) } private fun checkCondition(wrongNode: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases { @@ -217,42 +258,9 @@ class LineLength(configRules: List) : DiktatRule( val binList: MutableList = mutableListOf() searchBinaryExpression(wrongNode, binList) if (binList.size == 1) { - return LongLineFixableCases.None - } - return LongLineFixableCases.Condition(configuration.lineLength, leftOffset, binList) - } - - @Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION") - private fun checkProperty(wrongNode: ASTNode, configuration: LineLengthConfiguration): LongLineFixableCases { - var newParent = wrongNode - while (newParent.hasChildOfType(PARENTHESIZED)) { - newParent = wrongNode.findChildByType(PARENTHESIZED)!! - } - if (!newParent.hasChildOfType(STRING_TEMPLATE)) { - if (newParent.hasChildOfType(BINARY_EXPRESSION)) { - val leftOffset = positionByOffset(newParent.findChildByType(BINARY_EXPRESSION)!!.startOffset).second - val binList: MutableList = mutableListOf() - dfsForProperty(wrongNode, binList) - if (binList.size == 1) { - return LongLineFixableCases.None - } - return LongLineFixableCases.Condition(configuration.lineLength, leftOffset, binList) - } else { - return LongLineFixableCases.None - } - } else { - val leftOffset = positionByOffset(newParent.findChildByType(STRING_TEMPLATE)!!.startOffset).second - if (leftOffset > configuration.lineLength - STRING_PART_OFFSET) { - return LongLineFixableCases.None - } - val text = wrongNode.findChildByType(STRING_TEMPLATE)!!.text.trim('"') - val lastCharIndex = configuration.lineLength.toInt() - leftOffset - STRING_PART_OFFSET - val indexLastSpace = (text.substring(0, lastCharIndex).lastIndexOf(' ')) - if (indexLastSpace == -1) { - return LongLineFixableCases.None - } - return LongLineFixableCases.Property(wrongNode, indexLastSpace, text) + return BinaryExpression(wrongNode) } + return LongBinaryExpression(wrongNode, configuration, leftOffset, binList) } // fixme json method @@ -270,17 +278,17 @@ class LineLength(configRules: List) : DiktatRule( @Suppress("UnsafeCallOnNullableType", "WHEN_WITHOUT_ELSE") private fun fixError(fixableType: LongLineFixableCases) { when (fixableType) { - is LongLineFixableCases.Fun -> fixableType.node.appendNewlineMergingWhiteSpace(null, fixableType.node.findChildByType(EQ)!!.treeNext) - is LongLineFixableCases.Comment -> fixComment(fixableType) - is LongLineFixableCases.Condition -> fixLongBinaryExpression(fixableType) - is LongLineFixableCases.Property -> createSplitProperty(fixableType) - is LongLineFixableCases.StringTemplate -> fixStringTemplate(fixableType) - is LongLineFixableCases.BinaryExpression -> fixBinaryExpression(fixableType.node) - is LongLineFixableCases.None -> return + is FunAndProperty -> fixableType.node.appendNewlineMergingWhiteSpace(null, fixableType.node.findChildByType(EQ)!!.treeNext) + is Comment -> fixComment(fixableType) + is LongBinaryExpression -> fixLongBinaryExpression(fixableType) + is BinaryExpression -> fixBinaryExpression(fixableType.node) + is StringTemplate -> fixStringTemplate(fixableType) + is Lambda -> fixLambda(fixableType.node) + is None -> return } } - private fun fixComment(wrongComment: LongLineFixableCases.Comment) { + private fun fixComment(wrongComment: Comment) { val wrongNode = wrongComment.node if (wrongComment.hasNewLineBefore) { val indexLastSpace = wrongComment.indexLastSpace @@ -309,14 +317,37 @@ class LineLength(configRules: List) : DiktatRule( } } + /** + * Fix a binary expression - + * If the transfer is done on the Elvis operator, then transfers it to a new line + * If not on the Elvis operator, then transfers it to a new line after the operation reference + */ @Suppress("UnsafeCallOnNullableType") private fun fixBinaryExpression(node: ASTNode) { - val whiteSpaceAfterPlus = node.findChildByType(OPERATION_REFERENCE)!!.treeNext - node.replaceChild(whiteSpaceAfterPlus, PsiWhiteSpaceImpl("\n")) + val nodeOperationReference = node.findChildByType(OPERATION_REFERENCE) + val nextNode = if (nodeOperationReference!!.firstChildNode.elementType != ELVIS) { + nodeOperationReference.treeNext + } else { + if (nodeOperationReference.treePrev.elementType == WHITE_SPACE) { + nodeOperationReference.treePrev + } else { + nodeOperationReference + } + } + node.appendNewlineMergingWhiteSpace(nextNode, nextNode) + } + + /** + * Splits Lambda expressions - add splits lines, thereby making the lambda expression a separate line + */ + @Suppress("UnsafeCallOnNullableType") + private fun fixLambda(node: ASTNode) { + node.appendNewlineMergingWhiteSpace(node.findChildByType(LBRACE)!!.treeNext, node.findChildByType(LBRACE)!!.treeNext) + node.appendNewlineMergingWhiteSpace(node.findChildByType(RBRACE)!!.treePrev, node.findChildByType(RBRACE)!!.treePrev) } @Suppress("UnsafeCallOnNullableType", "COMMENT_WHITE_SPACE") - private fun fixStringTemplate(wrongStringTemplate: LongLineFixableCases.StringTemplate) { + private fun fixStringTemplate(wrongStringTemplate: StringTemplate) { val incorrectText = wrongStringTemplate.node.text val firstPart = incorrectText.substring(0, wrongStringTemplate.delimiterIndex) val secondPart = incorrectText.substring(wrongStringTemplate.delimiterIndex, incorrectText.length) @@ -331,95 +362,30 @@ class LineLength(configRules: List) : DiktatRule( } /** - * This method fix too long binary expression: split after OPERATION_REFERENCE closest to max length - * - * In this method we collect all binary expression in correct order and then - * we collect their if their length less then max. + * Finds where it is better to fix a Binary expression and fixes it */ @Suppress("UnsafeCallOnNullableType") - private fun fixLongBinaryExpression(wrongBinaryExpression: LongLineFixableCases.Condition) { - val leftOffset = wrongBinaryExpression.leftOffset - val binList = wrongBinaryExpression.binList - var binaryText = "" - binList.forEachIndexed { index, astNode -> - binaryText += findAllText(astNode) - if (leftOffset + binaryText.length > wrongBinaryExpression.maximumLineLength && index != 0) { - val commonParent = astNode.parent({ it.elementType == BINARY_EXPRESSION && it in binList[index - 1].parents() })!! - val nextNode = commonParent.findChildByType(OPERATION_REFERENCE)!!.treeNext - if (!nextNode.text.contains("\n")) { - commonParent.appendNewlineMergingWhiteSpace(nextNode, nextNode) + private fun fixLongBinaryExpression(wrongBinaryExpression: LongBinaryExpression) { + val anySplitNode = searchSomeSplitInBinaryExpression(wrongBinaryExpression.node, wrongBinaryExpression.maximumLineLength) + val rigthSplitnode = anySplitNode[0] ?: anySplitNode[1] ?: anySplitNode[2] + val nodeOperationReference = rigthSplitnode?.first?.getFirstChildWithType(OPERATION_REFERENCE) + rigthSplitnode?.let { + val nextNode = if (nodeOperationReference!!.firstChildNode.elementType != ELVIS) { + nodeOperationReference.treeNext + } else { + if (nodeOperationReference.treePrev.elementType == WHITE_SPACE) { + nodeOperationReference.treePrev + } else { + nodeOperationReference } - return } - } - } - - @Suppress("UnsafeCallOnNullableType") - private fun findAllText(astNode: ASTNode): String { - var text = "" - var node = astNode - var prevNode: ASTNode - do { - prevNode = node - node = node.treeParent - if (node.elementType == PARENTHESIZED) { - text += getTextFromParenthesized(node) - } - } while (node.elementType != BINARY_EXPRESSION) - - if (node.firstChildNode == prevNode) { - if (node.treePrev != null && node.treePrev.elementType == WHITE_SPACE) { - text += node.treePrev.text + if (!nextNode.text.contains(("\n"))) { + rigthSplitnode.first.appendNewlineMergingWhiteSpace(nextNode, nextNode) } - } else { - if (prevNode.treePrev != null && prevNode.treePrev.elementType == WHITE_SPACE) { - text += prevNode.treePrev.text - } - } - while (node.treeParent.elementType == PARENTHESIZED) { - node = node.treeParent - text += getBraceAndBeforeText(node, prevNode) - } - text += astNode.text - node = astNode.parent({ newNode -> newNode.nextSibling { it.elementType == OPERATION_REFERENCE } != null }, - strict = false) - ?: return text - node = node.nextSibling { it.elementType == OPERATION_REFERENCE }!! - if (node.treePrev.elementType == WHITE_SPACE) { - text += node.treePrev.text } - text += node.text - return text - } - - @Suppress("UnsafeCallOnNullableType") - private fun getBraceAndBeforeText(node: ASTNode, prevNode: ASTNode): String { - val par = prevNode.prevSibling { it.elementType == OPERATION_REFERENCE }?.let { LPAR } ?: RPAR - var text = "" - if (node.findChildByType(par)!!.treePrev != null && - node.findChildByType(par)!!.treePrev.elementType == WHITE_SPACE) { - text += node.findChildByType(par)!!.treePrev.text - } - text += node.findChildByType(par)!!.text - return text - } - - @Suppress("UnsafeCallOnNullableType") - private fun getTextFromParenthesized(node: ASTNode): String { - var text = "" - text += node.findChildByType(LPAR)!!.text - if (node.findChildByType(LPAR)!!.treeNext.elementType == WHITE_SPACE) { - text += node.findChildByType(LPAR)!!.treeNext.text - } - if (node.findChildByType(RPAR)!!.treePrev.elementType == WHITE_SPACE) { - text += node.findChildByType(RPAR)!!.treePrev.text - } - text += node.findChildByType(RPAR)!!.text - return text } /** - * This method stored all the nodes that have BINARY_EXPRESSION or PREFIX_EXPRESSION element type. * This method uses recursion to store binary node in the order in which they are located * Also binList contains nodes with PREFIX_EXPRESSION element type ( !isFoo(), !isValid) * @@ -437,52 +403,76 @@ class LineLength(configRules: List) : DiktatRule( .forEach { searchBinaryExpression(it, binList) } - } else { + } + if (node.elementType == BINARY_EXPRESSION) { binList.add(node) binList.add(node.treeParent.findChildByType(PREFIX_EXPRESSION) ?: return) } } /** - * Collect by Depth-first search (DFS) all children to the right side of the equal sign with specific type [propertyList], - * by which we can split expression. - * Such logic needed, because AST representation of complex conditions is quite loaded - * - * @param node target node to be processed - * @param binList where to store the corresponding results + * This method stored all the nodes that have BINARY_EXPRESSION or PREFIX_EXPRESSION element type. + * Return List of the Pair + * First elem in List - Logic Binary Expression (&& ||) + * Second elem in List - Comparison Binary Expression (> < == >= <= !=) + * Other types (Arithmetical and Bit operation) (+ - * / % >> << *= += -= /= %= ++ -- ! in !in etc) */ - private fun dfsForProperty(node: ASTNode, binList: MutableList) { - node.getChildren(null).forEach { - if (it.elementType in propertyList) { - if (it.elementType == REFERENCE_EXPRESSION && it.treeParent?.elementType == CALL_EXPRESSION) { - binList.add(it.treeParent) - } else { - binList.add(it) - } - } - dfsForProperty(it, binList) + @Suppress("TYPE_ALIAS", "UnsafeCallOnNullableType") + private fun searchSomeSplitInBinaryExpression(parent: ASTNode, configuration: LineLengthConfiguration): List?> { + val logicListOperationReference = listOf(OROR, ANDAND) + val compressionListOperationReference = listOf(GT, LT, EQEQ, GTEQ, LTEQ, EXCLEQ) + val binList: MutableList = mutableListOf() + searchBinaryExpression(parent, binList) + val rightBinList = binList.map { + it to positionByOffset(it.getFirstChildWithType(OPERATION_REFERENCE)!!.startOffset).second + } + .sortedBy { it.second } + .reversed() + val returnList: MutableList?> = mutableListOf() + addInSmartListBinExpression(returnList, rightBinList, logicListOperationReference, configuration) + addInSmartListBinExpression(returnList, rightBinList, compressionListOperationReference, configuration) + val expression = rightBinList.firstOrNull { (it, offset) -> + val binOperationReference = it.getFirstChildWithType(OPERATION_REFERENCE)!!.firstChildNode.elementType + offset + (it.getFirstChildWithType(OPERATION_REFERENCE)?.text!!.length ?: 0) <= configuration.lineLength + 1 && + binOperationReference !in logicListOperationReference && binOperationReference !in compressionListOperationReference && binOperationReference != EXCL } + returnList.add(expression) + return returnList } - private fun createSplitProperty(wrongProperty: LongLineFixableCases.Property) { - val node = wrongProperty.node - val indexLastSpace = wrongProperty.indexLastSpace - val text = wrongProperty.text - splitTextAndCreateNode(node, text, indexLastSpace) + /** + * Runs through the sorted list [rightBinList], finds its last element, the type of which is included in the set [typesList] and adds it in the list [returnList] + */ + @Suppress("TYPE_ALIAS", "UnsafeCallOnNullableType") + private fun addInSmartListBinExpression( + returnList: MutableList?>, + rightBinList: List>, + typesList: List, + configuration: LineLengthConfiguration + ) { + val expression = rightBinList.firstOrNull { (it, offset) -> + val binOperationReference = it.getFirstChildWithType(OPERATION_REFERENCE) + offset + (it.getFirstChildWithType(OPERATION_REFERENCE)?.text!!.length ?: 0) <= configuration.lineLength + 1 && + binOperationReference!!.firstChildNode.elementType in typesList + } + returnList.add(expression) } + /** + * Finds the first binary expression closer to the separator + */ @Suppress("UnsafeCallOnNullableType") - private fun splitTextAndCreateNode( - node: ASTNode, - text: String, - index: Int - ) { - val resultText = "\"${text.substring(0, index)}\" +\n\"${text.substring(index)}\"" - val newNode = KotlinParser().createNode(resultText) - node.removeChild(node.findChildByType(STRING_TEMPLATE)!!) - val prevExp = CompositeElement(BINARY_EXPRESSION) - node.addChild(prevExp, null) - prevExp.addChild(newNode, null) + private fun searchRightSplitInBinaryExpression(parent: ASTNode, configuration: LineLengthConfiguration): Pair? { + val binList: MutableList = mutableListOf() + searchBinaryExpression(parent, binList) + return binList.map { + it to positionByOffset(it.getFirstChildWithType(OPERATION_REFERENCE)!!.startOffset).second + } + .sortedBy { it.second } + .reversed() + .firstOrNull { (it, offset) -> + offset + (it.getFirstChildWithType(OPERATION_REFERENCE)?.text!!.length ?: 0) <= configuration.lineLength + 1 + } } /** @@ -496,49 +486,86 @@ class LineLength(configRules: List) : DiktatRule( val lineLength = config["lineLength"]?.toLongOrNull() ?: MAX_LENGTH } + /** + * Class LongLineFixableCases is parent class for several specific error classes + */ @Suppress("KDOC_NO_CONSTRUCTOR_PROPERTY", "MISSING_KDOC_CLASS_ELEMENTS") // todo add proper docs - sealed class LongLineFixableCases { - object None : LongLineFixableCases() + sealed class LongLineFixableCases(val node: ASTNode) - /** - * @property node node - * @property hasNewLineBefore flag to handle type of comment: ordinary comment (long part of which should be moved to the next line) - * and inline comments (which should be moved entirely to the previous line) - * @property indexLastSpace index of last space to substring comment - */ - class Comment( - val node: ASTNode, - val hasNewLineBefore: Boolean, - val indexLastSpace: Int = 0 - ) : LongLineFixableCases() + /** + * Class None show error long line have unidentified type or something else that we can't analyze + */ + private class None : LongLineFixableCases(KotlinParser().createNode("ERROR")) - /** - * @property node node - * @property delimiterIndex index to split - * @property isOneLineString flag is string is one line - */ - class StringTemplate( - val node: ASTNode, - val delimiterIndex: Int, - val isOneLineString: Boolean - ) : LongLineFixableCases() - - class BinaryExpression(val node: ASTNode) : LongLineFixableCases() - - class Condition( - val maximumLineLength: Long, - val leftOffset: Int, - val binList: MutableList - ) : LongLineFixableCases() - - class Fun(val node: ASTNode) : LongLineFixableCases() - - class Property( - val node: ASTNode, - val indexLastSpace: Int, - val text: String - ) : LongLineFixableCases() - } + /** + * @property node node + * @property hasNewLineBefore flag to handle type of comment: ordinary comment (long part of which should be moved to the next line) + * and inline comments (which should be moved entirely to the previous line) + * @property indexLastSpace index of last space to substring comment + */ + + /** + * Class Comment show that long line should be split in comment + * @property hasNewLineBefore + * @property indexLastSpace + */ + private class Comment( + node: ASTNode, + val hasNewLineBefore: Boolean, + val indexLastSpace: Int = 0 + ) : LongLineFixableCases(node) + + /** + * @property node node + * @property delimiterIndex index to split + * @property isOneLineString flag is string is one line + */ + + /** + * Class StringTemplate show that long line should be split in string template + * @property delimiterIndex + * @property isOneLineString + */ + private class StringTemplate( + node: ASTNode, + val delimiterIndex: Int, + val isOneLineString: Boolean + ) : LongLineFixableCases(node) + + /** + * Class BinaryExpression show that long line should be split in short binary expression? after operation reference + */ + private class BinaryExpression(node: ASTNode) : LongLineFixableCases(node) + + /** + * Class LongBinaryExpression show that long line should be split between other parts long binary expression, + * after one of operation reference + * @property maximumLineLength + * @property leftOffset + * @property binList + */ + private class LongBinaryExpression( + node: ASTNode, + val maximumLineLength: LineLengthConfiguration, + val leftOffset: Int, + val binList: MutableList + ) : LongLineFixableCases(node) + + /** + * Class Fun show that long line should be split in Fun: after EQ (between head and body this function) + */ + private class FunAndProperty(node: ASTNode) : LongLineFixableCases(node) + + /** + * Class Lambda show that long line should be split in Comment: in space between two words + */ + private class Lambda(node: ASTNode) : LongLineFixableCases(node) + + /** + * Class Property show that long line should be split in property: after a EQ + * @property indexLastSpace + * @property text + */ /** * val text = "first part" + diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthFixTest.kt index 4271d9a117..8dfc008cf4 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/LineLengthFixTest.kt @@ -7,6 +7,10 @@ import org.cqfn.diktat.util.FixTestBase import org.junit.jupiter.api.Test class LineLengthFixTest : FixTestBase("test/paragraph3/long_line", ::LineLength) { + private val rulesConfigListLongLineLength: List = listOf( + RulesConfig(LONG_LINE.name, true, + mapOf("lineLength" to "175")) + ) private val rulesConfigListDefaultLineLength: List = listOf( RulesConfig(LONG_LINE.name, true, mapOf("lineLength" to "120")) @@ -74,4 +78,14 @@ class LineLengthFixTest : FixTestBase("test/paragraph3/long_line", ::LineLength) fun `should fix annotation`() { fixAndCompare("LongLineAnnotationExpected.kt", "LongLineAnnotationTest.kt", rulesConfigListLineLength) } + + @Test + fun `fix condition in small function with long length`() { + fixAndCompare("LongConditionInSmallFunctionExpected.kt", "LongConditionInSmallFunctionTest.kt", rulesConfigListLongLineLength) + } + + @Test + fun `fix expression in condition`() { + fixAndCompare("LongExpressionInConditionExpected.kt", "LongExpressionInConditionTest.kt", rulesConfigListLineLength) + } } diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionExpected.kt index 94c5f6f895..432b811517 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionExpected.kt @@ -1,35 +1,48 @@ package test.paragraph3.long_line fun foo() { - val veryLongExpression = Methoooooooooooooooood() + - 12345 + val veryLongExpression = + Methoooooooooooooooood() + 12345 - val veryLongExpression = Methoooooooooooooooood() ?: - null + val veryLongExpression = + Methoooooooooooooooood() ?: null val veryLongExpression = a.Methooooood() + b.field - val variable = someField.filter { it.elementType == KDOC } + val variable = someField.filter { + it.elementType == KDOC + } // limit at the left side - val variable = a?.filter { it.elementType == KDOC } ?: - null + val variable = a?.filter { + it.elementType == KDOC + } ?: null // limit at the right side - val variable = bar?.filter { it.b == c } ?: - null + val variable = bar?.filter { it.b == c } + ?: null // limit at the operation reference - val variable = field?.filter { bar == foo } ?: - null + val variable = field?.filter { bar == foo } + ?: null - val variable = Methoooooooooooooooooooooooooood() ?: - "some loooooong string" + val variable = field?.filter { bar == foo } +?: null + + val variable = Methooood() * 2 + 12 + field + ?: 123 + Methood().linelength + + val variable = Methooood() * 2 + 12 + field +?: 123 + Methood().linelength + + val variable = + Methoooooooooooooooooooooooooood() ?: "some loooooong string" val variable = Methooooood() ?: "some" + " looong string" - var headerKdoc = firstCodeNode.prevSibling { it.elementType == KDOC } ?: - if (firstCodeNode == packageDirectiveNode) importsList?.prevSibling { it.elementType == KDOC } else null + var headerKdoc = firstCodeNode.prevSibling { + it.elementType == KDOC + } ?: if (firstCodeNode == packageDirectiveNode) importsList?.prevSibling { it.elementType == KDOC } else null } diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionTest.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionTest.kt index 2f14386194..cf77691e6e 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongBinaryExpressionTest.kt @@ -18,6 +18,12 @@ fun foo() { // limit at the operation reference val variable = field?.filter { bar == foo } ?: null + val variable = field?.filter { bar == foo }?: null + + val variable = Methooood() * 2 + 12 + field ?: 123 + Methood().linelength + + val variable = Methooood() * 2 + 12 + field?: 123 + Methood().linelength + val variable = Methoooooooooooooooooooooooooood() ?: "some loooooong string" val variable = Methooooood() ?: "some looong string" diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionExpected.kt new file mode 100644 index 0000000000..d415bc0fce --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionExpected.kt @@ -0,0 +1,5 @@ +package test.paragraph3.long_line + +private fun isContainingRequiredPartOfCode(text: String): Boolean = + text.contains("val ", true) || text.contains("var ", true) || text.contains("=", true) || (text.contains("{", true) && + text.substringAfter("{").contains("}", true)) diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionTest.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionTest.kt new file mode 100644 index 0000000000..421efa3343 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongConditionInSmallFunctionTest.kt @@ -0,0 +1,4 @@ +package test.paragraph3.long_line + +private fun isContainingRequiredPartOfCode(text: String): Boolean = + text.contains("val ", true) || text.contains("var ", true) || text.contains("=", true) || (text.contains("{", true) && text.substringAfter("{").contains("}", true)) diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionExpected.kt new file mode 100644 index 0000000000..04f55581f4 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionExpected.kt @@ -0,0 +1,18 @@ +package test.paragraph3.long_line + +fun foo() { + val veryLooongStringName = "ASDFGHJKL" + val veryLooooooongConstIntName1 = 12345 + val veryLooooooongConstIntName2 = 54321 + var carry = 1 + if (veryLooooooongConstIntName1 > + veryLooooooongConstIntName2) { + carry++ + } else if (veryLooooooongConstIntName2 > + 123 * 12 && veryLooongStringName != "asd") { + carry+=2 + } else if (1234 + 1235 + 1236 + 1237 + 1238 > + 124 * 12) { + carry+=3 + } +} \ No newline at end of file diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionTest.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionTest.kt new file mode 100644 index 0000000000..e1e3598b05 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongExpressionInConditionTest.kt @@ -0,0 +1,15 @@ +package test.paragraph3.long_line + +fun foo() { + val veryLooongStringName = "ASDFGHJKL" + val veryLooooooongConstIntName1 = 12345 + val veryLooooooongConstIntName2 = 54321 + var carry = 1 + if (veryLooooooongConstIntName1 > veryLooooooongConstIntName2) { + carry++ + } else if (veryLooooooongConstIntName2 > 123 * 12 && veryLooongStringName != "asd") { + carry+=2 + } else if (1234 + 1235 + 1236 + 1237 + 1238 > 124 * 12) { + carry+=3 + } +} \ No newline at end of file diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineCommentExpected2.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineCommentExpected2.kt index f9b6d642e4..4f15518fd6 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineCommentExpected2.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineCommentExpected2.kt @@ -3,8 +3,13 @@ */ class ImplicitBackingPropertyRuleTest(configRules: List) { private fun validateAccessors(node: ASTNode, propsWithBackSymbol: List) { - val accessors = node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) } // Comment, which shouldn't be moved - accessors.filter { it.hasChildOfType(GET_KEYWORD) }.forEach { handleGetAccessors(it, node, propsWithBackSymbol) } - accessors.filter { it.hasChildOfType(SET_KEYWORD) }.forEach { handleSetAccessors(it, node, propsWithBackSymbol) } + val accessors = + node.findAllDescendantsWithSpecificType(PROPERTY_ACCESSOR).filter { it.hasChildOfType(BLOCK) } // Comment, which shouldn't be moved + accessors.filter { it.hasChildOfType(GET_KEYWORD) }.forEach { + handleGetAccessors(it, node, propsWithBackSymbol) + } + accessors.filter { it.hasChildOfType(SET_KEYWORD) }.forEach { + handleSetAccessors(it, node, propsWithBackSymbol) + } } } diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionExpected.kt index f53742c6a3..8e89ff4e21 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionExpected.kt @@ -1,6 +1,8 @@ package test.paragraph3.long_line fun foo() { + if (( x > 4365873654863745683)|| +y<238479283749238&&!isFoo()){} if (( x > 4365873654863745683) || y<238479283749238 && !isFoo()){} if (q.text == "dc" && !IsFoo() || @@ -9,7 +11,8 @@ fun foo() { x > 238479283749238 && y < 238479283749238 || g == "text"){} if (d == "very long text" && gh == "very long text" || x > 238479283749238 || y< 238479283749238){} - if (x == 2384792837492387498728947289472987492){} + if (x == + 2384792837492387498728947289472987492){} if (x == 972938473924535278492792738497){} if (x == "veery long text to split" || x == "es" || y == 123 || b > 12 && jh==234 || h==54){} diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionTest.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionTest.kt index d7058d8e86..5eba9b017b 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineExpressionTest.kt @@ -1,6 +1,7 @@ package test.paragraph3.long_line fun foo() { + if (( x > 4365873654863745683)||y<238479283749238&&!isFoo()){} if (( x > 4365873654863745683) || y<238479283749238 && !isFoo()){} if (q.text == "dc" && !IsFoo() || x > 238479283749238 && y < 238479283749238 || g == "text"){} if (q.text == "dc" && !IsFoo() || x > 238479283749238 && y < 238479283749238 || g == "text"){} diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueExpected.kt index 2fd0dfcf09..06fc6dc392 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueExpected.kt @@ -5,39 +5,44 @@ fun foo() { " should be split" fun foo() { - val veryLoooooooooooooooooongNamesList = listOf("Jack", "Nick") - veryLoooooooooooooooooongNamesList.forEach { name -> + val veryLoooooooooooooooooongNamesList = + listOf("Jack", "Nick") + veryLoooooooooooooooooongNamesList.forEach { + name -> if (name == "Nick") { veryLoooooooooooooooooongNamesList.map { val str = "This string shouldn't be split"} - name.map { val str = "This" + -" string should be split" } + name.map { val str = + "This string should be split" } } + } } val longIntExpression = 12345 + 12345 + 12345 + 12345 + val longIntExpression = (12345 + 12345 + + 12345 + 12345) + + val longIntExpression = (12345) + (12345) + + (12345) + (12345) + val LongWithVar2 = "very long" + " woooooordsdcsdcsdcsdc $variable" val longStringExpression = "First part" + -"second Part" + "second Part" val longStringExpression = "First" + "second Part" val longStringExpression = "First very long" + " part" + "second Part" - val longStringExpression2 = "String starts at the line len limit" + val longStringExpression2 = + "String starts at the line len limit" - val veryLooooooooooooooooooooooooooooooongVal = "text" - - val longIntExpression = (12345 + 12345 + - 12345 + 12345) - - val longIntExpression = (12345) + (12345) + - (12345) + (12345) + val veryLooooooooooooooooooooooooooooooongVal = + "text" val veryLongExpression = Method() + 12345 + baaar() diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueTest.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueTest.kt index fa6d6c1881..8f02b5a898 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongLineRValueTest.kt @@ -15,6 +15,10 @@ fun foo() { val longIntExpression = 12345 + 12345 + 12345 + 12345 + val longIntExpression = (12345 + 12345 + 12345 + 12345) + + val longIntExpression = (12345) + (12345) + (12345) + (12345) + val LongWithVar2 = "very long woooooordsdcsdcsdcsdc $variable" val longStringExpression = "First part" + "second Part" @@ -27,10 +31,6 @@ fun foo() { val veryLooooooooooooooooooooooooooooooongVal = "text" - val longIntExpression = (12345 + 12345 + 12345 + 12345) - - val longIntExpression = (12345) + (12345) + (12345) + (12345) - val veryLongExpression = Method() + 12345 + baaar() val veryLongExpression = Method() + baaar() + 12345 diff --git a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongStringTemplateExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongStringTemplateExpected.kt index 74bbdd341c..b386956da8 100644 --- a/diktat-rules/src/test/resources/test/paragraph3/long_line/LongStringTemplateExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph3/long_line/LongStringTemplateExpected.kt @@ -15,12 +15,14 @@ val someCode = 15 class Foo() { fun Fuu() { - logger.log("<-- ${response.code} ${ if (response.message.isEmpty()) "skfnvkdjdfvd" else "dfjvndkjnbvif" + response.message}") + logger.log("<-- ${response.code} ${ if (response.message.isEmpty()) "skfnvkdjdfvd" else "dfjvndkjnbvif" + + response.message}") logger.log("<-- ${response.code} ${ if (response.message.isEmpty()) "skfnvsdcsdcscskdjdfvd" else "dfjvndsdcsdcsdcskjnbvif" + response.message}") } val q = """ - <--${respodcnsee.ccode}${if (response.mesdscsage.isEmpty()) "skfnvkdjeeeeeee" else "dfjvndksdcjnbvif" + response.mecsssdcage} + <--${respodcnsee.ccode}${if (response.mesdscsage.isEmpty()) "skfnvkdjeeeeeee" else "dfjvndksdcjnbvif" + + response.mecsssdcage} """.trimIndent() val w = """ @@ -31,15 +33,16 @@ class Foo() { val e = """ another line - <--${respodcnse.ccode}${if (response.mesdscsage.isEmpty()) "skfnvkdjdsdcfvd" else "dfjvndksdcjnbvif" + response.mecsssdcage} + <--${respodcnse.ccode}${if (response.mesdscsage.isEmpty()) "skfnvkdjdsdcfvd" else "dfjvndksdcjnbvif" + + response.mecsssdcage} """.trimIndent() fun foo() { val q = """ re ${ - if (( x > "436587365486374568343658736548637456834365873654863745683436587365486374568343658736548637456834365873654863745683") || - y<238479283749238 && !isFoo()){} + if (( x > + "436587365486374568343658736548637456834365873654863745683436587365486374568343658736548637456834365873654863745683") || y<238479283749238 && !isFoo()){} } """.trimIndent() }