From 2662d6611116612b0a473cfe94f6de17df0aebd0 Mon Sep 17 00:00:00 2001 From: Denis Kumar Date: Thu, 13 May 2021 17:02:30 +0300 Subject: [PATCH] FP for gradle script (#885) * FP for gradle script ### What's done: Fixed logic in `RunScriptRule` Removed handler for header in gradle script Updated Kdoc Updated test --- .../chapter2/comments/HeaderCommentRule.kt | 5 ++- .../ruleset/rules/chapter6/RunInScript.kt | 42 +++++++++---------- .../cqfn/diktat/ruleset/utils/AstNodeUtils.kt | 12 ++++++ .../ruleset/chapter2/HeaderCommentRuleTest.kt | 27 ++++++++++++ .../ruleset/chapter6/RunInScriptWarnTest.kt | 38 +++++++++++++++++ 5 files changed, 102 insertions(+), 22 deletions(-) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/HeaderCommentRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/HeaderCommentRule.kt index 4202bb7d1f..421cbff623 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/HeaderCommentRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/HeaderCommentRule.kt @@ -13,7 +13,10 @@ import org.cqfn.diktat.ruleset.utils.copyrightWords import org.cqfn.diktat.ruleset.utils.findChildAfter import org.cqfn.diktat.ruleset.utils.findChildBefore import org.cqfn.diktat.ruleset.utils.getAllChildrenWithType +import org.cqfn.diktat.ruleset.utils.getFilePath import org.cqfn.diktat.ruleset.utils.getFirstChildWithType +import org.cqfn.diktat.ruleset.utils.getRootNode +import org.cqfn.diktat.ruleset.utils.isGradleScript import org.cqfn.diktat.ruleset.utils.moveChildBefore import com.pinterest.ktlint.core.ast.ElementType @@ -45,7 +48,7 @@ class HeaderCommentRule(configRules: List) : DiktatRule( listOf(HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE, HEADER_MISSING_OR_WRONG_COPYRIGHT, HEADER_NOT_BEFORE_PACKAGE, HEADER_NOT_BEFORE_PACKAGE, HEADER_WRONG_FORMAT, WRONG_COPYRIGHT_YEAR)) { override fun logic(node: ASTNode) { - if (node.elementType == FILE) { + if (node.elementType == FILE && !node.getRootNode().getFilePath().isGradleScript()) { checkCopyright(node) if (checkHeaderKdocPosition(node)) { checkHeaderKdoc(node) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/RunInScript.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/RunInScript.kt index ab48e27c1b..70d41d663c 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/RunInScript.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/RunInScript.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement /** * Rule that checks if kts script contains other functions except run code * In .kts files allow use only property declaration, function, classes, and code inside `run` block - * In gradle.kts files allow to call expression and dot qualified expression in addition to everything used in .kts files + * In gradle.kts files allow to call binary expression with EQ, expression and dot qualified expression in addition to everything used in .kts files */ class RunInScript(private val configRules: List) : Rule("run-script") { private var isFixMode: Boolean = false @@ -44,20 +44,16 @@ class RunInScript(private val configRules: List) : Rule("run-script } private fun checkGradleNode(node: ASTNode) { - val astNode = if (node.firstChildNode.elementType == PARENTHESIZED) { - node.firstChildNode + val astNode = if (node.hasEqBinaryExpression()) { + return } else { - node + when (node.firstChildNode.elementType) { + PARENTHESIZED -> node.firstChildNode + else -> node + } } if (!astNode.hasChildOfType(CALL_EXPRESSION) && !astNode.hasChildOfType(DOT_QUALIFIED_EXPRESSION)) { - RUN_IN_SCRIPT.warnAndFix(configRules, emitWarn, isFixMode, astNode.text, astNode.startOffset, astNode) { - val parent = astNode.treeParent - val newNode = KotlinParser().createNode("run {\n ${astNode.text}\n} \n") - val newScript = CompositeElement(SCRIPT_INITIALIZER) - parent.addChild(newScript, astNode) - newScript.addChild(newNode) - parent.removeChild(astNode) - } + warnRunInScript(astNode) } } @@ -65,15 +61,19 @@ class RunInScript(private val configRules: List) : Rule("run-script val isLambdaArgument = node.firstChildNode.hasChildOfType(LAMBDA_ARGUMENT) val isLambdaInsideValueArgument = node.firstChildNode.findChildByType(VALUE_ARGUMENT_LIST)?.findChildByType(VALUE_ARGUMENT)?.findChildByType(LAMBDA_EXPRESSION) != null if (!(isLambdaArgument || isLambdaInsideValueArgument)) { - RUN_IN_SCRIPT.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) { - if (node.firstChildNode.elementType != DOT_QUALIFIED_EXPRESSION) { - val parent = node.treeParent - val newNode = KotlinParser().createNode("run {\n ${node.text}\n} \n") - val newScript = CompositeElement(SCRIPT_INITIALIZER) - parent.addChild(newScript, node) - newScript.addChild(newNode) - parent.removeChild(node) - } + warnRunInScript(node) + } + } + + private fun warnRunInScript(node: ASTNode) { + RUN_IN_SCRIPT.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) { + if (node.firstChildNode.elementType != DOT_QUALIFIED_EXPRESSION) { + val parent = node.treeParent + val newNode = KotlinParser().createNode("run {\n ${node.text}\n} \n") + val newScript = CompositeElement(SCRIPT_INITIALIZER) + parent.addChild(newScript, node) + newScript.addChild(newNode) + parent.removeChild(node) } } } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt index 2feed40a6f..d9f77e422c 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt @@ -17,9 +17,11 @@ import com.pinterest.ktlint.core.KtLint import com.pinterest.ktlint.core.ast.ElementType import com.pinterest.ktlint.core.ast.ElementType.ANNOTATED_EXPRESSION 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.BLOCK_COMMENT import com.pinterest.ktlint.core.ast.ElementType.CONST_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT +import com.pinterest.ktlint.core.ast.ElementType.EQ import com.pinterest.ktlint.core.ast.ElementType.FILE import com.pinterest.ktlint.core.ast.ElementType.FILE_ANNOTATION_LIST import com.pinterest.ktlint.core.ast.ElementType.IMPORT_LIST @@ -28,6 +30,7 @@ import com.pinterest.ktlint.core.ast.ElementType.KDOC import com.pinterest.ktlint.core.ast.ElementType.LATEINIT_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.LBRACE import com.pinterest.ktlint.core.ast.ElementType.MODIFIER_LIST +import com.pinterest.ktlint.core.ast.ElementType.OPERATION_REFERENCE import com.pinterest.ktlint.core.ast.ElementType.OVERRIDE_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.PRIVATE_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.PROPERTY @@ -750,6 +753,15 @@ fun ASTNode.isGoingAfter(otherNode: ASTNode): Boolean { return (thisLineNumber > otherLineNumber) } +/** + * check that node has binary expression with `EQ` + */ +fun ASTNode.hasEqBinaryExpression(): Boolean = + findChildByType(BINARY_EXPRESSION) + ?.findChildByType(OPERATION_REFERENCE) + ?.hasChildOfType(EQ) + ?: false + /** * Get line number, where this node's content starts. To avoid `ArrayIndexOutOfBoundsException`s we check whether node's maximum offset is less than * Document's maximum offset, and calculate line number manually if needed. diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt index f7774578ee..fb91c8ea2c 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/HeaderCommentRuleTest.kt @@ -373,4 +373,31 @@ class HeaderCommentRuleTest : LintTestBase(::HeaderCommentRule) { rulesConfigList = rulesConfigList ) } + + @Test + @Tag(WarningNames.HEADER_NOT_BEFORE_PACKAGE) + fun `header KDoc in gradle script`() { + lintMethod( + """ + |version = "0.1.0-SNAPSHOT" + | + """.trimMargin(), + fileName = "src/main/kotlin/org/cqfn/diktat/builds.gradle.kts" + + ) + } + + @Test + @Tag(WarningNames.HEADER_NOT_BEFORE_PACKAGE) + fun `header KDoc in kts script`() { + lintMethod( + """ + |val version = "0.1.0-SNAPSHOT" + | + """.trimMargin(), + LintError(1, 1, ruleId, "${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 0 declared classes and/or objects"), + fileName = "src/main/kotlin/org/cqfn/diktat/Example.kts" + + ) + } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/RunInScriptWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/RunInScriptWarnTest.kt index 8deb1d9ac1..6618fab740 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/RunInScriptWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/RunInScriptWarnTest.kt @@ -130,4 +130,42 @@ class RunInScriptWarnTest : LintTestBase(::RunInScript) { fileName = "src/main/kotlin/org/cqfn/diktat/builds.gradle.kts" ) } + + @Test + @Tag(WarningNames.RUN_IN_SCRIPT) + fun `check gradle script with eq expression`() { + lintMethod( + """ + version = "0.1.0-SNAPSHOT" + + diktat {} + + diktat({}) + + foo/*df*/() + + foo().goo() + """.trimMargin(), + fileName = "src/main/kotlin/org/cqfn/diktat/builds.gradle.kts" + ) + } + + @Test + @Tag(WarningNames.RUN_IN_SCRIPT) + fun `check kts script with eq expression`() { + lintMethod( + """ + version = "0.1.0-SNAPSHOT" + + diktat {} + + diktat({}) + + foo/*df*/() + """.trimMargin(), + LintError(1, 17, ruleId, "${RUN_IN_SCRIPT.warnText()} version = \"0.1.0-SNAPSHOT\"", true), + LintError(7, 17, ruleId, "${RUN_IN_SCRIPT.warnText()} foo/*df*/()", true), + fileName = "src/main/kotlin/org/cqfn/diktat/Example.kts" + ) + } }