diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/IdentifierNaming.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/IdentifierNaming.kt index c0e9e277c1..c834ffc84e 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/IdentifierNaming.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter1/IdentifierNaming.kt @@ -371,8 +371,8 @@ class IdentifierNaming(configRules: List) : DiktatRule( * 4) backticks are prohibited in the naming of non-test methods */ @Suppress("UnsafeCallOnNullableType") - private fun checkFunctionName(node: ASTNode): List { - val functionName = node.getIdentifierName()!! + private fun checkFunctionName(node: ASTNode): List? { + val functionName = node.getIdentifierName() ?: return null // basic check for camel case if (!functionName.text.isLowerCamelCase()) { diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt index 09586184c3..22a408605b 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt @@ -21,6 +21,7 @@ import org.cqfn.diktat.ruleset.utils.hasKnownKdocTag import org.cqfn.diktat.ruleset.utils.hasTestAnnotation import org.cqfn.diktat.ruleset.utils.insertTagBefore import org.cqfn.diktat.ruleset.utils.isAccessibleOutside +import org.cqfn.diktat.ruleset.utils.isAnonymousFunction import org.cqfn.diktat.ruleset.utils.isGetterOrSetter import org.cqfn.diktat.ruleset.utils.isLocatedInTest import org.cqfn.diktat.ruleset.utils.isOverridden @@ -88,7 +89,7 @@ class KdocMethods(configRules: List) : DiktatRule( val config = configRules.getCommonConfiguration() val filePath = node.getFilePath() val isTestMethod = node.hasTestAnnotation() || isLocatedInTest(filePath.splitPathToDirs(), config.testAnchors) - if (!isTestMethod && !node.isStandardMethod() && !node.isSingleLineGetterOrSetter()) { + if (!isTestMethod && !node.isStandardMethod() && !node.isSingleLineGetterOrSetter() && !node.isAnonymousFunction()) { checkSignatureDescription(node) } } else if (node.elementType == KDOC_SECTION) { diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/AvoidNestedFunctionsRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/AvoidNestedFunctionsRule.kt index 8fdc38eaf5..5ab5b27579 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/AvoidNestedFunctionsRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter5/AvoidNestedFunctionsRule.kt @@ -7,6 +7,7 @@ import org.cqfn.diktat.ruleset.utils.findAllDescendantsWithSpecificType import org.cqfn.diktat.ruleset.utils.getFirstChildWithType import org.cqfn.diktat.ruleset.utils.hasChildOfType import org.cqfn.diktat.ruleset.utils.hasParent +import org.cqfn.diktat.ruleset.utils.isAnonymousFunction import com.pinterest.ktlint.core.ast.ElementType.CLASS_BODY import com.pinterest.ktlint.core.ast.ElementType.FUN @@ -65,7 +66,8 @@ class AvoidNestedFunctionsRule(configRules: List) : DiktatRule( } private fun isNestedFunction(node: ASTNode): Boolean = - node.hasParent(FUN) && node.hasFunParentUntil(CLASS_BODY) && !node.hasChildOfType(MODIFIER_LIST) + node.hasParent(FUN) && node.hasFunParentUntil(CLASS_BODY) && !node.hasChildOfType(MODIFIER_LIST) && + !node.isAnonymousFunction() private fun ASTNode.hasFunParentUntil(stopNode: IElementType): Boolean = parents() 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 2fb9170d58..46abdf0973 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 @@ -28,6 +28,7 @@ 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.FUN import com.pinterest.ktlint.core.ast.ElementType.IMPORT_LIST import com.pinterest.ktlint.core.ast.ElementType.INTERNAL_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.KDOC @@ -159,6 +160,15 @@ fun ASTNode.replaceWhiteSpaceText(beforeNode: ASTNode, text: String) { fun ASTNode.getFirstChildWithType(elementType: IElementType): ASTNode? = this.findChildByType(elementType) +/** + * Checks if a function is anonymous + * throws exception if the node type is different from FUN + */ +fun ASTNode.isAnonymousFunction(): Boolean { + require(this.elementType == FUN) + return this.getIdentifierName() == null +} + /** * Checks if the symbols in this node are at the end of line */ diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/IdentifierNamingWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/IdentifierNamingWarnTest.kt index a7a9c8d432..b31d901213 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/IdentifierNamingWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter1/IdentifierNamingWarnTest.kt @@ -58,6 +58,20 @@ class IdentifierNamingWarnTest : LintTestBase(::IdentifierNaming) { lintMethod(code) } + @Test + @Tag(WarningNames.GENERIC_NAME) + fun `anonymous function`() { + val code = """ + package org.cqfn.diktat.test + + fun foo() { + val sum: (Int) -> Int = fun(x): Int = x + x + } + + """.trimIndent() + lintMethod(code) + } + @Test @Tag(WarningNames.GENERIC_NAME) fun `generic class - single capital letter, can be followed by a number (check - negative1)`() { diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocMethodsTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocMethodsTest.kt index 727f320758..0cb229990d 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocMethodsTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocMethodsTest.kt @@ -54,6 +54,22 @@ class KdocMethodsTest : LintTestBase(::KdocMethods) { lintMethod(validCode) } + @Test + @Tag(WarningNames.MISSING_KDOC_TOP_LEVEL) + fun `anonymous function`() { + val code = """ + package org.cqfn.diktat.test + + fun foo() { + val sum: (Int) -> Int = fun(x): Int = x + x + } + + """.trimIndent() + lintMethod(code, + LintError(3, 1, ruleId, "${MISSING_KDOC_ON_FUNCTION.warnText()} foo", false), + ) + } + @Test @Tags( Tag(WarningNames.KDOC_WITHOUT_PARAM_TAG), diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt index 0671fb3f36..bdedc76de3 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt @@ -6,6 +6,7 @@ import org.cqfn.diktat.ruleset.rules.chapter5.AvoidNestedFunctionsRule import org.cqfn.diktat.util.LintTestBase import com.pinterest.ktlint.core.LintError +import generated.WarningNames import generated.WarningNames.AVOID_NESTED_FUNCTIONS import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test @@ -35,6 +36,20 @@ class AvoidNestedFunctionsWarnTest : LintTestBase(::AvoidNestedFunctionsRule) { ) } + @Test + @Tag(AVOID_NESTED_FUNCTIONS) + fun `anonymous function`() { + val code = """ + package org.cqfn.diktat.test + + fun foo() { + val sum: (Int) -> Int = fun(x): Int = x + x + } + + """.trimIndent() + lintMethod(code) + } + @Test @Tag(AVOID_NESTED_FUNCTIONS) fun `several nested functions`() { diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt index 13f9bc4a5c..bd0e64d293 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt @@ -108,6 +108,12 @@ class DiktatSmokeTest : FixTestBase("test/smoke/src/main/kotlin", fixAndCompareSmokeTest("DefaultPackageExpected.kt", "DefaultPackageTest.kt") } + @Test + @Tag("DiktatRuleSetProvider") + fun `smoke test #8 - anonymous function`() { + fixAndCompareSmokeTest("Example8Expected.kt", "Example8Test.kt") + } + @Test @Tag("DiktatRuleSetProvider") fun `smoke test #7`() { diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example8Expected.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example8Expected.kt new file mode 100644 index 0000000000..2725173aa7 --- /dev/null +++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example8Expected.kt @@ -0,0 +1,14 @@ +package org.cqfn.diktat + +fun foo() { + val sum: (Int, Int, Int,) -> Int = fun( + x, + y, + z + ): Int = x + y + x + println(sum(8, 8, 8)) +} + +fun boo() { + val message = fun() = println("Hello") +} \ No newline at end of file diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example8Test.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example8Test.kt new file mode 100644 index 0000000000..33cf27b281 --- /dev/null +++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example8Test.kt @@ -0,0 +1,16 @@ +package org.cqfn.diktat + +fun foo() { + val sum: (Int, Int, Int,) -> Int = fun( + x, + y, + z + ): Int { + return x + y + x + } + println(sum(8, 8, 8)) +} + +fun boo() { + val message = fun()=println("Hello") +} \ No newline at end of file