Repository: cqfn/diKTat (kotlin)

Issue:
Add analysis of fully-qualified expression in NewLines rule
## Describe the bug

Fully-qualified expression should not be separated

## Initial code:

```kotlin
private val holder: java.util.concurrent.atomic.AtomicReference<T> = java.util.concurrent.atomic.AtomicReference(valueToStore)
```



```kotlin
private val holder: kotlin.native.concurrent.AtomicReference<T> = kotlin.native.concurrent.AtomicReference(valueToStore)
```

## Expected behavior

```kotlin
private val holder: java.util.concurrent.atomic.AtomicReference<T> = java.util.concurrent.atomic.AtomicReference(valueToStore)
```



```kotlin
private val holder: kotlin.native.concurrent.AtomicReference<T> = kotlin.native.concurrent.AtomicReference(valueToStore)
```

## Observed behavior

```kotlin
private val holder: java.util.concurrent.atomic.AtomicReference<T> = java.util
        .concurrent
        .atomic
        .AtomicReference(valueToStore)
```



```kotlin
private val holder: kotlin.native.concurrent.AtomicReference<T> = kotlin.native
        .concurrent
        .AtomicReference(valueToStore)
```

## Environment information
* diktat version: 1.2.0
* kotlin version: 1.6

Pull request:
## Whats added

 Add analytic fully qualified - split long `dot qualified expression` and `safe access expression` and and their combinations after first `call expression`
 
## This pull request closes #1403

## Actions checklist
* [ ] correct Warning message
* [ ] Added tests on fixers - 5 last test in `long dot qualified expression`


<!-- Is there anything left out of scope of this PR? -->

Patch:
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt
index 14cd33672e..f85f885fd7 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/NewlinesRule.kt
@@ -158,13 +158,18 @@ class NewlinesRule(configRules: List<RulesConfig>) : DiktatRule(
                 isDotQuaOrSafeAccessOrPostfixExpression(it) && it.elementType != POSTFIX_EXPRESSION
             }.reversed()
             if (listDot.size > 3) {
-                val without = listDot.filterNot {
-                    val whiteSpaceBeforeDotOrSafeAccess = it.findChildByType(DOT)?.treePrev ?: it.findChildByType(SAFE_ACCESS)?.treePrev
-                    whiteSpaceBeforeDotOrSafeAccess?.elementType == WHITE_SPACE && whiteSpaceBeforeDotOrSafeAccess.text.lines().size > 1
+                val without = listDot.filterIndexed { index, it ->
+                    val nodeBeforeDotOrSafeAccess = it.findChildByType(DOT)?.treePrev ?: it.findChildByType(SAFE_ACCESS)?.treePrev
+                    val firstElem = it.firstChildNode
+                    val isTextContainsParenthesized = isTextContainsFunctionCall(firstElem)
+                    val isNotWhiteSpaceBeforeDotOrSafeAccessContainNewLine = nodeBeforeDotOrSafeAccess?.elementType != WHITE_SPACE ||
+                        (nodeBeforeDotOrSafeAccess.elementType != WHITE_SPACE && !nodeBeforeDotOrSafeAccess.textContains('\n'))
+                    isTextContainsParenthesized && (index > 0) && isNotWhiteSpaceBeforeDotOrSafeAccessContainNewLine
                 }
-                if (without.size > 1 || (without.size == 1 && without[0] != listDot[0])) {
-                    WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode, "should be split before second and other dot/safe access", node.startOffset, node) {
-                        fixDotQualifiedExpression(listDot)
+                if (without.isNotEmpty()) {
+                    WRONG_NEWLINES.warnAndFix(configRules, emitWarn, isFixMode, "wrong split long `dot qualified expression` or `safe access expression`",
+                        node.startOffset, node) {
+                        fixDotQualifiedExpression(without)
                     }
                 }
             }
@@ -190,12 +195,10 @@ class NewlinesRule(configRules: List<RulesConfig>) : DiktatRule(
      * 2) If before first Dot or Safe Access node stay White Space node with \n - remove this node
      */
     private fun fixDotQualifiedExpression(list: List<ASTNode>) {
-        list.forEachIndexed { index, astNode ->
+        list.forEach { astNode ->
             val dotNode = astNode.getFirstChildWithType(DOT) ?: astNode.getFirstChildWithType(SAFE_ACCESS)
             val nodeBeforeDot = dotNode?.treePrev
-            if (index > 0) {
-                astNode.appendNewlineMergingWhiteSpace(nodeBeforeDot, dotNode)
-            }
+            astNode.appendNewlineMergingWhiteSpace(nodeBeforeDot, dotNode)
         }
     }
 
@@ -624,12 +627,14 @@ class NewlinesRule(configRules: List<RulesConfig>) : DiktatRule(
             }
         return if (dropLeadingProperties) {
             // fixme: we can't distinguish fully qualified names (like java.lang) from chain of property accesses (like list.size) for now
-            parentExpressionList?.dropWhile { !it.treeParent.textContains('(') && !it.treeParent.textContains('{') }
+            parentExpressionList?.dropWhile { !isTextContainsFunctionCall(it.treeParent) }
         } else {
             parentExpressionList
         }
     }
 
+    private fun isTextContainsFunctionCall(node: ASTNode): Boolean = node.textContains('(') || node.textContains('{')
+
     private fun List<ASTNode>.isNotValidCalls(node: ASTNode): Boolean {
         if (this.size == 1) {
             return false


Test patch:
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleWarnTest.kt
index 9fff0a58bd..3008ad44ee 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleWarnTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/files/NewlinesRuleWarnTest.kt
@@ -26,7 +26,7 @@ class NewlinesRuleWarnTest : LintTestBase(::NewlinesRule) {
             mapOf("maxCallsInOneLine" to "1"))
     )
     private val ruleId = "$DIKTAT_RULE_SET_ID:${NewlinesRule.NAME_ID}"
-    private val dotQuaOrSafeAccessOrPostfixExpression = "${WRONG_NEWLINES.warnText()} should be split before second and other dot/safe access"
+    private val dotQuaOrSafeAccessOrPostfixExpression = "${WRONG_NEWLINES.warnText()} wrong split long `dot qualified expression` or `safe access expression`"
     private val shouldBreakAfter = "${WRONG_NEWLINES.warnText()} should break a line after and not before"
     private val shouldBreakBefore = "${WRONG_NEWLINES.warnText()} should break a line before and not after"
     private val functionalStyleWarn = "${WRONG_NEWLINES.warnText()} should follow functional style at"
diff --git a/diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionExpected.kt b/diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionExpected.kt
index 3ddbd9f27a..49615088f2 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionExpected.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionExpected.kt
@@ -1,21 +1,20 @@
 package test.paragraph3.newlines
 
-val elem1 = firstArgumentDot?.secondArgumentDot
+val elem1 = firstArgumentDot()?.secondArgumentDot
 ?.thirdArgumentDot
 ?.fourthArgumentDot
 ?.fifthArgumentDot
 ?.sixthArgumentDot
 
 
-val elem2 = firstArgumentDot?.secondArgumentDot
+val elem2 = firstArgumentDot?.secondArgumentDot()
 ?.thirdArgumentDot
     ?.fourthArgumentDot
 ?.fifthArgumentDot
 ?.sixthArgumentDot
 
 
-val elem3 = firstArgumentDot?.secondArgumentDot
-?.thirdArgumentDot
+val elem3 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot()
 ?.fourthArgumentDot
     ?.fifthArgumentDot
 ?.sixthArgumentDot
@@ -24,70 +23,79 @@ val elem3 = firstArgumentDot?.secondArgumentDot
 val elem4 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot + firstArgumentDot?.secondArgumentDot?.thirdArgumentDot?.fourthArgumentDot
 
 
-val elem5 = firstArgumentDot!!.secondArgumentDot!!
+val elem5 = firstArgumentDot()!!.secondArgumentDot()!!
 .thirdArgumentDot!!
 .fourthArgumentDot!!
 .fifthArgumentDot!!
-.sixthArgumentDot
+.sixthArgumentDot()
 
 
-val elem6 = firstArgumentDot!!.secondArgumentDot!!
-.thirdArgumentDot!!
+val elem6 = firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot()!!
     .fourthArgumentDot!!
-.fifthArgumentDot!!
+.fifthArgumentDot()!!
 .sixthArgumentDot
 
 
-val elem7 = firstArgumentDot!!.secondArgumentDot!!
+val elem7 = firstArgumentDot!!.secondArgumentDot()!!
 .thirdArgumentDot!!
-.fourthArgumentDot!!
+.fourthArgumentDot()!!
     .fifthArgumentDot!!
 .sixthArgumentDot
 
 
-val elem8 = firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot + firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot!!.fourthArgumentDot
+val elem8 = firstArgumentDot()!!.secondArgumentDot!!.thirdArgumentDot + firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot!!.fourthArgumentDot
 
 
-val elem9 = firstArgumentDot.secondArgumentDot
-.thirdArgumentDot
+val elem9 = firstArgumentDot().secondArgumentDot
+.thirdArgumentDot()
 .fourthArgumentDot
 .fifthArgumentDot
 .sixthArgumentDot
 
 
-val elem10 = firstArgumentDot.secondArgumentDot
+val elem10 = firstArgumentDot.secondArgumentDot()
 .thirdArgumentDot
     .fourthArgumentDot
-.fifthArgumentDot
+.fifthArgumentDot()
 .sixthArgumentDot
 
 
-val elem11 = firstArgumentDot.secondArgumentDot
-.thirdArgumentDot
+val elem11 = firstArgumentDot.secondArgumentDot.thirdArgumentDot()
 .fourthArgumentDot
     .fifthArgumentDot
 .sixthArgumentDot
 
 
-val elem12 = firstArgumentDot.secondArgumentDot.thirdArgumentDot + firstArgumentDot.secondArgumentDot.thirdArgumentDot.fourthArgumentDot
+val elem12 = firstArgumentDot.secondArgumentDot.thirdArgumentDot + firstArgumentDot.secondArgumentDot().thirdArgumentDot.fourthArgumentDot
 
 
-val elem13 = firstArgumentDot!!.secondArgumentDot
-?.thirdArgumentDot
+val elem13 = firstArgumentDot!!.secondArgumentDot?.thirdArgumentDot()
 .fourthArgumentDot!!
-.fifthArgumentDot
+.fifthArgumentDot()
 ?.sixthArgumentDot
 
 
-val elem14 = firstArgumentDot.secondArgumentDot
-?.thirdArgumentDot!!
+val elem14 = firstArgumentDot.secondArgumentDot?.thirdArgumentDot()!!
 .fourthArgumentDot
 ?.fifthArgumentDot
 .sixthArgumentDot
 
 
-val elem15 = firstArgumentDot?.secondArgumentDot!!
-.thirdArgumentDot
-.fourthArgumentDot
+val elem15 = firstArgumentDot?.secondArgumentDot!!.thirdArgumentDot.fourthArgumentDot()
 .fifthArgumentDot!!
 .sixthArgumentDot
+
+
+val elem16 = firstArgumentDot.secondArgumentDot.thirdArgumentDot.fourthArgumentDot.fifthArgumentDot.sixthArgumentDot
+
+
+val elem17 = firstArgumentDot!!.secondArgumentDot.thirdArgumentDot!!.fourthArgumentDot.fifthArgumentDot!!.sixthArgumentDot
+
+
+val elem18 = firstArgumentDot.secondArgumentDot?.thirdArgumentDot.fourthArgumentDot?.fifthArgumentDot.sixthArgumentDot
+
+
+private val holder: java.util.concurrent.atomic.AtomicReference<T> = java.util.concurrent.atomic.AtomicReference(valueToStore)
+
+
+private val holder: kotlin.native.concurrent.AtomicReference<T> = kotlin.native.concurrent.AtomicReference(valueToStore)
diff --git a/diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionTest.kt b/diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionTest.kt
index 7ccb6cb55b..b32e0100a8 100644
--- a/diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionTest.kt
+++ b/diktat-rules/src/test/resources/test/paragraph3/newlines/LongDotQualifiedExpressionTest.kt
@@ -1,51 +1,66 @@
 package test.paragraph3.newlines
 
-val elem1 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot?.fourthArgumentDot?.fifthArgumentDot?.sixthArgumentDot
+val elem1 = firstArgumentDot()?.secondArgumentDot?.thirdArgumentDot?.fourthArgumentDot?.fifthArgumentDot?.sixthArgumentDot
 
 
-val elem2 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot
+val elem2 = firstArgumentDot?.secondArgumentDot()?.thirdArgumentDot
     ?.fourthArgumentDot?.fifthArgumentDot?.sixthArgumentDot
 
 
-val elem3 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot?.fourthArgumentDot
+val elem3 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot()?.fourthArgumentDot
     ?.fifthArgumentDot?.sixthArgumentDot
 
 
 val elem4 = firstArgumentDot?.secondArgumentDot?.thirdArgumentDot + firstArgumentDot?.secondArgumentDot?.thirdArgumentDot?.fourthArgumentDot
 
 
-val elem5 = firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot!!.fourthArgumentDot!!.fifthArgumentDot!!.sixthArgumentDot
+val elem5 = firstArgumentDot()!!.secondArgumentDot()!!.thirdArgumentDot!!.fourthArgumentDot!!.fifthArgumentDot!!.sixthArgumentDot()
 
 
-val elem6 = firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot!!
-    .fourthArgumentDot!!.fifthArgumentDot!!.sixthArgumentDot
+val elem6 = firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot()!!
+    .fourthArgumentDot!!.fifthArgumentDot()!!.sixthArgumentDot
 
 
-val elem7 = firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot!!.fourthArgumentDot!!
+val elem7 = firstArgumentDot!!.secondArgumentDot()!!.thirdArgumentDot!!.fourthArgumentDot()!!
     .fifthArgumentDot!!.sixthArgumentDot
 
 
-val elem8 = firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot + firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot!!.fourthArgumentDot
+val elem8 = firstArgumentDot()!!.secondArgumentDot!!.thirdArgumentDot + firstArgumentDot!!.secondArgumentDot!!.thirdArgumentDot!!.fourthArgumentDot
 
 
-val elem9 = firstArgumentDot.secondArgumentDot.thirdArgumentDot.fourthArgumentDot.fifthArgumentDot.sixthArgumentDot
+val elem9 = firstArgumentDot().secondArgumentDot.thirdArgumentDot().fourthArgumentDot.fifthArgumentDot.sixthArgumentDot
 
 
-val elem10 = firstArgumentDot.secondArgumentDot.thirdArgumentDot
-    .fourthArgumentDot.fifthArgumentDot.sixthArgumentDot
+val elem10 = firstArgumentDot.secondArgumentDot().thirdArgumentDot
+    .fourthArgumentDot.fifthArgumentDot().sixthArgumentDot
 
 
-val elem11 = firstArgumentDot.secondArgumentDot.thirdArgumentDot.fourthArgumentDot
+val elem11 = firstArgumentDot.secondArgumentDot.thirdArgumentDot().fourthArgumentDot
     .fifthArgumentDot.sixthArgumentDot
 
 
-val elem12 = firstArgumentDot.secondArgumentDot.thirdArgumentDot + firstArgumentDot.secondArgumentDot.thirdArgumentDot.fourthArgumentDot
+val elem12 = firstArgumentDot.secondArgumentDot.thirdArgumentDot + firstArgumentDot.secondArgumentDot().thirdArgumentDot.fourthArgumentDot
 
 
-val elem13 = firstArgumentDot!!.secondArgumentDot?.thirdArgumentDot.fourthArgumentDot!!.fifthArgumentDot?.sixthArgumentDot
+val elem13 = firstArgumentDot!!.secondArgumentDot?.thirdArgumentDot().fourthArgumentDot!!.fifthArgumentDot()?.sixthArgumentDot
 
 
-val elem14 = firstArgumentDot.secondArgumentDot?.thirdArgumentDot!!.fourthArgumentDot?.fifthArgumentDot.sixthArgumentDot
+val elem14 = firstArgumentDot.secondArgumentDot?.thirdArgumentDot()!!.fourthArgumentDot?.fifthArgumentDot.sixthArgumentDot
 
 
-val elem15 = firstArgumentDot?.secondArgumentDot!!.thirdArgumentDot.fourthArgumentDot.fifthArgumentDot!!.sixthArgumentDot
\ No newline at end of file
+val elem15 = firstArgumentDot?.secondArgumentDot!!.thirdArgumentDot.fourthArgumentDot().fifthArgumentDot!!.sixthArgumentDot
+
+
+val elem16 = firstArgumentDot.secondArgumentDot.thirdArgumentDot.fourthArgumentDot.fifthArgumentDot.sixthArgumentDot
+
+
+val elem17 = firstArgumentDot!!.secondArgumentDot.thirdArgumentDot!!.fourthArgumentDot.fifthArgumentDot!!.sixthArgumentDot
+
+
+val elem18 = firstArgumentDot.secondArgumentDot?.thirdArgumentDot.fourthArgumentDot?.fifthArgumentDot.sixthArgumentDot
+
+
+private val holder: java.util.concurrent.atomic.AtomicReference<T> = java.util.concurrent.atomic.AtomicReference(valueToStore)
+
+
+private val holder: kotlin.native.concurrent.AtomicReference<T> = kotlin.native.concurrent.AtomicReference(valueToStore)