Repository: analysis-dev/diktat (kotlin)

Issue:
Error with regex in COMMENTED_OUT_CODE rule
The exception occurs on the project iosched

[ERROR] 2021-06-10 16:24:08 As a workaround you can disable these inspections in yml config: [COMMENTED_OUT_CODE]

```
package com.google.samples.apps.iosched.tests.ui

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.samples.apps.iosched.R
import com.google.samples.apps.iosched.tests.FixedTimeRule
import com.google.samples.apps.iosched.tests.SetPreferencesRule
import com.google.samples.apps.iosched.ui.sessioncommon.SessionViewHolder
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

/**
 * Basic Espresso tests for the schedule screen.
 */
@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
class ScheduleTest {

    @get:Rule(order = 0)
    var hiltRule = HiltAndroidRule(this)

    // Sets the time to before the conference
    @get:Rule(order = 1)
    var timeProviderRule = FixedTimeRule()

    // Sets the preferences so no welcome screens are shown
    @get:Rule(order = 1)
    var preferencesRule = SetPreferencesRule()

    @get:Rule(order = 2)
    var activityRule = MainActivityTestRule(R.id.navigation_schedule)

    private val resources = ApplicationProvider.getApplicationContext<Context>().resources

    @Test
    fun showFirstDay_sessionOnFirstDayShown() {
        onView(withText(FAKE_SESSION_ON_DAY1))
            .check(matches(isDisplayed()))
    }

    @Test
    @Ignore(
        "Session Details are shown in another pane owned by a parent fragment. This test runs in " +
            "a test Activity that does not include the other pane, so it will never pass."
    )
    fun clickOnFirstItem_detailsShown() {
        onView(withId(R.id.recyclerview_schedule))
            .perform(RecyclerViewActions.actionOnItemAtPosition<SessionViewHolder>(0, click()))

        onView(withId(R.id.session_detail_title)).check(matches(isDisplayed()))
    }

/* TODO(jdkoren) move to new schedule screen
    @Test
    fun clickFilters_showFilters() {
        checkAnimationsDisabled()

        onView(withId(R.id.filter_fab)).perform(click())

        val uncheckedFilterContentDesc =
            getDisabledFilterContDesc(FakeConferenceDataSource.FAKE_SESSION_TAG_NAME)
        val checkedFilterContentDesc =
            getActiveFilterContDesc(FakeConferenceDataSource.FAKE_SESSION_TAG_NAME)

        // Scroll to the filter
        onView(allOf(withId(R.id.recyclerview_filter), withParent(withId(R.id.filter_sheet))))
            .perform(
                RecyclerViewActions.scrollTo<ScheduleFilterAdapter.FilterViewHolder>(
                    withContentDescription(uncheckedFilterContentDesc)
                )
            )

        onView(withContentDescription(uncheckedFilterContentDesc))
            .check(matches(isDisplayed()))
            .perform(click())

        // Check that the filter is enabled
        onView(
            allOf(
                withId(R.id.filter_label),
                withContentDescription(checkedFilterContentDesc),
                not(withParent(withId(R.id.filter_description_tags)))
            )
        )
            .check(matches(isDisplayed()))
            .perform(click())
    }

    @Test
    fun filters_applyAFilter() {
        checkAnimationsDisabled()
        val sessionName = FakeConferenceDataSource.FAKE_SESSION_NAME

        // Apply the filter that will show the session
        applyFilter(FakeConferenceDataSource.FAKE_SESSION_TAG_NAME)

        // Check that it's displayed now
        onView(withText(sessionName))
            .check(matches(isDisplayed()))
    }

    @Test
    fun filters_clearFilters() {
        // Apply the filter that will show the session
        val filter = FakeConferenceDataSource.FAKE_SESSION_TAG_NAME
        applyFilter(filter)

        // Clear
        onView(withId(R.id.clear_filters_shortcut)).perform(click())

        onView(
            allOf(
                withId(R.id.filter_label),
                withContentDescription(getActiveFilterContDesc(filter)),
                withParent(withId(R.id.filter_description_tags))
            )
        ).check(matches(isCompletelyDisplayed()))
    }

    private fun applyFilter(filter: String) {
        // Open the filters sheet
        onView(withId(R.id.filter_fab)).perform(click())

        // Get the content description of the view we need to click on
        val uncheckedFilterContentDesc =
            resources.getString(R.string.a11y_filter_not_applied, filter)

        onView(allOf(withId(R.id.recyclerview_filter), withParent(withId(R.id.filter_sheet))))
            .check(matches(isDisplayed()))

        // Scroll to the filter
        onView(allOf(withId(R.id.recyclerview_filter), withParent(withId(R.id.filter_sheet))))
            .perform(
                RecyclerViewActions.scrollTo<ScheduleFilterAdapter.FilterViewHolder>(
                    withContentDescription(uncheckedFilterContentDesc)
                )
            )

        // Click on the filter
        onView(withContentDescription(uncheckedFilterContentDesc))
            .check(matches(isDisplayed()))
            .perform(click())

        pressBack()
    }

    private fun getDisabledFilterContDesc(filter: String) =
        resources.getString(R.string.a11y_filter_not_applied, filter)

    private fun getActiveFilterContDesc(filter: String) =
        resources.getString(R.string.a11y_filter_applied, filter)

    private fun checkAnimationsDisabled() {
        val scale = Settings.Global.getFloat(
            ApplicationProvider.getApplicationContext<Context>().contentResolver,
            Settings.Global.ANIMATOR_DURATION_SCALE,
            1f
        )

        if (scale > 0) {
            throw Exception(
                "Device must have animations disabled. " +
                    "Developer options -> Animator duration scale"
            )
        }
    }
*/
    companion object {
        private const val FAKE_SESSION_ON_DAY1 = "Fake session on day 1"
    }
}
```

Pull request description:
### What's done:
* fixed bug in COMMENTED_OUT_CODE
* replace requirePartOfCode regex on isRequirePartOfCode function
Closes #921

Patch:
diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt
index 4555fc9b57..a97fb7f4a2 100644
--- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt
+++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt
@@ -65,13 +65,14 @@ class CommentsRule(configRules: List<RulesConfig>) : DiktatRule(
                     offset to it
                 }
             }
+            .map { (offset, text) -> offset to text.trim() }
             .mapNotNull { (offset, text) ->
                 when {
                     text.contains(importKeyword) ->
                         offset to ktPsiFactory.createImportDirective(ImportPath.fromString(text.substringAfter("$importKeyword "))).node
                     text.contains(packageKeyword) ->
                         offset to ktPsiFactory.createPackageDirective(FqName(text.substringAfter("$packageKeyword "))).node
-                    else -> if (text.contains(requirePartOfCode)) {
+                    else -> if (isContainingRequiredPartOfCode(text)) {
                         offset to ktPsiFactory.createBlockCodeFragment(text, null).node
                     } else {
                         null
@@ -85,7 +86,7 @@ class CommentsRule(configRules: List<RulesConfig>) : DiktatRule(
             }
             .forEach { (offset, parsedNode) ->
                 COMMENTED_OUT_CODE.warn(configRules, emitWarn, isFixMode, parsedNode.text.substringBefore("\n").trim(), offset,
-                    errorNodesWithText.find { it.second == parsedNode.text }?.first ?: parsedNode)
+                    errorNodesWithText.find { it.second.trim().contains(parsedNode.text, false) || parsedNode.text.contains(it.second.trim(), false) }?.first!!)
             }
     }
 
@@ -135,6 +136,9 @@ class CommentsRule(configRules: List<RulesConfig>) : DiktatRule(
         return codeFileStartCases.any { textWithoutCommentStartToken.contains(it) }
     }
 
+    private fun isContainingRequiredPartOfCode(text: String): Boolean =
+            text.contains("val ", true) || text.contains("var ", true) || text.contains("=", true) || (text.contains("{", true) && text.substringAfter("{").contains("}", true))
+
     @Suppress("MaxLineLength")
     companion object {
         private val importKeyword = KtTokens.IMPORT_KEYWORD.value
@@ -145,8 +149,8 @@ class CommentsRule(configRules: List<RulesConfig>) : DiktatRule(
         private val importOrPackageRegex = """^(import|package)?\s+([a-zA-Z.])+;*$""".toRegex()
         private val functionRegex = """^(public|private|protected)*\s*(override|abstract|actual|expect)*\s?fun\s+\w+(\(.*\))?(\s*:\s*\w+)?\s*[{=]${'$'}""".toRegex()
         private val rightBraceRegex = """^\s*}$""".toRegex()
-        private val requirePartOfCode = """val |var |=|(\{((.|\n)*)})""".toRegex()
-        private val codeFileStartCases = listOf(classRegex, importOrPackageRegex, functionRegex, rightBraceRegex)
+        private val valOrVarRegex = """val |var """.toRegex()
+        private val codeFileStartCases = listOf(classRegex, importOrPackageRegex, functionRegex, rightBraceRegex, valOrVarRegex)
         private val eolCommentStart = """// \S""".toRegex()
     }
 }


Test patch:
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/comments/CommentedCodeTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/comments/CommentedCodeTest.kt
index b35327d1bd..2be054be4c 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/comments/CommentedCodeTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/comments/CommentedCodeTest.kt
@@ -150,6 +150,74 @@ class CommentedCodeTest : LintTestBase(::CommentsRule) {
         )
     }
 
+    @Test
+    @Tag(WarningNames.COMMENTED_OUT_CODE)
+    @Suppress("TOO_LONG_FUNCTION", "LongMethod")
+    fun `very long commented code`() {
+        lintMethod(
+            """
+                |class ScheduleTest {
+                |/* 
+                |   fun clickFilters_showFilters() {
+                |       checkAnimationsDisabled()
+                |
+                |       onView(withId(R.id.filter_fab)).perform(click())
+                |
+                |       val uncheckedFilterContentDesc =
+                |           getDisabledFilterContDesc(FakeConferenceDataSource.FAKE_SESSION_TAG_NAME)
+                |       val checkedFilterContentDesc =
+                |           getActiveFilterContDesc(FakeConferenceDataSource.FAKE_SESSION_TAG_NAME)
+                |
+                |       // Scroll to the filter
+                |       onView(allOf(withId(R.id.recyclerview_filter), withParent(withId(R.id.filter_sheet))))
+                |           .perform(
+                |               RecyclerViewActions.scrollTo<ScheduleFilterAdapter.FilterViewHolder>(
+                |                   withContentDescription(uncheckedFilterContentDesc)
+                |               )
+                |           )
+                |
+                |       onView(withContentDescription(uncheckedFilterContentDesc))
+                |           .check(matches(isDisplayed()))
+                |           .perform(click())
+                |
+                |       // Check that the filter is enabled
+                |       onView(
+                |           allOf(
+                |               withId(R.id.filter_label),
+                |               withContentDescription(checkedFilterContentDesc),
+                |               not(withParent(withId(R.id.filter_description_tags)))
+                |           )
+                |       )
+                |           .check(matches(isDisplayed()))
+                |           .perform(click())
+                |   }
+                |
+                |   private fun applyFilter(filter: String) {
+                |       // Open the filters sheet
+                |       onView(withId(R.id.filter_fab)).perform(click())
+                |   
+                |       // Get the content description of the view we need to click on
+                |       val uncheckedFilterContentDesc =
+                |           resources.getString(R.string.a11y_filter_not_applied, filter)
+                |   
+                |      onView(allOf(withId(R.id.recyclerview_filter), withParent(withId(R.id.filter_sheet))))
+                |          .check(matches(isDisplayed()))
+                |   
+                |       // Scroll to the filter
+                |       onView(allOf(withId(R.id.recyclerview_filter), withParent(withId(R.id.filter_sheet))))
+                |         .perform(
+                |             RecyclerViewActions.scrollTo<ScheduleFilterAdapter.FilterViewHolder>(
+                |                 withContentDescription(uncheckedFilterContentDesc)
+                |             )
+                |         )
+                |   }
+                |   */
+                |}
+            """.trimMargin(),
+            LintError(2, 1, ruleId, "${COMMENTED_OUT_CODE.warnText()} fun clickFilters_showFilters() {", false)
+        )
+    }
+
     @Test
     @Tag(WarningNames.COMMENTED_OUT_CODE)
     fun `Should warn if detects commented out code example with IDEA style indents`() {
@@ -191,6 +259,48 @@ class CommentedCodeTest : LintTestBase(::CommentsRule) {
             LintError(1, 1, ruleId, "${COMMENTED_OUT_CODE.warnText()} public data class Test(val some: Int): Exception()", false))
     }
 
+    @Test
+    @Tag(WarningNames.COMMENTED_OUT_CODE)
+    fun `should trigger on one-line comment with var or val`() {
+        lintMethod(
+            """
+            |// var foo: Int = 1
+            """.trimMargin(),
+            LintError(1, 1, ruleId, "${COMMENTED_OUT_CODE.warnText()} var foo: Int = 1", false))
+    }
+
+    @Test
+    @Tag(WarningNames.COMMENTED_OUT_CODE)
+    fun `should trigger on one-line multi comment`() {
+        lintMethod(
+            """
+            | // fun foo() {
+            | //     varfoo adda foofoo
+            | // }
+            """.trimMargin(),
+            LintError(1, 2, ruleId, "${COMMENTED_OUT_CODE.warnText()} fun foo() {", false))
+    }
+
+    @Test
+    @Tag(WarningNames.COMMENTED_OUT_CODE)
+    fun `should trigger on one-line comment`() {
+        lintMethod(
+            """
+            | // class A { val a = 2 } 
+            """.trimMargin(),
+            LintError(1, 2, ruleId, "${COMMENTED_OUT_CODE.warnText()} class A { val a = 2 }", false))
+    }
+
+    @Test
+    @Tag(WarningNames.COMMENTED_OUT_CODE)
+    fun `should trigger on one-line block comment`() {
+        lintMethod(
+            """
+            | /* class A { val a = 2 } */
+            """.trimMargin(),
+            LintError(1, 2, ruleId, "${COMMENTED_OUT_CODE.warnText()} class A { val a = 2 }", false))
+    }
+
     @Test
     @Tag(WarningNames.COMMENTED_OUT_CODE)
     fun `should trigger on class with one space after comment start token and 2 modifiers #2`() {
@@ -318,8 +428,8 @@ class CommentedCodeTest : LintTestBase(::CommentsRule) {
             
             */
             """.trimMargin(),
-            LintError(7, 13, ruleId, "${COMMENTED_OUT_CODE.warnText()} ", false),
-            LintError(14, 13, ruleId, "${COMMENTED_OUT_CODE.warnText()} ", false)
+            LintError(7, 13, ruleId, "${COMMENTED_OUT_CODE.warnText()} x = 2 + 4 + 1", false),
+            LintError(14, 13, ruleId, "${COMMENTED_OUT_CODE.warnText()} class A {", false)
         )
     }