Repository: cqfn/diKTat (kotlin)

Issue:
NullPointerException on KDOC inspection
```
package test.paragraph3.trailing_comma

class Customer(
    val name: String,
    lastName: String,
)

fun shift(x: Int,
          y: Int,
) {
    shift(
        25,
        20,
    )

    val colors = listOf(
        "red",
        "green",
        "blue",
    )
}

fun getZValue(mySurface: Surface,
              xValue: Int,
              yValue: Int,
) =
    mySurface[
            xValue,
            yValue
    ]

fun isReferenceApplicable(myReference: KClass<*>,
) = when (myReference) {
    Comparable::class,
    Iterable::class,
    String::class,
    -> true
    else -> false
}

fun isReferenceApplicable(myReference: KClass<*> ,// comment
) = when (myReference) {
    Comparable::class,
    Iterable::class,
    String::class,
    -> true
    else -> false
}

@ApplicableFor([
    "serializer",
    "balancer",
    "database",
    "inMemoryCache",
],
)
fun foo() {}

fun <T1,
        T21,
        > foo() {}

fun mains() {
    foo<
            Comparable<Number,
                    >,
            Iterable<Number,
                    >,
            >()
}

fun printMeanValue() {
    var meanValue: Int = 0
    for ((
        _,
        _,
        year,
    ) in cars) {
        meanValue += year
    }
    println(meanValue/cars.size)
}

enum class SomeEnum(
    val a: Int, val b: Int  ,// comment
)

enum class SomeEnum(
    val a: Int, val b: Int,// comment
)

enum class SomeEnum(
    val a: Int, val b: Int  ,/* comment */
)

enum class SomeEnum(
    val a: Int, val b: Int,  /**
    some comment */
)

fun foo() {
    val sum: (Int, Int, Int,) -> Int = fun(
        x,
        y,
        z ,// trailing comma
    ): Int {
        return x + y + x
    }
    println(sum(8, 8, 8))
}

fun shift(x: Int, y: Int) {
    shift(
        25,
        20, // trailing comma
    )

    val colors = listOf(
        "red",
        "green",
        "blue", // trailing comma
    )
}
```

<img width="1205" alt="image" src="https://user-images.githubusercontent.com/58667063/171022032-4fd59843-84d8-4e0c-9486-d03597e72184.png">


Diktat incorrectly treats KDOC and causes hard failure

Pull request description:
### What's done:
* fixed NullPointerException on KDOC inspection
Closes #1331

Patch:
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<RulesConfig>) : DiktatRule(
      * 4) backticks are prohibited in the naming of non-test methods
      */
     @Suppress("UnsafeCallOnNullableType")
-    private fun checkFunctionName(node: ASTNode): List<ASTNode> {
-        val functionName = node.getIdentifierName()!!
+    private fun checkFunctionName(node: ASTNode): List<ASTNode>? {
+        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<RulesConfig>) : 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<RulesConfig>) : 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
  */


Test patch:
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